bangonit 0.3.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +24 -33
  2. package/app/desktopapp/dist/main/index.js +7 -3
  3. package/app/desktopapp/dist/main/ipc.js +96 -20
  4. package/app/desktopapp/dist/main/preload.js +4 -3
  5. package/app/desktopapp/dist/main/tabs.js +86 -44
  6. package/app/replay/dist/replay.css +1 -1
  7. package/app/replay/dist/replay.js +24 -24
  8. package/app/webapp/.next/standalone/app/webapp/.next/BUILD_ID +1 -1
  9. package/app/webapp/.next/standalone/app/webapp/.next/app-build-manifest.json +2 -2
  10. package/app/webapp/.next/standalone/app/webapp/.next/app-path-routes-manifest.json +1 -1
  11. package/app/webapp/.next/standalone/app/webapp/.next/build-manifest.json +2 -2
  12. package/app/webapp/.next/standalone/app/webapp/.next/prerender-manifest.json +1 -1
  13. package/app/webapp/.next/standalone/app/webapp/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  14. package/app/webapp/.next/standalone/app/webapp/.next/server/app/_not-found.html +1 -1
  15. package/app/webapp/.next/standalone/app/webapp/.next/server/app/_not-found.rsc +1 -1
  16. package/app/webapp/.next/standalone/app/webapp/.next/server/app/app/page.js +3 -3
  17. package/app/webapp/.next/standalone/app/webapp/.next/server/app/app/page_client-reference-manifest.js +1 -1
  18. package/app/webapp/.next/standalone/app/webapp/.next/server/app/app.html +1 -1
  19. package/app/webapp/.next/standalone/app/webapp/.next/server/app/app.rsc +2 -2
  20. package/app/webapp/.next/standalone/app/webapp/.next/server/app/index.html +1 -1
  21. package/app/webapp/.next/standalone/app/webapp/.next/server/app/index.rsc +1 -1
  22. package/app/webapp/.next/standalone/app/webapp/.next/server/app/page_client-reference-manifest.js +1 -1
  23. package/app/webapp/.next/standalone/app/webapp/.next/server/app-paths-manifest.json +2 -2
  24. package/app/webapp/.next/standalone/app/webapp/.next/server/chunks/708.js +6 -2
  25. package/app/webapp/.next/standalone/app/webapp/.next/server/pages/404.html +1 -1
  26. package/app/webapp/.next/standalone/app/webapp/.next/server/pages/500.html +1 -1
  27. package/app/webapp/.next/standalone/app/webapp/.next/server/pages-manifest.json +1 -1
  28. package/app/webapp/.next/standalone/app/webapp/.next/server/server-reference-manifest.json +1 -1
  29. package/app/webapp/.next/standalone/app/webapp/.next/static/chunks/app/app/page-d6a322343ab207d9.js +1 -0
  30. package/app/webapp/.next/{static/css/38219627f55424f2.css → standalone/app/webapp/.next/static/css/85c115515088d5dd.css} +1 -1
  31. package/app/webapp/.next/standalone/package.json +5 -2
  32. package/app/webapp/.next/static/chunks/app/app/page-d6a322343ab207d9.js +1 -0
  33. package/app/webapp/.next/{standalone/app/webapp/.next/static/css/38219627f55424f2.css → static/css/85c115515088d5dd.css} +1 -1
  34. package/app/webapp/src/shared/api/chat.ts +8 -2
  35. package/app/webapp/src/shared/components/AppShell.tsx +6 -5
  36. package/app/webapp/src/shared/components/SessionView.tsx +5 -4
  37. package/app/webapp/src/shared/lib/browser/index.ts +17 -27
  38. package/app/webapp/src/shared/lib/browser/recorder.ts +13 -4
  39. package/app/webapp/src/shared/lib/browser/snapshot.ts +19 -5
  40. package/app/webapp/src/shared/lib/browser/types.ts +21 -6
  41. package/app/webapp/src/shared/types/global.d.ts +6 -4
  42. package/bin/src/cli/bangonit.js +22 -12
  43. package/package.json +5 -2
  44. package/scripts/regen-replays.sh +101 -0
  45. package/app/webapp/.next/standalone/app/webapp/.next/static/chunks/app/app/page-0e096497dcb81dae.js +0 -1
  46. package/app/webapp/.next/static/chunks/app/app/page-0e096497dcb81dae.js +0 -1
  47. /package/app/webapp/.next/standalone/app/webapp/.next/static/{CIPi_XcKXl17yJkvAnMYF → GYX27NS_2uYjr9ksgGxIo}/_buildManifest.js +0 -0
  48. /package/app/webapp/.next/standalone/app/webapp/.next/static/{CIPi_XcKXl17yJkvAnMYF → GYX27NS_2uYjr9ksgGxIo}/_ssgManifest.js +0 -0
  49. /package/app/webapp/.next/static/{CIPi_XcKXl17yJkvAnMYF → GYX27NS_2uYjr9ksgGxIo}/_buildManifest.js +0 -0
  50. /package/app/webapp/.next/static/{CIPi_XcKXl17yJkvAnMYF → GYX27NS_2uYjr9ksgGxIo}/_ssgManifest.js +0 -0
@@ -2,4 +2,4 @@
2
2
 
3
3
  /*
4
4
  ! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com
5
- */*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);text-decoration:underline;font-weight:500}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:italic;color:var(--tw-prose-quotes);border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"\201C""\201D""\2018""\2019";margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px var(--tw-prose-kbd-shadows),0 3px 0 var(--tw-prose-kbd-shadows);font-size:.875em;border-radius:.3125rem;padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding-top:.8571429em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-kbd:#111827;--tw-prose-kbd-shadows:rgba(17,24,39,.1);--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:hsla(0,0%,100%,.1);--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.5714286em;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-sm{font-size:.875rem;line-height:1.7142857}.prose-sm :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em}.prose-sm :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2857143em;line-height:1.5555556;margin-top:.8888889em;margin-bottom:.8888889em}.prose-sm :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em;margin-bottom:1.3333333em;padding-inline-start:1.1111111em}.prose-sm :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:2.1428571em;margin-top:0;margin-bottom:.8em;line-height:1.2}.prose-sm :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.4285714em;margin-top:1.6em;margin-bottom:.8em;line-height:1.4}.prose-sm :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2857143em;margin-top:1.5555556em;margin-bottom:.4444444em;line-height:1.5555556}.prose-sm :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.4285714em;margin-bottom:.5714286em;line-height:1.4285714}.prose-sm :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-sm :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;border-radius:.3125rem;padding-top:.1428571em;padding-inline-end:.3571429em;padding-bottom:.1428571em;padding-inline-start:.3571429em}.prose-sm :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em}.prose-sm :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em}.prose-sm :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em}.prose-sm :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.6666667;margin-top:1.6666667em;margin-bottom:1.6666667em;border-radius:.25rem;padding-top:.6666667em;padding-inline-end:1em;padding-bottom:.6666667em;padding-inline-start:1em}.prose-sm :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em;padding-inline-start:1.5714286em}.prose-sm :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em;padding-inline-start:1.5714286em}.prose-sm :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.2857143em;margin-bottom:.2857143em}.prose-sm :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4285714em}.prose-sm :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4285714em}.prose-sm :where(.prose-sm>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5714286em;margin-bottom:.5714286em}.prose-sm :where(.prose-sm>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(.prose-sm>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5714286em;margin-bottom:.5714286em}.prose-sm :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em}.prose-sm :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.2857143em;padding-inline-start:1.5714286em}.prose-sm :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2.8571429em;margin-bottom:2.8571429em}.prose-sm :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.5}.prose-sm :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:1em;padding-bottom:.6666667em;padding-inline-start:1em}.prose-sm :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.6666667em;padding-inline-end:1em;padding-bottom:.6666667em;padding-inline-start:1em}.prose-sm :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-sm :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.3333333;margin-top:.6666667em}.prose-sm :where(.prose-sm>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(.prose-sm>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-invert{--tw-prose-body:var(--tw-prose-invert-body);--tw-prose-headings:var(--tw-prose-invert-headings);--tw-prose-lead:var(--tw-prose-invert-lead);--tw-prose-links:var(--tw-prose-invert-links);--tw-prose-bold:var(--tw-prose-invert-bold);--tw-prose-counters:var(--tw-prose-invert-counters);--tw-prose-bullets:var(--tw-prose-invert-bullets);--tw-prose-hr:var(--tw-prose-invert-hr);--tw-prose-quotes:var(--tw-prose-invert-quotes);--tw-prose-quote-borders:var(--tw-prose-invert-quote-borders);--tw-prose-captions:var(--tw-prose-invert-captions);--tw-prose-kbd:var(--tw-prose-invert-kbd);--tw-prose-kbd-shadows:var(--tw-prose-invert-kbd-shadows);--tw-prose-code:var(--tw-prose-invert-code);--tw-prose-pre-code:var(--tw-prose-invert-pre-code);--tw-prose-pre-bg:var(--tw-prose-invert-pre-bg);--tw-prose-th-borders:var(--tw-prose-invert-th-borders);--tw-prose-td-borders:var(--tw-prose-invert-td-borders)}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-3{bottom:.75rem}.right-3{right:.75rem}.z-0{z-index:0}.z-10{z-index:10}.z-20{z-index:20}.z-\[1\]{z-index:1}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.ml-auto{margin-left:auto}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.table{display:table}.hidden{display:none}.h-2{height:.5rem}.h-full{height:100%}.h-screen{height:100vh}.max-h-60{max-height:15rem}.w-2{width:.5rem}.w-48{width:12rem}.w-\[420px\]{width:420px}.w-full{width:100%}.min-w-0{min-width:0}.max-w-\[200px\]{max-width:200px}.max-w-none{max-width:none}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.rotate-90{--tw-rotate:90deg}.rotate-90,.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.cursor-not-allowed{cursor:not-allowed}.select-all{-webkit-user-select:all;-moz-user-select:all;user-select:all}.resize-none{resize:none}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-blue-400\/60{border-color:rgba(96,165,250,.6)}.border-blue-600{--tw-border-opacity:1;border-color:rgb(37 99 235/var(--tw-border-opacity,1))}.border-green-900\/50{border-color:rgba(20,83,45,.5)}.border-red-900\/50{border-color:rgba(127,29,29,.5)}.border-zinc-700{--tw-border-opacity:1;border-color:rgb(63 63 70/var(--tw-border-opacity,1))}.border-zinc-800{--tw-border-opacity:1;border-color:rgb(39 39 42/var(--tw-border-opacity,1))}.bg-amber-500{--tw-bg-opacity:1;background-color:rgb(245 158 11/var(--tw-bg-opacity,1))}.bg-blue-400\/50{background-color:rgba(96,165,250,.5)}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.bg-blue-950\/30{background-color:rgba(23,37,84,.3)}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(34 197 94/var(--tw-bg-opacity,1))}.bg-green-950\/30{background-color:rgba(5,46,22,.3)}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity,1))}.bg-red-950\/30{background-color:rgba(69,10,10,.3)}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-zinc-600{--tw-bg-opacity:1;background-color:rgb(82 82 91/var(--tw-bg-opacity,1))}.bg-zinc-800{--tw-bg-opacity:1;background-color:rgb(39 39 42/var(--tw-bg-opacity,1))}.bg-zinc-900{--tw-bg-opacity:1;background-color:rgb(24 24 27/var(--tw-bg-opacity,1))}.bg-zinc-900\/50{background-color:rgba(24,24,27,.5)}.bg-zinc-900\/80{background-color:rgba(24,24,27,.8)}.bg-zinc-950{--tw-bg-opacity:1;background-color:rgb(9 9 11/var(--tw-bg-opacity,1))}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.text-left{text-align:left}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.uppercase{text-transform:uppercase}.leading-none{line-height:1}.tracking-wider{letter-spacing:.05em}.text-blue-400{--tw-text-opacity:1;color:rgb(96 165 250/var(--tw-text-opacity,1))}.text-green-400{--tw-text-opacity:1;color:rgb(74 222 128/var(--tw-text-opacity,1))}.text-green-500{--tw-text-opacity:1;color:rgb(34 197 94/var(--tw-text-opacity,1))}.text-red-400{--tw-text-opacity:1;color:rgb(248 113 113/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-zinc-200{--tw-text-opacity:1;color:rgb(228 228 231/var(--tw-text-opacity,1))}.text-zinc-300{--tw-text-opacity:1;color:rgb(212 212 216/var(--tw-text-opacity,1))}.text-zinc-400{--tw-text-opacity:1;color:rgb(161 161 170/var(--tw-text-opacity,1))}.text-zinc-500{--tw-text-opacity:1;color:rgb(113 113 122/var(--tw-text-opacity,1))}.text-zinc-600{--tw-text-opacity:1;color:rgb(82 82 91/var(--tw-text-opacity,1))}.line-through{text-decoration-line:line-through}.placeholder-zinc-500::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(113 113 122/var(--tw-placeholder-opacity,1))}.placeholder-zinc-500::placeholder{--tw-placeholder-opacity:1;color:rgb(113 113 122/var(--tw-placeholder-opacity,1))}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.drop-shadow{--tw-drop-shadow:drop-shadow(0 1px 2px rgba(0,0,0,.1)) drop-shadow(0 1px 1px rgba(0,0,0,.06))}.drop-shadow,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}body,html{font-family:DM Sans,-apple-system,BlinkMacSystemFont,sans-serif;background:#050505;color:#fafafa;height:100%}.font-display{font-family:Outfit,sans-serif}.hover\:border-zinc-500:hover{--tw-border-opacity:1;border-color:rgb(113 113 122/var(--tw-border-opacity,1))}.hover\:border-zinc-700:hover{--tw-border-opacity:1;border-color:rgb(63 63 70/var(--tw-border-opacity,1))}.hover\:bg-blue-500:hover{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.hover\:bg-zinc-800:hover{--tw-bg-opacity:1;background-color:rgb(39 39 42/var(--tw-bg-opacity,1))}.hover\:text-zinc-200:hover{--tw-text-opacity:1;color:rgb(228 228 231/var(--tw-text-opacity,1))}.hover\:text-zinc-300:hover{--tw-text-opacity:1;color:rgb(212 212 216/var(--tw-text-opacity,1))}.focus\:border-zinc-500:focus{--tw-border-opacity:1;border-color:rgb(113 113 122/var(--tw-border-opacity,1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.disabled\:bg-zinc-700:disabled{--tw-bg-opacity:1;background-color:rgb(63 63 70/var(--tw-bg-opacity,1))}.disabled\:text-zinc-500:disabled{--tw-text-opacity:1;color:rgb(113 113 122/var(--tw-text-opacity,1))}
5
+ */*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);text-decoration:underline;font-weight:500}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:italic;color:var(--tw-prose-quotes);border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"\201C""\201D""\2018""\2019";margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px var(--tw-prose-kbd-shadows),0 3px 0 var(--tw-prose-kbd-shadows);font-size:.875em;border-radius:.3125rem;padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding-top:.8571429em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-kbd:#111827;--tw-prose-kbd-shadows:rgba(17,24,39,.1);--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:hsla(0,0%,100%,.1);--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.5714286em;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-sm{font-size:.875rem;line-height:1.7142857}.prose-sm :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em}.prose-sm :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2857143em;line-height:1.5555556;margin-top:.8888889em;margin-bottom:.8888889em}.prose-sm :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em;margin-bottom:1.3333333em;padding-inline-start:1.1111111em}.prose-sm :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:2.1428571em;margin-top:0;margin-bottom:.8em;line-height:1.2}.prose-sm :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.4285714em;margin-top:1.6em;margin-bottom:.8em;line-height:1.4}.prose-sm :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2857143em;margin-top:1.5555556em;margin-bottom:.4444444em;line-height:1.5555556}.prose-sm :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.4285714em;margin-bottom:.5714286em;line-height:1.4285714}.prose-sm :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-sm :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;border-radius:.3125rem;padding-top:.1428571em;padding-inline-end:.3571429em;padding-bottom:.1428571em;padding-inline-start:.3571429em}.prose-sm :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em}.prose-sm :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em}.prose-sm :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em}.prose-sm :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.6666667;margin-top:1.6666667em;margin-bottom:1.6666667em;border-radius:.25rem;padding-top:.6666667em;padding-inline-end:1em;padding-bottom:.6666667em;padding-inline-start:1em}.prose-sm :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em;padding-inline-start:1.5714286em}.prose-sm :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em;padding-inline-start:1.5714286em}.prose-sm :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.2857143em;margin-bottom:.2857143em}.prose-sm :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4285714em}.prose-sm :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4285714em}.prose-sm :where(.prose-sm>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5714286em;margin-bottom:.5714286em}.prose-sm :where(.prose-sm>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(.prose-sm>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5714286em;margin-bottom:.5714286em}.prose-sm :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em}.prose-sm :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.2857143em;padding-inline-start:1.5714286em}.prose-sm :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2.8571429em;margin-bottom:2.8571429em}.prose-sm :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.5}.prose-sm :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:1em;padding-bottom:.6666667em;padding-inline-start:1em}.prose-sm :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.6666667em;padding-inline-end:1em;padding-bottom:.6666667em;padding-inline-start:1em}.prose-sm :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-sm :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.3333333;margin-top:.6666667em}.prose-sm :where(.prose-sm>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(.prose-sm>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-invert{--tw-prose-body:var(--tw-prose-invert-body);--tw-prose-headings:var(--tw-prose-invert-headings);--tw-prose-lead:var(--tw-prose-invert-lead);--tw-prose-links:var(--tw-prose-invert-links);--tw-prose-bold:var(--tw-prose-invert-bold);--tw-prose-counters:var(--tw-prose-invert-counters);--tw-prose-bullets:var(--tw-prose-invert-bullets);--tw-prose-hr:var(--tw-prose-invert-hr);--tw-prose-quotes:var(--tw-prose-invert-quotes);--tw-prose-quote-borders:var(--tw-prose-invert-quote-borders);--tw-prose-captions:var(--tw-prose-invert-captions);--tw-prose-kbd:var(--tw-prose-invert-kbd);--tw-prose-kbd-shadows:var(--tw-prose-invert-kbd-shadows);--tw-prose-code:var(--tw-prose-invert-code);--tw-prose-pre-code:var(--tw-prose-invert-pre-code);--tw-prose-pre-bg:var(--tw-prose-invert-pre-bg);--tw-prose-th-borders:var(--tw-prose-invert-th-borders);--tw-prose-td-borders:var(--tw-prose-invert-td-borders)}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-3{bottom:.75rem}.right-3{right:.75rem}.z-0{z-index:0}.z-10{z-index:10}.z-20{z-index:20}.z-\[1\]{z-index:1}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.ml-auto{margin-left:auto}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.table{display:table}.hidden{display:none}.h-2{height:.5rem}.h-full{height:100%}.h-screen{height:100vh}.max-h-48{max-height:12rem}.max-h-60{max-height:15rem}.w-2{width:.5rem}.w-48{width:12rem}.w-\[420px\]{width:420px}.w-full{width:100%}.min-w-0{min-width:0}.max-w-\[200px\]{max-width:200px}.max-w-none{max-width:none}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.rotate-90{--tw-rotate:90deg}.rotate-90,.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.cursor-not-allowed{cursor:not-allowed}.select-all{-webkit-user-select:all;-moz-user-select:all;user-select:all}.resize-none{resize:none}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-blue-400\/60{border-color:rgba(96,165,250,.6)}.border-blue-600{--tw-border-opacity:1;border-color:rgb(37 99 235/var(--tw-border-opacity,1))}.border-green-900\/50{border-color:rgba(20,83,45,.5)}.border-red-900\/50{border-color:rgba(127,29,29,.5)}.border-zinc-700{--tw-border-opacity:1;border-color:rgb(63 63 70/var(--tw-border-opacity,1))}.border-zinc-800{--tw-border-opacity:1;border-color:rgb(39 39 42/var(--tw-border-opacity,1))}.bg-amber-500{--tw-bg-opacity:1;background-color:rgb(245 158 11/var(--tw-bg-opacity,1))}.bg-blue-400\/50{background-color:rgba(96,165,250,.5)}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.bg-blue-950\/30{background-color:rgba(23,37,84,.3)}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(34 197 94/var(--tw-bg-opacity,1))}.bg-green-950\/30{background-color:rgba(5,46,22,.3)}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity,1))}.bg-red-950\/30{background-color:rgba(69,10,10,.3)}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-zinc-600{--tw-bg-opacity:1;background-color:rgb(82 82 91/var(--tw-bg-opacity,1))}.bg-zinc-800{--tw-bg-opacity:1;background-color:rgb(39 39 42/var(--tw-bg-opacity,1))}.bg-zinc-900{--tw-bg-opacity:1;background-color:rgb(24 24 27/var(--tw-bg-opacity,1))}.bg-zinc-900\/50{background-color:rgba(24,24,27,.5)}.bg-zinc-900\/80{background-color:rgba(24,24,27,.8)}.bg-zinc-950{--tw-bg-opacity:1;background-color:rgb(9 9 11/var(--tw-bg-opacity,1))}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.text-left{text-align:left}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.uppercase{text-transform:uppercase}.leading-none{line-height:1}.tracking-wider{letter-spacing:.05em}.text-blue-400{--tw-text-opacity:1;color:rgb(96 165 250/var(--tw-text-opacity,1))}.text-green-400{--tw-text-opacity:1;color:rgb(74 222 128/var(--tw-text-opacity,1))}.text-green-500{--tw-text-opacity:1;color:rgb(34 197 94/var(--tw-text-opacity,1))}.text-red-400{--tw-text-opacity:1;color:rgb(248 113 113/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-zinc-200{--tw-text-opacity:1;color:rgb(228 228 231/var(--tw-text-opacity,1))}.text-zinc-300{--tw-text-opacity:1;color:rgb(212 212 216/var(--tw-text-opacity,1))}.text-zinc-400{--tw-text-opacity:1;color:rgb(161 161 170/var(--tw-text-opacity,1))}.text-zinc-500{--tw-text-opacity:1;color:rgb(113 113 122/var(--tw-text-opacity,1))}.text-zinc-600{--tw-text-opacity:1;color:rgb(82 82 91/var(--tw-text-opacity,1))}.line-through{text-decoration-line:line-through}.placeholder-zinc-500::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(113 113 122/var(--tw-placeholder-opacity,1))}.placeholder-zinc-500::placeholder{--tw-placeholder-opacity:1;color:rgb(113 113 122/var(--tw-placeholder-opacity,1))}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.drop-shadow{--tw-drop-shadow:drop-shadow(0 1px 2px rgba(0,0,0,.1)) drop-shadow(0 1px 1px rgba(0,0,0,.06))}.drop-shadow,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}body,html{font-family:DM Sans,-apple-system,BlinkMacSystemFont,sans-serif;background:#050505;color:#fafafa;height:100%}.font-display{font-family:Outfit,sans-serif}.hover\:border-zinc-500:hover{--tw-border-opacity:1;border-color:rgb(113 113 122/var(--tw-border-opacity,1))}.hover\:border-zinc-700:hover{--tw-border-opacity:1;border-color:rgb(63 63 70/var(--tw-border-opacity,1))}.hover\:bg-blue-500:hover{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.hover\:bg-zinc-800:hover{--tw-bg-opacity:1;background-color:rgb(39 39 42/var(--tw-bg-opacity,1))}.hover\:text-zinc-200:hover{--tw-text-opacity:1;color:rgb(228 228 231/var(--tw-text-opacity,1))}.hover\:text-zinc-300:hover{--tw-text-opacity:1;color:rgb(212 212 216/var(--tw-text-opacity,1))}.focus\:border-zinc-500:focus{--tw-border-opacity:1;border-color:rgb(113 113 122/var(--tw-border-opacity,1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.disabled\:bg-zinc-700:disabled{--tw-bg-opacity:1;background-color:rgb(63 63 70/var(--tw-bg-opacity,1))}.disabled\:text-zinc-500:disabled{--tw-text-opacity:1;color:rgb(113 113 122/var(--tw-text-opacity,1))}
@@ -55,7 +55,8 @@ Actions:
55
55
  IMPORTANT: Mouse actions move a real cursor across the screen. The cursor travels from its current position to the target, which may trigger hover effects (tooltips, dropdowns, highlights) on elements along the path. If a hover side-effect disrupts your intended action (e.g. a menu opens over your click target), take a fresh snapshot and retry. You can also use this to your advantage — use "move" to intentionally hover over elements to reveal tooltips or dropdown menus.
56
56
  type <text> — type text at cursor (keystrokes)
57
57
  press <key> — press a key or combo (Enter, Tab, ${mod}+a, Shift+Enter)
58
- downloads list recent file downloads
58
+ upload --paths=["/path/to/file"] upload files to an open file picker (the snapshot will tell you when a file picker is open)
59
+ upload --cancel=true — cancel/dismiss an open file picker
59
60
  tabs --action=list — list open tabs
60
61
  tabs --action=new --url=<url> — open new tab
61
62
  tabs --action=select --tabId=<id> — switch tab
@@ -94,6 +95,9 @@ Good — use screenshot when you need visual info:
94
95
  Good — drag from one point to another:
95
96
  { actions: [{"action":"mouse","mouseActions":[{"action":"down","x":100,"y":200},{"action":"move","x":300,"y":400},{"action":"up","x":300,"y":400}]}] }
96
97
 
98
+ ## Dialogs and file pickers
99
+ JavaScript dialogs are automatically handled: alert() is suppressed, confirm() returns true, and prompt() returns the default value. File picker dialogs are intercepted — they will not visually appear, but the snapshot will show "[File picker is open]" when one is triggered. Use the "upload" action to provide file paths or cancel the picker.
100
+
97
101
  ## Todo tracking
98
102
  For tasks with 3+ distinct steps, call the todos tool to show progress. Call it with the FULL list each time:
99
103
  1. At the start: create all todos as "pending"
@@ -160,7 +164,7 @@ export function createChatHandler() {
160
164
  properties: {
161
165
  action: {
162
166
  type: "string",
163
- enum: ["navigate", "back", "forward", "mouse", "type", "press", "tabs", "downloads", "wait", "close"],
167
+ enum: ["navigate", "back", "forward", "mouse", "type", "press", "upload", "tabs", "wait", "close"],
164
168
  description: "The browser action to perform",
165
169
  },
166
170
  url: { type: "string", description: "URL for navigate or new tab" },
@@ -182,6 +186,8 @@ export function createChatHandler() {
182
186
  required: ["action"],
183
187
  },
184
188
  },
189
+ paths: { type: "array", items: { type: "string" }, description: "File paths for upload" },
190
+ cancel: { type: "boolean", description: "Cancel file picker" },
185
191
  tabAction: { type: "string", enum: ["list", "new", "close", "select"] },
186
192
  tabId: { type: "number" },
187
193
  timeout: { type: "number" },
@@ -25,12 +25,13 @@ interface TestPlanMessage {
25
25
  retries?: number;
26
26
  extraPrompt?: string;
27
27
  record?: boolean;
28
+ planDir?: string;
28
29
  }
29
30
 
30
31
  export default function AppShell() {
31
32
  const [agents, setAgents] = useState<AgentConfig[]>([]);
32
33
  const [agentStatuses, setAgentStatuses] = useState<Record<string, AgentStatus>>({});
33
- const [agentSessions, setAgentSessions] = useState<Record<string, { initialPrompt: string; initialMessages?: any[]; initialTabs?: { id: number; url: string; title: string }[]; initialActiveTabId?: number; initialTodos?: { content: string; status: "pending" | "in_progress" | "completed" }[] }>>({});
34
+ const [agentSessions, setAgentSessions] = useState<Record<string, { initialPrompt: string; initialMessages?: any[]; initialTabs?: { id: number; url: string; title: string }[]; initialActiveTabId?: number; initialTodos?: { content: string; status: "pending" | "in_progress" | "completed" }[]; planDir?: string }>>({});
34
35
  const [loaded, setLoaded] = useState(false);
35
36
  const [retryKeys, setRetryKeys] = useState<Record<string, number>>({});
36
37
  const retryConfigRef = useRef<Map<string, { maxRetries: number; attempt: number; testPlan: string }>>(new Map());
@@ -130,8 +131,7 @@ export default function AppShell() {
130
131
  });
131
132
 
132
133
  const data = sr.toJSON(agentInfo, allClips);
133
- await window.bangonit?.saveReplayData?.({ runDir, data: JSON.stringify(data) });
134
- await window.bangonit?.generateReplayHtml?.({ runDir });
134
+ await window.bangonit?.generateReplayHtml?.({ runDir, data: JSON.stringify(data) });
135
135
  }, []);
136
136
 
137
137
  const handleStatusChange = useCallback((agentId: string, status: "running" | "idle", result?: "pass" | "fail") => {
@@ -182,7 +182,7 @@ export default function AppShell() {
182
182
  useEffect(() => {
183
183
  const cleanup = window.bangonit?.onTestPlan?.((data: TestPlanMessage) => {
184
184
  setCliMode(true);
185
- const { agentIndex, testPlan, name, retries, extraPrompt, record: doRecord } = data;
185
+ const { agentIndex, testPlan, name, retries, extraPrompt, record: doRecord, planDir } = data;
186
186
 
187
187
  if (doRecord && !sessionRecorderRef.current) {
188
188
  const runId = new Date().toISOString().replace(/[:.]/g, "-");
@@ -217,7 +217,7 @@ export default function AppShell() {
217
217
 
218
218
  setAgentSessions((prev) => ({
219
219
  ...prev,
220
- [agent.id]: { initialPrompt: prompt },
220
+ [agent.id]: { initialPrompt: prompt, planDir },
221
221
  }));
222
222
  setAgentStatuses((prev) => ({ ...prev, [agent.id]: "running" }));
223
223
  if (retries && retries > 0) {
@@ -313,6 +313,7 @@ export default function AppShell() {
313
313
  record={recording}
314
314
  sessionRecorder={sessionRecorderRef.current || undefined}
315
315
  onRegisterRecorder={registerBrowserRecorder}
316
+ planDir={agentSessions[agent.id].planDir}
316
317
  />
317
318
  </div>
318
319
  ) : null
@@ -31,6 +31,7 @@ export default function SessionView({
31
31
  record,
32
32
  sessionRecorder,
33
33
  onRegisterRecorder,
34
+ planDir,
34
35
  }: {
35
36
  agentId: string;
36
37
  agentName: string;
@@ -44,6 +45,7 @@ export default function SessionView({
44
45
  record?: boolean;
45
46
  sessionRecorder?: SessionRecorder;
46
47
  onRegisterRecorder?: (agentId: string, recorder: BrowserRecorder) => void;
48
+ planDir?: string;
47
49
  }) {
48
50
  const [tabs, setTabs] = useState<Tab[]>(
49
51
  initialTabs?.map((t) => ({ ...t, initialUrl: t.url })) || [
@@ -122,8 +124,7 @@ export default function SessionView({
122
124
  const clips = browserRecorderRef.current?.getClipsMeta() || [];
123
125
  const agentInfo = [{ id: agentId, name: agentName, result: result as "pass" | "fail", summary }];
124
126
  const replayData = sessionRecorderRef.current.toJSON(agentInfo, clips);
125
- await window.bangonit?.saveReplayData?.({ runDir, data: JSON.stringify(replayData) });
126
- await window.bangonit?.generateReplayHtml?.({ runDir });
127
+ await window.bangonit?.generateReplayHtml?.({ runDir, data: JSON.stringify(replayData) });
127
128
  }
128
129
  } catch (e) {
129
130
  console.error(e);
@@ -425,7 +426,7 @@ export default function SessionView({
425
426
  const wcId = el.getWebContentsId?.();
426
427
  if (wcId) {
427
428
  registeredTabsRef.current.add(tabId);
428
- window.bangonit?.registerTab(agentId, tabId, wcId, initialUrl);
429
+ window.bangonit?.registerTab(agentId, tabId, wcId, initialUrl, planDir);
429
430
  if (tabId === activeTabId) {
430
431
  window.bangonit?.setActiveTab(agentId, tabId);
431
432
  }
@@ -538,7 +539,7 @@ export default function SessionView({
538
539
 
539
540
  {/* Todo progress */}
540
541
  {todos.length > 0 && (
541
- <div className="text-xs space-y-1 px-4 py-2 border-b border-zinc-800 bg-zinc-900/80 shrink-0">
542
+ <div className="text-xs space-y-1 px-4 py-2 border-b border-zinc-800 bg-zinc-900/80 shrink-0 max-h-48 overflow-y-auto">
542
543
  {todos.map((todo, i) => (
543
544
  <div key={i} className={`flex items-center gap-2 ${todo.status === "completed" ? "text-zinc-500" : "text-zinc-300"}`}>
544
545
  <span className="shrink-0">
@@ -93,20 +93,21 @@ export class BrowserTools {
93
93
  return pressKey(this.agentId, args.key);
94
94
  case "browser_close":
95
95
  return tabAction(this.agentId, { action: "close" });
96
+ case "browser_upload": {
97
+ if (args.cancel) {
98
+ const result = await window.bangonit!.handleFileChooser(this.agentId, "cancel");
99
+ if (!result.ok) return `Error: ${result.error}`;
100
+ return "File picker cancelled.";
101
+ }
102
+ if (!args.paths?.length) return "Error: provide paths to upload, or cancel: true";
103
+ const result = await window.bangonit!.handleFileChooser(this.agentId, "accept", args.paths);
104
+ if (!result.ok) return `Error: ${result.error}`;
105
+ return `Uploaded ${args.paths.length} file(s).`;
106
+ }
96
107
  case "browser_wait_for":
97
108
  return waitFor(this.agentId, args);
98
109
  case "browser_tabs":
99
110
  return tabAction(this.agentId, args);
100
- case "browser_downloads": {
101
- const downloads = await window.bangonit!.getDownloads(this.agentId);
102
- if (!downloads.length) return "No downloads.";
103
- return downloads
104
- .map((d: any) => {
105
- const pct = d.totalBytes > 0 ? Math.round((d.bytes / d.totalBytes) * 100) + "%" : "";
106
- return `[${d.state}] ${d.filename} ${pct} → ${d.path}`;
107
- })
108
- .join("\n");
109
- }
110
111
  default:
111
112
  throw new Error(`Unknown tool: ${name}`);
112
113
  }
@@ -180,25 +181,12 @@ export class BrowserTools {
180
181
  }
181
182
  }
182
183
 
183
- // Stop recording clip and save
184
+ // Stop recording clip (base64 data is stored in the clip meta)
184
185
  if (this.recorder) {
185
186
  try {
186
- const clip = await this.recorder.stopClip();
187
- if (clip) {
188
- const runDir = await window.bangonit?.getRunDir?.();
189
- if (runDir) {
190
- const arrayBuffer = await clip.blob.arrayBuffer();
191
- await window.bangonit?.saveRecordingClip?.({
192
- runDir,
193
- agentId: clip.meta.agentId,
194
- clipIndex: clip.meta.index,
195
- tabId: clip.meta.tabId,
196
- data: arrayBuffer,
197
- });
198
- }
199
- }
187
+ await this.recorder.stopClip();
200
188
  } catch (e) {
201
- console.warn("Failed to save recording clip:", e);
189
+ console.warn("Failed to stop recording clip:", e);
202
190
  }
203
191
  }
204
192
 
@@ -208,7 +196,7 @@ export class BrowserTools {
208
196
  private actionToToolArgs(act: BrowserAction): any {
209
197
  switch (act.action) {
210
198
  case "navigate": return { url: act.url };
211
- case "back": case "forward": case "close": case "downloads": return {};
199
+ case "back": case "forward": case "close": return {};
212
200
  case "mouse": {
213
201
  const steps = (act.mouseActions || []).map((s) => {
214
202
  if (s.action === "wait") return { action: "wait", ms: s.ms || 100 };
@@ -220,6 +208,7 @@ export class BrowserTools {
220
208
  }
221
209
  case "type": return { text: act.text };
222
210
  case "press": return { key: act.key };
211
+ case "upload": return { paths: act.paths, cancel: act.cancel };
223
212
  case "tabs": return { action: act.tabAction, tabId: act.tabId, url: act.url };
224
213
  case "wait": return { timeout: act.timeout };
225
214
  default: return {};
@@ -240,6 +229,7 @@ export class BrowserTools {
240
229
  }
241
230
  case "type": return `type "${(act.text || "").slice(0, 30)}"`;
242
231
  case "press": return `press ${act.key}`;
232
+ case "upload": return act.cancel ? "upload cancel" : `upload ${(act.paths || []).join(", ")}`;
243
233
  case "tabs": return `tabs ${act.tabAction}${act.tabId ? " " + act.tabId : ""}`;
244
234
  case "wait": return `wait ${act.timeout || 10}s`;
245
235
  default: return act.action;
@@ -7,8 +7,8 @@ export interface ClipMeta {
7
7
  index: number;
8
8
  startTime: number;
9
9
  endTime: number;
10
- path: string;
11
10
  url?: string;
11
+ data: string; // base64-encoded webm video
12
12
  }
13
13
 
14
14
  interface CapturedFrame {
@@ -156,7 +156,7 @@ export class BrowserRecorder {
156
156
  });
157
157
  }
158
158
 
159
- async stopClip(): Promise<{ blob: Blob; meta: ClipMeta } | null> {
159
+ async stopClip(): Promise<{ meta: ClipMeta } | null> {
160
160
  if (!this.recording) return null;
161
161
  this.recording = false;
162
162
  const endTime = Date.now();
@@ -176,17 +176,26 @@ export class BrowserRecorder {
176
176
  const blob = await this.compositeAndEncode(frames);
177
177
  if (!blob || blob.size === 0) return null;
178
178
 
179
+ // Convert blob to base64 for self-contained replay
180
+ const arrayBuffer = await blob.arrayBuffer();
181
+ const bytes = new Uint8Array(arrayBuffer);
182
+ let binary = "";
183
+ for (let i = 0; i < bytes.length; i++) {
184
+ binary += String.fromCharCode(bytes[i]);
185
+ }
186
+ const data = btoa(binary);
187
+
179
188
  const meta: ClipMeta = {
180
189
  agentId: this.agentId,
181
190
  tabId: this.currentTabId,
182
191
  index: this.clips.length,
183
192
  startTime: this.clipStartTime,
184
193
  endTime,
185
- path: `clips/${this.agentId}/clip-${this.clips.length}-tab-${this.currentTabId}.webm`,
186
194
  url: this.currentUrl || undefined,
195
+ data,
187
196
  };
188
197
  this.clips.push(meta);
189
- return { blob, meta };
198
+ return { meta };
190
199
  }
191
200
 
192
201
  private async cancelClip(): Promise<void> {
@@ -124,9 +124,23 @@ export async function takeSnapshot(
124
124
  mouseY: number,
125
125
  tabSummary: string
126
126
  ): Promise<string> {
127
- const { result } = await window.bangonit!.cdpSend(agentId, "Runtime.evaluate", {
128
- expression: SNAPSHOT_JS,
129
- returnByValue: true,
130
- });
131
- return (result.value || "Empty page") + `\n\nMouse position: ${mouseX},${mouseY}` + tabSummary;
127
+ const [{ result }, downloads, fileChooser] = await Promise.all([
128
+ window.bangonit!.cdpSend(agentId, "Runtime.evaluate", {
129
+ expression: SNAPSHOT_JS,
130
+ returnByValue: true,
131
+ }),
132
+ window.bangonit!.getDownloads(agentId),
133
+ window.bangonit!.getFileChooserState(agentId),
134
+ ]);
135
+ let out = (result.value || "Empty page") + `\n\nMouse position: ${mouseX},${mouseY}` + tabSummary;
136
+ if (fileChooser.open) {
137
+ out += `\n\n[File picker is open — use upload action with paths to select files, or cancel: true to dismiss]`;
138
+ }
139
+ if (downloads.length > 0) {
140
+ const lines = downloads.map((d: any) =>
141
+ `- ${d.filename} (${d.bytes} bytes) [${d.state}]`
142
+ );
143
+ out += `\n\nDownloads:\n${lines.join("\n")}`;
144
+ }
145
+ return out;
132
146
  }
@@ -22,6 +22,8 @@ export interface BrowserAction {
22
22
  tabAction?: string;
23
23
  tabId?: number;
24
24
  timeout?: number;
25
+ paths?: string[];
26
+ cancel?: boolean;
25
27
  }
26
28
 
27
29
  export interface BrowserToolInput {
@@ -38,7 +40,7 @@ export const ACTION_TO_TOOL: Record<string, string> = {
38
40
  type: "browser_type",
39
41
  press: "browser_press_key",
40
42
  tabs: "browser_tabs",
41
- downloads: "browser_downloads",
43
+ upload: "browser_upload",
42
44
  wait: "browser_wait_for",
43
45
  close: "browser_close",
44
46
  };
@@ -81,6 +83,24 @@ export const TOOL_DEFS = [
81
83
  description: "Close the current page/tab",
82
84
  parameters: { type: "object", properties: {} },
83
85
  },
86
+ {
87
+ name: "browser_upload",
88
+ description: "Upload files to an open file picker, or cancel it. The snapshot will show when a file picker is open.",
89
+ parameters: {
90
+ type: "object",
91
+ properties: {
92
+ paths: {
93
+ type: "array",
94
+ items: { type: "string" },
95
+ description: "Absolute file paths to upload",
96
+ },
97
+ cancel: {
98
+ type: "boolean",
99
+ description: "Cancel the file picker instead of uploading",
100
+ },
101
+ },
102
+ },
103
+ },
84
104
  {
85
105
  name: "browser_wait_for",
86
106
  description: "Wait for text to appear or disappear on the page, or wait a specified time",
@@ -93,11 +113,6 @@ export const TOOL_DEFS = [
93
113
  },
94
114
  },
95
115
  },
96
- {
97
- name: "browser_downloads",
98
- description: "List recent file downloads",
99
- parameters: { type: "object", properties: {} },
100
- },
101
116
  {
102
117
  name: "browser_tabs",
103
118
  description: "List, create, close, or select browser tabs",
@@ -47,7 +47,7 @@ interface BangOnIt {
47
47
  getURL: (agentId: string) => Promise<string | null>;
48
48
 
49
49
  // Tab management
50
- registerTab: (agentId: string, tabId: number, wcId: number, initialUrl: string) => Promise<void>;
50
+ registerTab: (agentId: string, tabId: number, wcId: number, initialUrl: string, planDir?: string) => Promise<void>;
51
51
  setActiveTab: (agentId: string, tabId: number) => Promise<void>;
52
52
  getTabInfo: (agentId: string) => Promise<{ tabs: any[]; activeTabId: number | null }>;
53
53
  requestNewTab: (agentId: string, url: string) => Promise<void>;
@@ -57,6 +57,10 @@ interface BangOnIt {
57
57
  // Downloads
58
58
  getDownloads: (agentId: string) => Promise<any[]>;
59
59
 
60
+ // File chooser
61
+ handleFileChooser: (agentId: string, action: "accept" | "cancel", files?: string[]) => Promise<{ ok: boolean; error?: string }>;
62
+ getFileChooserState: (agentId: string) => Promise<{ open: boolean; mode?: string }>;
63
+
60
64
  // Events — data includes agentId
61
65
  onTabUpdated: (cb: (data: TabInfo) => void) => () => void;
62
66
  onOpenNewTab: (cb: (data: { agentId: string; url: string }) => void) => () => void;
@@ -90,9 +94,7 @@ interface BangOnIt {
90
94
  emitTestRetry?: (data: { agentId: string; attempt: number; maxRetries: number }) => void;
91
95
 
92
96
  // Recording
93
- saveRecordingClip?: (opts: { runDir: string; agentId: string; clipIndex: number; tabId: number; data: ArrayBuffer }) => Promise<void>;
94
- saveReplayData?: (opts: { runDir: string; data: string }) => Promise<void>;
95
- generateReplayHtml?: (opts: { runDir: string }) => Promise<void>;
97
+ generateReplayHtml?: (opts: { runDir: string; data: string }) => Promise<void>;
96
98
  getRunDir?: () => Promise<string | null>;
97
99
  }
98
100
 
@@ -48,6 +48,7 @@ const Minio = __importStar(require("minio"));
48
48
  const yargs_1 = __importDefault(require("yargs"));
49
49
  const helpers_1 = require("yargs/helpers");
50
50
  const is_ci_1 = __importDefault(require("is-ci"));
51
+ const dotenv = __importStar(require("dotenv"));
51
52
  const args_1 = require("../../app/desktopapp/src/shared/args");
52
53
  const ROOT = path.resolve(__dirname, "..", "..", "..");
53
54
  const WEBAPP_DIR = path.join(ROOT, "app", "webapp");
@@ -99,17 +100,7 @@ async function waitForPort(port, timeoutMs = 30000) {
99
100
  die(`Timed out waiting for port ${port}`);
100
101
  }
101
102
  function loadEnv() {
102
- if (!process.env.ANTHROPIC_API_KEY) {
103
- const envPath = path.join(process.cwd(), ".env");
104
- if (fs.existsSync(envPath)) {
105
- for (const line of fs.readFileSync(envPath, "utf-8").split("\n")) {
106
- const match = line.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
107
- if (match && !process.env[match[1]]) {
108
- process.env[match[1]] = match[2].replace(/^["']|["']$/g, "");
109
- }
110
- }
111
- }
112
- }
103
+ dotenv.config({ quiet: true });
113
104
  }
114
105
  // Interpolate ${ENV_VAR} references in string values throughout an object
115
106
  function interpolateEnv(obj) {
@@ -651,12 +642,31 @@ async function run(argv, config) {
651
642
  die(`Webapp server crashed (exit code ${code}). Check logs/webapp.log for details.`);
652
643
  }
653
644
  });
645
+ // Save terminal state before Electron (which inherits stdin) can modify it
646
+ let savedTtyState = null;
647
+ try {
648
+ savedTtyState = (0, child_process_1.execSync)("stty -g", { stdio: ["inherit", "pipe", "ignore"] }).toString().trim();
649
+ }
650
+ catch (e) {
651
+ console.error("[cli] stty save failed:", e.message);
652
+ }
654
653
  const cleanup = () => {
655
654
  webappCrashed = true; // suppress crash message during normal shutdown
656
655
  try {
657
656
  webappProc.kill();
658
657
  }
659
- catch { }
658
+ catch (e) {
659
+ console.error("[cli] webappProc.kill failed:", e.message);
660
+ }
661
+ // Restore terminal state — Electron may have changed raw mode, echo, etc.
662
+ if (savedTtyState) {
663
+ try {
664
+ (0, child_process_1.execSync)(`stty ${savedTtyState}`, { stdio: ["inherit", "ignore", "ignore"] });
665
+ }
666
+ catch (e) {
667
+ console.error("[cli] stty restore failed:", e.message);
668
+ }
669
+ }
660
670
  };
661
671
  process.on("exit", cleanup);
662
672
  process.on("SIGINT", () => { cleanup(); process.exit(1); });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bangonit",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "description": "AI-powered E2E testing tool",
5
5
  "bin": {
6
6
  "bangonit": "bin/src/cli/bangonit.js",
@@ -13,7 +13,8 @@
13
13
  "build:cli": "npx tsc -p tsconfig.cli.json",
14
14
  "build:webapp": "cd app/webapp && npm run build && cp -r .next/static .next/standalone/app/webapp/.next/static",
15
15
  "build:electron": "cd app/desktopapp && npx tsc",
16
- "build:replay": "cd app/replay && npx vite build"
16
+ "build:replay": "cd app/replay && npx vite build",
17
+ "test": "node --test test/*.test.ts"
17
18
  },
18
19
  "workspaces": [
19
20
  "app/*"
@@ -49,6 +50,7 @@
49
50
  },
50
51
  "dependencies": {
51
52
  "@iarna/toml": "^2.2.5",
53
+ "dotenv": "^17.3.1",
52
54
  "electron": "^40.8.0",
53
55
  "electron-store": "^8.1.0",
54
56
  "is-ci": "^4.1.0",
@@ -59,6 +61,7 @@
59
61
  "devDependencies": {
60
62
  "@types/is-ci": "^3.0.4",
61
63
  "@types/yargs": "^17.0.35",
64
+ "concurrently": "^9.2.1",
62
65
  "playwright": "^1.58.2"
63
66
  }
64
67
  }