bloby-bot 0.54.12 → 0.55.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.
- package/dist-bloby/assets/{bloby-CjvuL1QI.js → bloby-C0cl8nq4.js} +77 -77
- package/dist-bloby/assets/globals-BqjrOUer.css +2 -0
- package/dist-bloby/assets/{highlighted-body-OFNGDK62-D0QQRXpE.js → highlighted-body-OFNGDK62-BwjDEAOv.js} +1 -1
- package/dist-bloby/assets/mermaid-GHXKKRXX-B_2tdKu_.js +1 -0
- package/dist-bloby/assets/{onboard-DU3OfA5h.js → onboard-CeuzZ0Ku.js} +1 -1
- package/dist-bloby/bloby.html +3 -3
- package/dist-bloby/onboard.html +3 -3
- package/package.json +4 -5
- package/supervisor/chat/src/components/Chat/AudioBubble.tsx +11 -4
- package/supervisor/chat/src/components/Chat/AuthedImage.tsx +25 -0
- package/supervisor/chat/src/components/Chat/BlobyImageCard.tsx +18 -8
- package/supervisor/chat/src/components/Chat/ImageLightbox.tsx +20 -7
- package/supervisor/chat/src/components/Chat/MessageBubble.tsx +13 -3
- package/supervisor/chat/src/components/Chat/MessageList.tsx +3 -0
- package/supervisor/chat/src/components/Chat/MorphyActionCard.tsx +50 -0
- package/supervisor/chat/src/lib/authedFile.ts +57 -0
- package/supervisor/index.ts +1 -1
- package/workspace/skills/mac/SKILL.md +5 -5
- package/dist-bloby/assets/globals-ZdFBsH0Q.css +0 -2
- package/dist-bloby/assets/mermaid-GHXKKRXX-D9GshF2B.js +0 -1
- /package/dist-bloby/assets/{globals-UaNdQXf5.js → globals-DSmE2rZO.js} +0 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-space-x-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-content:""}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-100:oklch(93.6% .032 17.717);--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-red-800:oklch(44.4% .177 26.899);--color-orange-400:oklch(75% .183 55.934);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-500:oklch(76.9% .188 70.08);--color-amber-600:oklch(66.6% .179 58.318);--color-emerald-400:oklch(76.5% .177 163.223);--color-emerald-500:oklch(69.6% .17 162.48);--color-blue-400:oklch(70.7% .165 254.624);--color-blue-500:oklch(62.3% .214 259.815);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-900:oklch(21% .034 264.665);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-md:28rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wider:.05em;--tracking-widest:.1em;--leading-tight:1.25;--leading-snug:1.375;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--ease-out:cubic-bezier(0, 0, .2, 1);--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--animate-ping:ping 1s cubic-bezier(0, 0, .2, 1) infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--animate-bounce:bounce 1s infinite;--blur-sm:8px;--blur-md:12px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-background:#1a1a1a;--color-foreground:#ebebeb}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}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;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.inset-y-0{inset-block:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.-top-1\.5{top:calc(var(--spacing) * -1.5)}.-top-2\.5{top:calc(var(--spacing) * -2.5)}.top-1{top:calc(var(--spacing) * 1)}.top-1\/2{top:50%}.top-2{top:calc(var(--spacing) * 2)}.top-4{top:calc(var(--spacing) * 4)}.top-full{top:100%}.-right-1\.5{right:calc(var(--spacing) * -1.5)}.right-0{right:calc(var(--spacing) * 0)}.right-2{right:calc(var(--spacing) * 2)}.right-3{right:calc(var(--spacing) * 3)}.right-4{right:calc(var(--spacing) * 4)}.bottom-2{bottom:calc(var(--spacing) * 2)}.bottom-4{bottom:calc(var(--spacing) * 4)}.left-0{left:calc(var(--spacing) * 0)}.left-1\/2{left:50%}.left-2{left:calc(var(--spacing) * 2)}.left-3{left:calc(var(--spacing) * 3)}.left-4{left:calc(var(--spacing) * 4)}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.z-\[200\]{z-index:200}.z-\[300\]{z-index:300}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.mx-2{margin-inline:calc(var(--spacing) * 2)}.mx-4{margin-inline:calc(var(--spacing) * 4)}.my-2{margin-block:calc(var(--spacing) * 2)}.my-3{margin-block:calc(var(--spacing) * 3)}.my-4{margin-block:calc(var(--spacing) * 4)}.my-6{margin-block:calc(var(--spacing) * 6)}.-mt-3{margin-top:calc(var(--spacing) * -3)}.-mt-10{margin-top:calc(var(--spacing) * -10)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-2\.5{margin-top:calc(var(--spacing) * 2.5)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-px{margin-top:1px}.mr-1\.5{margin-right:calc(var(--spacing) * 1.5)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-5{margin-bottom:calc(var(--spacing) * 5)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.-ml-1{margin-left:calc(var(--spacing) * -1)}.ml-0\.5{margin-left:calc(var(--spacing) * .5)}.ml-1{margin-left:calc(var(--spacing) * 1)}.ml-1\.5{margin-left:calc(var(--spacing) * 1.5)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-2\.5{margin-left:calc(var(--spacing) * 2.5)}.ml-3{margin-left:calc(var(--spacing) * 3)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.list-item{display:list-item}.table{display:table}.table-cell{display:table-cell}.table-row{display:table-row}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-full{width:100%;height:100%}.h-1{height:calc(var(--spacing) * 1)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-3{height:calc(var(--spacing) * 3)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-11{height:calc(var(--spacing) * 11)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-16{height:calc(var(--spacing) * 16)}.h-28{height:calc(var(--spacing) * 28)}.h-40{height:calc(var(--spacing) * 40)}.h-\[18px\]{height:18px}.h-\[22px\]{height:22px}.h-\[46px\]{height:46px}.h-\[140px\]{height:140px}.h-\[180px\]{height:180px}.h-dvh{height:100dvh}.h-full{height:100%}.max-h-32{max-height:calc(var(--spacing) * 32)}.max-h-80{max-height:calc(var(--spacing) * 80)}.max-h-\[85vh\]{max-height:85vh}.max-h-\[300px\]{max-height:300px}.max-h-\[320px\]{max-height:320px}.max-h-\[500px\]{max-height:500px}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-28{min-height:calc(var(--spacing) * 28)}.min-h-\[200px\]{min-height:200px}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-3{width:calc(var(--spacing) * 3)}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-9{width:calc(var(--spacing) * 9)}.w-10{width:calc(var(--spacing) * 10)}.w-11{width:calc(var(--spacing) * 11)}.w-12{width:calc(var(--spacing) * 12)}.w-14{width:calc(var(--spacing) * 14)}.w-16{width:calc(var(--spacing) * 16)}.w-28{width:calc(var(--spacing) * 28)}.w-32{width:calc(var(--spacing) * 32)}.w-40{width:calc(var(--spacing) * 40)}.w-48{width:calc(var(--spacing) * 48)}.w-\[18px\]{width:18px}.w-\[140px\]{width:140px}.w-auto{width:auto}.w-fit{width:fit-content}.w-full{width:100%}.w-px{width:1px}.max-w-\[85\%\]{max-width:85%}.max-w-\[90vw\]{max-width:90vw}.max-w-\[320px\]{max-width:320px}.max-w-\[340px\]{max-width:340px}.max-w-\[360px\]{max-width:360px}.max-w-\[480px\]{max-width:480px}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.max-w-none{max-width:none}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-\[120px\]{min-width:120px}.min-w-\[180px\]{min-width:180px}.min-w-\[200px\]{min-width:200px}.min-w-\[220px\]{min-width:220px}.flex-1{flex:1}.flex-shrink-0,.shrink-0{flex-shrink:0}.border-collapse{border-collapse:collapse}.origin-center{transform-origin:50%}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-0{--tw-translate-x:calc(var(--spacing) * 0);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-1{--tw-translate-x:calc(var(--spacing) * 1);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-5{--tw-translate-x:calc(var(--spacing) * 5);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-\[18px\]{--tw-translate-x:18px;translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-\[5px\]{--tw-translate-y:calc(5px * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.rotate-90{rotate:90deg}.rotate-180{rotate:180deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-bounce{animation:var(--animate-bounce)}.animate-ping{animation:var(--animate-ping)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.resize{resize:both}.resize-none{resize:none}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.appearance-none{appearance:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-3\.5{gap:calc(var(--spacing) * 3.5)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-x-2>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing) * 2) * var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-x-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-border>:not(:last-child)){border-color:#333}.self-end{align-self:flex-end}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.75rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\[24px\]{border-radius:24px}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-\[1\.5px\]{border-style:var(--tw-border-style);border-width:1.5px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-\[\#00CAFF\]\/20{border-color:oklab(78.0899% -.104231 -.105835/.2)}.border-\[\#25D366\]\/20{border-color:oklab(76.0953% -.174012 .10152/.2)}.border-\[\#0069FE\]{border-color:#0069fe}.border-\[\#0069FE\]\/10{border-color:oklab(56.8276% -.0396384 -.232806/.1)}.border-\[\#0069FE\]\/15{border-color:oklab(56.8276% -.0396384 -.232806/.15)}.border-\[\#0069FE\]\/20{border-color:oklab(56.8276% -.0396384 -.232806/.2)}.border-\[\#0069FE\]\/25{border-color:oklab(56.8276% -.0396384 -.232806/.25)}.border-\[\#0069FE\]\/30{border-color:oklab(56.8276% -.0396384 -.232806/.3)}.border-\[\#0069FE\]\/40{border-color:oklab(56.8276% -.0396384 -.232806/.4)}.border-amber-500\/20{border-color:#f99c0033}@supports (color:color-mix(in lab, red, red)){.border-amber-500\/20{border-color:color-mix(in oklab, var(--color-amber-500) 20%, transparent)}}.border-blue-500\/20{border-color:#3080ff33}@supports (color:color-mix(in lab, red, red)){.border-blue-500\/20{border-color:color-mix(in oklab, var(--color-blue-500) 20%, transparent)}}.border-border{border-color:#333}.border-border\/15{border-color:oklab(32.1092% 2.98023e-8 0/.15)}.border-border\/30{border-color:oklab(32.1092% 2.98023e-8 0/.3)}.border-border\/40{border-color:oklab(32.1092% 2.98023e-8 0/.4)}.border-border\/60{border-color:oklab(32.1092% 2.98023e-8 0/.6)}.border-current{border-color:currentColor}.border-emerald-500\/15{border-color:#00bb7f26}@supports (color:color-mix(in lab, red, red)){.border-emerald-500\/15{border-color:color-mix(in oklab, var(--color-emerald-500) 15%, transparent)}}.border-emerald-500\/20{border-color:#00bb7f33}@supports (color:color-mix(in lab, red, red)){.border-emerald-500\/20{border-color:color-mix(in oklab, var(--color-emerald-500) 20%, transparent)}}.border-muted-foreground\/20{border-color:oklab(68.2953% 2.98023e-8 5.96046e-8/.2)}.border-muted-foreground\/30{border-color:oklab(68.2953% 2.98023e-8 5.96046e-8/.3)}.border-red-500\/15{border-color:#fb2c3626}@supports (color:color-mix(in lab, red, red)){.border-red-500\/15{border-color:color-mix(in oklab, var(--color-red-500) 15%, transparent)}}.border-red-500\/20{border-color:#fb2c3633}@supports (color:color-mix(in lab, red, red)){.border-red-500\/20{border-color:color-mix(in oklab, var(--color-red-500) 20%, transparent)}}.border-sidebar{border-color:#222}.border-white\/10{border-color:#ffffff1a}@supports (color:color-mix(in lab, red, red)){.border-white\/10{border-color:color-mix(in oklab, var(--color-white) 10%, transparent)}}.border-white\/20{border-color:#fff3}@supports (color:color-mix(in lab, red, red)){.border-white\/20{border-color:color-mix(in oklab, var(--color-white) 20%, transparent)}}.border-white\/\[0\.04\]{border-color:#ffffff0a}@supports (color:color-mix(in lab, red, red)){.border-white\/\[0\.04\]{border-color:color-mix(in oklab, var(--color-white) 4%, transparent)}}.border-white\/\[0\.06\]{border-color:#ffffff0f}@supports (color:color-mix(in lab, red, red)){.border-white\/\[0\.06\]{border-color:color-mix(in oklab, var(--color-white) 6%, transparent)}}.border-white\/\[0\.08\]{border-color:#ffffff14}@supports (color:color-mix(in lab, red, red)){.border-white\/\[0\.08\]{border-color:color-mix(in oklab, var(--color-white) 8%, transparent)}}.border-white\/\[0\.12\]{border-color:#ffffff1f}@supports (color:color-mix(in lab, red, red)){.border-white\/\[0\.12\]{border-color:color-mix(in oklab, var(--color-white) 12%, transparent)}}.border-t-\[\#0069FE\]{border-top-color:#0069fe}.border-t-muted-foreground\/60{border-top-color:oklab(68.2953% 2.98023e-8 5.96046e-8/.6)}.border-t-primary{border-top-color:#0069fe}.border-t-white\/50{border-top-color:#ffffff80}@supports (color:color-mix(in lab, red, red)){.border-t-white\/50{border-top-color:color-mix(in oklab, var(--color-white) 50%, transparent)}}.bg-\[\#00CAFF\]{background-color:#00caff}.bg-\[\#00CAFF\]\/10{background-color:oklab(78.0899% -.104231 -.105835/.1)}.bg-\[\#1c1c1e\]{background-color:#1c1c1e}.bg-\[\#007AFF\]\/15{background-color:oklab(60.2765% -.047404 -.212489/.15)}.bg-\[\#25D366\]{background-color:#25d366}.bg-\[\#25D366\]\/10{background-color:oklab(76.0953% -.174012 .10152/.1)}.bg-\[\#0069FE\]{background-color:#0069fe}.bg-\[\#0069FE\]\/10{background-color:oklab(56.8276% -.0396384 -.232806/.1)}.bg-\[\#0069FE\]\/15{background-color:oklab(56.8276% -.0396384 -.232806/.15)}.bg-\[\#222\]{background-color:#222}.bg-\[\#181818\]{background-color:#181818}.bg-\[var\(--sdm-tbg\)\]{background-color:var(--sdm-tbg)}.bg-amber-500\/8{background-color:#f99c0014}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/8{background-color:color-mix(in oklab, var(--color-amber-500) 8%, transparent)}}.bg-amber-500\/15{background-color:#f99c0026}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/15{background-color:color-mix(in oklab, var(--color-amber-500) 15%, transparent)}}.bg-amber-600{background-color:var(--color-amber-600)}.bg-background{background-color:#1a1a1a}.bg-background\/50{background-color:oklab(21.7786% -7.45058e-9 0/.5)}.bg-background\/80{background-color:oklab(21.7786% -7.45058e-9 0/.8)}.bg-background\/90{background-color:oklab(21.7786% -7.45058e-9 0/.9)}.bg-background\/95{background-color:oklab(21.7786% -7.45058e-9 0/.95)}.bg-black{background-color:var(--color-black)}.bg-black\/10{background-color:#0000001a}@supports (color:color-mix(in lab, red, red)){.bg-black\/10{background-color:color-mix(in oklab, var(--color-black) 10%, transparent)}}.bg-black\/20{background-color:#0003}@supports (color:color-mix(in lab, red, red)){.bg-black\/20{background-color:color-mix(in oklab, var(--color-black) 20%, transparent)}}.bg-black\/40{background-color:#0006}@supports (color:color-mix(in lab, red, red)){.bg-black\/40{background-color:color-mix(in oklab, var(--color-black) 40%, transparent)}}.bg-black\/60{background-color:#0009}@supports (color:color-mix(in lab, red, red)){.bg-black\/60{background-color:color-mix(in oklab, var(--color-black) 60%, transparent)}}.bg-black\/80{background-color:#000c}@supports (color:color-mix(in lab, red, red)){.bg-black\/80{background-color:color-mix(in oklab, var(--color-black) 80%, transparent)}}.bg-black\/85{background-color:#000000d9}@supports (color:color-mix(in lab, red, red)){.bg-black\/85{background-color:color-mix(in oklab, var(--color-black) 85%, transparent)}}.bg-black\/90{background-color:#000000e6}@supports (color:color-mix(in lab, red, red)){.bg-black\/90{background-color:color-mix(in oklab, var(--color-black) 90%, transparent)}}.bg-blue-500\/10{background-color:#3080ff1a}@supports (color:color-mix(in lab, red, red)){.bg-blue-500\/10{background-color:color-mix(in oklab, var(--color-blue-500) 10%, transparent)}}.bg-card\/50{background-color:oklab(25.1965% -7.45058e-9 0/.5)}.bg-destructive{background-color:#f04d68}.bg-destructive\/10{background-color:oklab(65.3498% .191597 .0514832/.1)}.bg-emerald-500{background-color:var(--color-emerald-500)}.bg-emerald-500\/5{background-color:#00bb7f0d}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/5{background-color:color-mix(in oklab, var(--color-emerald-500) 5%, transparent)}}.bg-emerald-500\/8{background-color:#00bb7f14}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/8{background-color:color-mix(in oklab, var(--color-emerald-500) 8%, transparent)}}.bg-emerald-500\/10{background-color:#00bb7f1a}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/10{background-color:color-mix(in oklab, var(--color-emerald-500) 10%, transparent)}}.bg-emerald-500\/15{background-color:#00bb7f26}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/15{background-color:color-mix(in oklab, var(--color-emerald-500) 15%, transparent)}}.bg-emerald-500\/20{background-color:#00bb7f33}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/20{background-color:color-mix(in oklab, var(--color-emerald-500) 20%, transparent)}}.bg-emerald-500\/\[0\.04\]{background-color:#00bb7f0a}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/\[0\.04\]{background-color:color-mix(in oklab, var(--color-emerald-500) 4%, transparent)}}.bg-gray-200{background-color:var(--color-gray-200)}.bg-muted{background-color:#272727}.bg-muted-foreground\/60{background-color:oklab(68.2953% 2.98023e-8 5.96046e-8/.6)}.bg-muted\/20{background-color:oklab(27.2741% 7.45058e-8 0/.2)}.bg-muted\/30{background-color:oklab(27.2741% 7.45058e-8 0/.3)}.bg-muted\/80{background-color:oklab(27.2741% 7.45058e-8 0/.8)}.bg-orange-400{background-color:var(--color-orange-400)}.bg-popover{background-color:#252525}.bg-primary{background-color:#0069fe}.bg-primary\/10{background-color:oklab(56.8276% -.0396384 -.232806/.1)}.bg-red-50{background-color:var(--color-red-50)}.bg-red-100{background-color:var(--color-red-100)}.bg-red-500{background-color:var(--color-red-500)}.bg-red-500\/8{background-color:#fb2c3614}@supports (color:color-mix(in lab, red, red)){.bg-red-500\/8{background-color:color-mix(in oklab, var(--color-red-500) 8%, transparent)}}.bg-red-500\/10{background-color:#fb2c361a}@supports (color:color-mix(in lab, red, red)){.bg-red-500\/10{background-color:color-mix(in oklab, var(--color-red-500) 10%, transparent)}}.bg-sidebar{background-color:#222}.bg-sidebar\/80{background-color:oklab(25.1965% -7.45058e-9 0/.8)}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.bg-white\/5{background-color:#ffffff0d}@supports (color:color-mix(in lab, red, red)){.bg-white\/5{background-color:color-mix(in oklab, var(--color-white) 5%, transparent)}}.bg-white\/10{background-color:#ffffff1a}@supports (color:color-mix(in lab, red, red)){.bg-white\/10{background-color:color-mix(in oklab, var(--color-white) 10%, transparent)}}.bg-white\/15{background-color:#ffffff26}@supports (color:color-mix(in lab, red, red)){.bg-white\/15{background-color:color-mix(in oklab, var(--color-white) 15%, transparent)}}.bg-white\/20{background-color:#fff3}@supports (color:color-mix(in lab, red, red)){.bg-white\/20{background-color:color-mix(in oklab, var(--color-white) 20%, transparent)}}.bg-white\/70{background-color:#ffffffb3}@supports (color:color-mix(in lab, red, red)){.bg-white\/70{background-color:color-mix(in oklab, var(--color-white) 70%, transparent)}}.bg-white\/\[0\.02\]{background-color:#ffffff05}@supports (color:color-mix(in lab, red, red)){.bg-white\/\[0\.02\]{background-color:color-mix(in oklab, var(--color-white) 2%, transparent)}}.bg-white\/\[0\.03\]{background-color:#ffffff08}@supports (color:color-mix(in lab, red, red)){.bg-white\/\[0\.03\]{background-color:color-mix(in oklab, var(--color-white) 3%, transparent)}}.bg-white\/\[0\.04\]{background-color:#ffffff0a}@supports (color:color-mix(in lab, red, red)){.bg-white\/\[0\.04\]{background-color:color-mix(in oklab, var(--color-white) 4%, transparent)}}.bg-white\/\[0\.05\]{background-color:#ffffff0d}@supports (color:color-mix(in lab, red, red)){.bg-white\/\[0\.05\]{background-color:color-mix(in oklab, var(--color-white) 5%, transparent)}}.bg-white\/\[0\.06\]{background-color:#ffffff0f}@supports (color:color-mix(in lab, red, red)){.bg-white\/\[0\.06\]{background-color:color-mix(in oklab, var(--color-white) 6%, transparent)}}.bg-white\/\[0\.08\]{background-color:#ffffff14}@supports (color:color-mix(in lab, red, red)){.bg-white\/\[0\.08\]{background-color:color-mix(in oklab, var(--color-white) 8%, transparent)}}.fill-current{fill:currentColor}.fill-white{fill:var(--color-white)}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.p-1{padding:calc(var(--spacing) * 1)}.p-1\.5{padding:calc(var(--spacing) * 1.5)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.px-0\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-7{padding-inline:calc(var(--spacing) * 7)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-3\.5{padding-block:calc(var(--spacing) * 3.5)}.py-8{padding-block:calc(var(--spacing) * 8)}.pt-0{padding-top:calc(var(--spacing) * 0)}.pt-1{padding-top:calc(var(--spacing) * 1)}.pt-1\.5{padding-top:calc(var(--spacing) * 1.5)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-2\.5{padding-top:calc(var(--spacing) * 2.5)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-5{padding-top:calc(var(--spacing) * 5)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pr-0\.5{padding-right:calc(var(--spacing) * .5)}.pr-1{padding-right:calc(var(--spacing) * 1)}.pr-10{padding-right:calc(var(--spacing) * 10)}.pr-16{padding-right:calc(var(--spacing) * 16)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-5{padding-bottom:calc(var(--spacing) * 5)}.pb-6{padding-bottom:calc(var(--spacing) * 6)}.pb-8{padding-bottom:calc(var(--spacing) * 8)}.pl-1{padding-left:calc(var(--spacing) * 1)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-4{padding-left:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[8px\]{font-size:8px}.text-\[10\.5px\]{font-size:10.5px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[17px\]{font-size:17px}.text-\[20px\]{font-size:20px}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[-0\.01em\]{--tw-tracking:-.01em;letter-spacing:-.01em}.tracking-\[0\.3em\]{--tw-tracking:.3em;letter-spacing:.3em}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-words{overflow-wrap:break-word}.wrap-anywhere{overflow-wrap:anywhere}.break-all{word-break:break-all}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[\#00CAFF\]{color:#00caff}.text-\[\#4AA8FF\]{color:#4aa8ff}.text-\[\#007AFF\]{color:#007aff}.text-\[\#9ecbff\]{color:#9ecbff}.text-\[\#9ecbff\]\/55{color:oklab(82.8868% -.026421 -.0835843/.55)}.text-\[\#9ecbff\]\/80{color:oklab(82.8868% -.026421 -.0835843/.8)}.text-\[\#25D366\]{color:#25d366}.text-\[\#0069FE\]{color:#0069fe}.text-\[\#0069FE\]\/60{color:oklab(56.8276% -.0396384 -.232806/.6)}.text-\[var\(--sdm-c\,inherit\)\]{color:var(--sdm-c,inherit)}.text-amber-400{color:var(--color-amber-400)}.text-amber-400\/50{color:#fcbb0080}@supports (color:color-mix(in lab, red, red)){.text-amber-400\/50{color:color-mix(in oklab, var(--color-amber-400) 50%, transparent)}}.text-amber-400\/60{color:#fcbb0099}@supports (color:color-mix(in lab, red, red)){.text-amber-400\/60{color:color-mix(in oklab, var(--color-amber-400) 60%, transparent)}}.text-amber-400\/70{color:#fcbb00b3}@supports (color:color-mix(in lab, red, red)){.text-amber-400\/70{color:color-mix(in oklab, var(--color-amber-400) 70%, transparent)}}.text-amber-400\/90{color:#fcbb00e6}@supports (color:color-mix(in lab, red, red)){.text-amber-400\/90{color:color-mix(in oklab, var(--color-amber-400) 90%, transparent)}}.text-blue-400{color:var(--color-blue-400)}.text-destructive{color:#f04d68}.text-destructive-foreground{color:#fff}.text-emerald-400{color:var(--color-emerald-400)}.text-emerald-400\/60{color:#00d29499}@supports (color:color-mix(in lab, red, red)){.text-emerald-400\/60{color:color-mix(in oklab, var(--color-emerald-400) 60%, transparent)}}.text-emerald-400\/70{color:#00d294b3}@supports (color:color-mix(in lab, red, red)){.text-emerald-400\/70{color:color-mix(in oklab, var(--color-emerald-400) 70%, transparent)}}.text-emerald-400\/90{color:#00d294e6}@supports (color:color-mix(in lab, red, red)){.text-emerald-400\/90{color:color-mix(in oklab, var(--color-emerald-400) 90%, transparent)}}.text-foreground{color:#ebebeb}.text-foreground\/80{color:oklab(94.007% 1.19209e-7 0/.8)}.text-gray-400{color:var(--color-gray-400)}.text-gray-900{color:var(--color-gray-900)}.text-muted-foreground{color:#999}.text-muted-foreground\/35{color:oklab(68.2953% 2.98023e-8 5.96046e-8/.35)}.text-muted-foreground\/40{color:oklab(68.2953% 2.98023e-8 5.96046e-8/.4)}.text-muted-foreground\/50{color:oklab(68.2953% 2.98023e-8 5.96046e-8/.5)}.text-muted-foreground\/60{color:oklab(68.2953% 2.98023e-8 5.96046e-8/.6)}.text-muted-foreground\/70{color:oklab(68.2953% 2.98023e-8 5.96046e-8/.7)}.text-primary{color:#0069fe}.text-primary-foreground{color:#fff}.text-primary-foreground\/60{color:oklab(100% 0 5.96046e-8/.6)}.text-red-400{color:var(--color-red-400)}.text-red-400\/70{color:#ff6568b3}@supports (color:color-mix(in lab, red, red)){.text-red-400\/70{color:color-mix(in oklab, var(--color-red-400) 70%, transparent)}}.text-red-400\/90{color:#ff6568e6}@supports (color:color-mix(in lab, red, red)){.text-red-400\/90{color:color-mix(in oklab, var(--color-red-400) 90%, transparent)}}.text-red-600{color:var(--color-red-600)}.text-red-700{color:var(--color-red-700)}.text-red-800{color:var(--color-red-800)}.text-white{color:var(--color-white)}.text-white\/20{color:#fff3}@supports (color:color-mix(in lab, red, red)){.text-white\/20{color:color-mix(in oklab, var(--color-white) 20%, transparent)}}.text-white\/25{color:#ffffff40}@supports (color:color-mix(in lab, red, red)){.text-white\/25{color:color-mix(in oklab, var(--color-white) 25%, transparent)}}.text-white\/30{color:#ffffff4d}@supports (color:color-mix(in lab, red, red)){.text-white\/30{color:color-mix(in oklab, var(--color-white) 30%, transparent)}}.text-white\/35{color:#ffffff59}@supports (color:color-mix(in lab, red, red)){.text-white\/35{color:color-mix(in oklab, var(--color-white) 35%, transparent)}}.text-white\/40{color:#fff6}@supports (color:color-mix(in lab, red, red)){.text-white\/40{color:color-mix(in oklab, var(--color-white) 40%, transparent)}}.text-white\/50{color:#ffffff80}@supports (color:color-mix(in lab, red, red)){.text-white\/50{color:color-mix(in oklab, var(--color-white) 50%, transparent)}}.text-white\/60{color:#fff9}@supports (color:color-mix(in lab, red, red)){.text-white\/60{color:color-mix(in oklab, var(--color-white) 60%, transparent)}}.text-white\/70{color:#ffffffb3}@supports (color:color-mix(in lab, red, red)){.text-white\/70{color:color-mix(in oklab, var(--color-white) 70%, transparent)}}.text-white\/80{color:#fffc}@supports (color:color-mix(in lab, red, red)){.text-white\/80{color:color-mix(in oklab, var(--color-white) 80%, transparent)}}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.no-underline{text-decoration-line:none}.underline{text-decoration-line:underline}.decoration-\[\#0069FE\]\/30{text-decoration-color:oklab(56.8276% -.0396384 -.232806/.3)}.underline-offset-2{text-underline-offset:2px}.accent-emerald-500{accent-color:var(--color-emerald-500)}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-75{opacity:.75}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.backdrop-blur-md{--tw-backdrop-blur:blur(var(--blur-md));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[width\]{transition-property:width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-100{--tw-duration:.1s;transition-duration:.1s}.duration-150{--tw-duration:.15s;transition-duration:.15s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.will-change-transform{will-change:transform}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}.\[counter-increment\:line_0\]{counter-increment:line 0}.\[counter-reset\:line\]{counter-reset:line}@media (hover:hover){.group-hover\:block:is(:where(.group):hover *){display:block}.group-hover\:text-white\/60:is(:where(.group):hover *){color:#fff9}@supports (color:color-mix(in lab, red, red)){.group-hover\:text-white\/60:is(:where(.group):hover *){color:color-mix(in oklab, var(--color-white) 60%, transparent)}}.group-hover\:opacity-100:is(:where(.group):hover *),.group-hover\/img\:opacity-100:is(:where(.group\/img):hover *){opacity:1}}.placeholder\:text-gray-400::placeholder{color:var(--color-gray-400)}.placeholder\:text-muted-foreground\/40::placeholder{color:oklab(68.2953% 2.98023e-8 5.96046e-8/.4)}.placeholder\:text-white\/20::placeholder{color:#fff3}@supports (color:color-mix(in lab, red, red)){.placeholder\:text-white\/20::placeholder{color:color-mix(in oklab, var(--color-white) 20%, transparent)}}.before\:mr-4:before{content:var(--tw-content);margin-right:calc(var(--spacing) * 4)}.before\:inline-block:before{content:var(--tw-content);display:inline-block}.before\:w-6:before{content:var(--tw-content);width:calc(var(--spacing) * 6)}.before\:text-right:before{content:var(--tw-content);text-align:right}.before\:font-mono:before{content:var(--tw-content);font-family:var(--font-mono)}.before\:text-\[13px\]:before{content:var(--tw-content);font-size:13px}.before\:text-muted-foreground\/50:before{content:var(--tw-content);color:oklab(68.2953% 2.98023e-8 5.96046e-8/.5)}.before\:content-\[counter\(line\)\]:before{--tw-content:counter(line);content:var(--tw-content)}.before\:select-none:before{content:var(--tw-content);-webkit-user-select:none;user-select:none}.before\:\[counter-increment\:line\]:before{content:var(--tw-content);counter-increment:line}@media (hover:hover){.hover\:border-white\/10:hover{border-color:#ffffff1a}@supports (color:color-mix(in lab, red, red)){.hover\:border-white\/10:hover{border-color:color-mix(in oklab, var(--color-white) 10%, transparent)}}.hover\:border-white\/15:hover{border-color:#ffffff26}@supports (color:color-mix(in lab, red, red)){.hover\:border-white\/15:hover{border-color:color-mix(in oklab, var(--color-white) 15%, transparent)}}.hover\:bg-\[\#00CAFF\]\/15:hover{background-color:oklab(78.0899% -.104231 -.105835/.15)}.hover\:bg-\[\#25D366\]\/15:hover{background-color:oklab(76.0953% -.174012 .10152/.15)}.hover\:bg-\[\#0069FE\]\/90:hover{background-color:oklab(56.8276% -.0396384 -.232806/.9)}.hover\:bg-\[\#0069FE\]\/\[0\.16\]:hover{background-color:oklab(56.8276% -.0396384 -.232806/.16)}.hover\:bg-amber-500:hover{background-color:var(--color-amber-500)}.hover\:bg-background:hover{background-color:#1a1a1a}.hover\:bg-black\/80:hover{background-color:#000c}@supports (color:color-mix(in lab, red, red)){.hover\:bg-black\/80:hover{background-color:color-mix(in oklab, var(--color-black) 80%, transparent)}}.hover\:bg-destructive\/20:hover{background-color:oklab(65.3498% .191597 .0514832/.2)}.hover\:bg-destructive\/90:hover{background-color:oklab(65.3498% .191597 .0514832/.9)}.hover\:bg-gray-100:hover{background-color:var(--color-gray-100)}.hover\:bg-muted:hover{background-color:#272727}.hover\:bg-muted\/40:hover{background-color:oklab(27.2741% 7.45058e-8 0/.4)}.hover\:bg-primary\/20:hover{background-color:oklab(56.8276% -.0396384 -.232806/.2)}.hover\:bg-primary\/90:hover{background-color:oklab(56.8276% -.0396384 -.232806/.9)}.hover\:bg-red-500\/20:hover{background-color:#fb2c3633}@supports (color:color-mix(in lab, red, red)){.hover\:bg-red-500\/20:hover{background-color:color-mix(in oklab, var(--color-red-500) 20%, transparent)}}.hover\:bg-white\/20:hover{background-color:#fff3}@supports (color:color-mix(in lab, red, red)){.hover\:bg-white\/20:hover{background-color:color-mix(in oklab, var(--color-white) 20%, transparent)}}.hover\:bg-white\/30:hover{background-color:#ffffff4d}@supports (color:color-mix(in lab, red, red)){.hover\:bg-white\/30:hover{background-color:color-mix(in oklab, var(--color-white) 30%, transparent)}}.hover\:bg-white\/\[0\.1\]:hover{background-color:#ffffff1a}@supports (color:color-mix(in lab, red, red)){.hover\:bg-white\/\[0\.1\]:hover{background-color:color-mix(in oklab, var(--color-white) 10%, transparent)}}.hover\:bg-white\/\[0\.02\]:hover{background-color:#ffffff05}@supports (color:color-mix(in lab, red, red)){.hover\:bg-white\/\[0\.02\]:hover{background-color:color-mix(in oklab, var(--color-white) 2%, transparent)}}.hover\:bg-white\/\[0\.04\]:hover{background-color:#ffffff0a}@supports (color:color-mix(in lab, red, red)){.hover\:bg-white\/\[0\.04\]:hover{background-color:color-mix(in oklab, var(--color-white) 4%, transparent)}}.hover\:bg-white\/\[0\.05\]:hover{background-color:#ffffff0d}@supports (color:color-mix(in lab, red, red)){.hover\:bg-white\/\[0\.05\]:hover{background-color:color-mix(in oklab, var(--color-white) 5%, transparent)}}.hover\:bg-white\/\[0\.06\]:hover{background-color:#ffffff0f}@supports (color:color-mix(in lab, red, red)){.hover\:bg-white\/\[0\.06\]:hover{background-color:color-mix(in oklab, var(--color-white) 6%, transparent)}}.hover\:bg-white\/\[0\.07\]:hover{background-color:#ffffff12}@supports (color:color-mix(in lab, red, red)){.hover\:bg-white\/\[0\.07\]:hover{background-color:color-mix(in oklab, var(--color-white) 7.0%, transparent)}}.hover\:bg-white\/\[0\.08\]:hover{background-color:#ffffff14}@supports (color:color-mix(in lab, red, red)){.hover\:bg-white\/\[0\.08\]:hover{background-color:color-mix(in oklab, var(--color-white) 8%, transparent)}}.hover\:text-\[\#3391FF\]:hover{color:#3391ff}.hover\:text-foreground:hover{color:#ebebeb}.hover\:text-gray-600:hover{color:var(--color-gray-600)}.hover\:text-muted-foreground:hover{color:#999}.hover\:text-muted-foreground\/70:hover{color:oklab(68.2953% 2.98023e-8 5.96046e-8/.7)}.hover\:text-white:hover{color:var(--color-white)}.hover\:text-white\/40:hover{color:#fff6}@supports (color:color-mix(in lab, red, red)){.hover\:text-white\/40:hover{color:color-mix(in oklab, var(--color-white) 40%, transparent)}}.hover\:text-white\/50:hover{color:#ffffff80}@supports (color:color-mix(in lab, red, red)){.hover\:text-white\/50:hover{color:color-mix(in oklab, var(--color-white) 50%, transparent)}}.hover\:text-white\/55:hover{color:#ffffff8c}@supports (color:color-mix(in lab, red, red)){.hover\:text-white\/55:hover{color:color-mix(in oklab, var(--color-white) 55%, transparent)}}.hover\:text-white\/60:hover{color:#fff9}@supports (color:color-mix(in lab, red, red)){.hover\:text-white\/60:hover{color:color-mix(in oklab, var(--color-white) 60%, transparent)}}.hover\:text-white\/70:hover{color:#ffffffb3}@supports (color:color-mix(in lab, red, red)){.hover\:text-white\/70:hover{color:color-mix(in oklab, var(--color-white) 70%, transparent)}}.hover\:text-white\/80:hover{color:#fffc}@supports (color:color-mix(in lab, red, red)){.hover\:text-white\/80:hover{color:color-mix(in oklab, var(--color-white) 80%, transparent)}}.hover\:text-white\/90:hover{color:#ffffffe6}@supports (color:color-mix(in lab, red, red)){.hover\:text-white\/90:hover{color:color-mix(in oklab, var(--color-white) 90%, transparent)}}.hover\:decoration-\[\#0069FE\]:hover{text-decoration-color:#0069fe}.hover\:opacity-80:hover{opacity:.8}.hover\:opacity-90:hover{opacity:.9}}.focus\:border-\[\#0069FE\]\/30:focus{border-color:oklab(56.8276% -.0396384 -.232806/.3)}.focus\:border-primary\/50:focus{border-color:oklab(56.8276% -.0396384 -.232806/.5)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-primary\/30:focus{--tw-ring-color:oklab(56.8276% -.0396384 -.232806/.3)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}@supports ((-webkit-backdrop-filter:var(--tw)) or (backdrop-filter:var(--tw))){.supports-\[backdrop-filter\]\:bg-background\/70{background-color:oklab(21.7787% -7.45058e-9 0/.7)}.supports-\[backdrop-filter\]\:bg-sidebar\/70{background-color:oklab(25.1965% -7.45058e-9 0/.7)}.supports-\[backdrop-filter\]\:backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.supports-\[backdrop-filter\]\:backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}}@media (width>=40rem){.sm\:hidden{display:none}.sm\:inline{display:inline}.sm\:items-center{align-items:center}}.dark\:bg-\[var\(--shiki-dark-bg\,var\(--sdm-tbg\)\)\]:is(.dark *){background-color:var(--shiki-dark-bg,var(--sdm-tbg))}.dark\:text-\[var\(--shiki-dark\,var\(--sdm-c\,inherit\)\)\]:is(.dark *){color:var(--shiki-dark,var(--sdm-c,inherit))}.\[\&_svg\]\:h-auto svg{height:auto}.\[\&_svg\]\:w-auto svg{width:auto}.\[\&_thead\]\:sticky thead{position:sticky}.\[\&_thead\]\:top-0 thead{top:calc(var(--spacing) * 0)}.\[\&_thead\]\:z-10 thead{z-index:10}.\[\&\>\*\:first-child\]\:mt-0>:first-child{margin-top:calc(var(--spacing) * 0)}.\[\&\>\*\:last-child\]\:mb-0>:last-child{margin-bottom:calc(var(--spacing) * 0)}.\[\&\>\*\:last-child\]\:after\:inline>:last-child:after{content:var(--tw-content);display:inline}.\[\&\>\*\:last-child\]\:after\:align-baseline>:last-child:after{content:var(--tw-content);vertical-align:baseline}.\[\&\>\*\:last-child\]\:after\:content-\[var\(--streamdown-caret\)\]>:last-child:after{--tw-content:var(--streamdown-caret);content:var(--tw-content)}.\[\&\>p\]\:inline>p{display:inline}li .\[li_\&\]\:pl-6{padding-left:calc(var(--spacing) * 6)}}html{touch-action:manipulation;-ms-touch-action:manipulation}body{background-color:var(--color-background);color:var(--color-foreground);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;overscroll-behavior:none}::selection{background-color:#0069fe40}::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:#333;border-radius:3px}::-webkit-scrollbar-thumb:hover{background:#444}.text-gradient{color:#0000;-webkit-text-fill-color:transparent;background-image:linear-gradient(135deg,#0166ff,#009afe,#4aeeff);-webkit-background-clip:text;background-clip:text}.bg-gradient-brand{background-image:linear-gradient(135deg,#0166ff,#009afe,#4aeeff)}.glow-border{box-shadow:0 0 0 1px #0069fe1a,0 0 20px -5px #0069fe26}.animated-border{position:relative;overflow:hidden}.animated-border:before{content:"";background:conic-gradient(#0166ff,#009afe,#4aeeff,#0166ff);animation:3s linear infinite border-spin;position:absolute;inset:-150%}.animated-border>*{z-index:1;position:relative}.animated-border-slow:before{animation-duration:5s}.input-glow:focus{border-color:#0069fe66;box-shadow:0 0 0 1px #0069fe26,0 0 20px -5px #0069fe40,0 0 4px -1px #4aeeff1a}@keyframes border-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes mic-pulse-scale{0%,to{transform:scale(1.1)translateY(-6px)}50%{transform:scale(1.15)translateY(-8px)}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@keyframes spin{to{transform:rotate(360deg)}}@keyframes ping{75%,to{opacity:0;transform:scale(2)}}@keyframes pulse{50%{opacity:.5}}@keyframes bounce{0%,to{animation-timing-function:cubic-bezier(.8,0,1,1);transform:translateY(-25%)}50%{animation-timing-function:cubic-bezier(0,0,.2,1);transform:none}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as e,r as t,t as n}from"./jsx-runtime-C0W9Wf2W.js";import{n as r,r as i,t as a}from"./bloby-
|
|
1
|
+
import{c as e,r as t,t as n}from"./jsx-runtime-C0W9Wf2W.js";import{n as r,r as i,t as a}from"./bloby-C0cl8nq4.js";var o=e(t(),1),s=n(),c=({code:e,language:t,raw:n,className:c,startLine:l,lineNumbers:u,...d})=>{let{shikiTheme:f}=(0,o.useContext)(i),p=r(),[m,h]=(0,o.useState)(n);return(0,o.useEffect)(()=>{if(!p){h(n);return}let r=p.highlight({code:e,language:t,themes:f},e=>{h(e)});r&&h(r)},[e,t,f,p,n]),(0,s.jsx)(a,{className:c,language:t,lineNumbers:u,result:m,startLine:l,...d})};export{c as HighlightedCodeBlockBody};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{i as e}from"./bloby-C0cl8nq4.js";export{e as Mermaid};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as e,r as t,t as n}from"./jsx-runtime-C0W9Wf2W.js";import{h as r,t as i}from"./globals-
|
|
1
|
+
import{c as e,r as t,t as n}from"./jsx-runtime-C0W9Wf2W.js";import{h as r,t as i}from"./globals-DSmE2rZO.js";var a=e(t(),1),o=e(r(),1),s=n();function c(){return(0,s.jsx)(i,{onComplete:()=>{window.parent?.postMessage({type:`bloby:onboard-complete`},`*`)},isInitialSetup:!0})}o.createRoot(document.getElementById(`root`)).render((0,s.jsx)(a.StrictMode,{children:(0,s.jsx)(c,{})}));
|
package/dist-bloby/bloby.html
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, interactive-widget=resizes-content" />
|
|
6
6
|
<title>Bloby Chat</title>
|
|
7
|
-
<script type="module" crossorigin src="/bloby/assets/bloby-
|
|
7
|
+
<script type="module" crossorigin src="/bloby/assets/bloby-C0cl8nq4.js"></script>
|
|
8
8
|
<link rel="modulepreload" crossorigin href="/bloby/assets/jsx-runtime-C0W9Wf2W.js">
|
|
9
|
-
<link rel="modulepreload" crossorigin href="/bloby/assets/globals-
|
|
10
|
-
<link rel="stylesheet" crossorigin href="/bloby/assets/globals-
|
|
9
|
+
<link rel="modulepreload" crossorigin href="/bloby/assets/globals-DSmE2rZO.js">
|
|
10
|
+
<link rel="stylesheet" crossorigin href="/bloby/assets/globals-BqjrOUer.css">
|
|
11
11
|
<link rel="stylesheet" crossorigin href="/bloby/assets/bloby-DkK0ymA2.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body class="bg-background text-foreground">
|
package/dist-bloby/onboard.html
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, interactive-widget=resizes-content" />
|
|
6
6
|
<title>Bloby Setup</title>
|
|
7
|
-
<script type="module" crossorigin src="/bloby/assets/onboard-
|
|
7
|
+
<script type="module" crossorigin src="/bloby/assets/onboard-CeuzZ0Ku.js"></script>
|
|
8
8
|
<link rel="modulepreload" crossorigin href="/bloby/assets/jsx-runtime-C0W9Wf2W.js">
|
|
9
|
-
<link rel="modulepreload" crossorigin href="/bloby/assets/globals-
|
|
10
|
-
<link rel="stylesheet" crossorigin href="/bloby/assets/globals-
|
|
9
|
+
<link rel="modulepreload" crossorigin href="/bloby/assets/globals-DSmE2rZO.js">
|
|
10
|
+
<link rel="stylesheet" crossorigin href="/bloby/assets/globals-BqjrOUer.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body class="bg-background text-foreground">
|
|
13
13
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bloby-bot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.55.0",
|
|
4
4
|
"releaseNotes": [
|
|
5
|
-
"1.
|
|
6
|
-
"2.
|
|
7
|
-
"3.
|
|
8
|
-
"4. "
|
|
5
|
+
"1. Fix: image (and audio) attachments now render in chat again — /api/files is fetched with the auth token instead of a raw <img> src that 401'd after the endpoint hardening",
|
|
6
|
+
"2. Affects chat thumbnails, the image lightbox, voice-note playback, and agent image cards",
|
|
7
|
+
"3. Chat now renders <morphy_action> Mac actions as a clean \"Agent actions: Spotlight at screen N\" chip instead of the raw tag"
|
|
9
8
|
],
|
|
10
9
|
"description": "Self-hosted, self-evolving AI agent with its own dashboard.",
|
|
11
10
|
"type": "module",
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
2
2
|
import { Play, Pause } from 'lucide-react';
|
|
3
|
+
import { useAuthedFileUrl } from '../../lib/authedFile';
|
|
3
4
|
|
|
4
5
|
interface Props {
|
|
5
|
-
audioData: string; // base64 data URL (data:audio/webm;base64,...)
|
|
6
|
+
audioData: string; // base64 data URL (data:audio/webm;base64,...) OR an /api/files/* path
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
function formatDuration(s: number): string {
|
|
@@ -19,9 +20,15 @@ export default function AudioBubble({ audioData }: Props) {
|
|
|
19
20
|
const audioRef = useRef<HTMLAudioElement | null>(null);
|
|
20
21
|
const barRef = useRef<HTMLDivElement>(null);
|
|
21
22
|
|
|
22
|
-
//
|
|
23
|
+
// Historical audio is stored as an /api/files/* path, which a native Audio element
|
|
24
|
+
// can't fetch (the Bearer token can't ride on the request) — resolve it to a blob URL
|
|
25
|
+
// fetched with auth. data: URLs (freshly-recorded clips) pass straight through.
|
|
26
|
+
const resolvedAudioUrl = useAuthedFileUrl(audioData);
|
|
27
|
+
|
|
28
|
+
// Create Audio element once the source URL is ready
|
|
23
29
|
useEffect(() => {
|
|
24
|
-
|
|
30
|
+
if (!resolvedAudioUrl) return;
|
|
31
|
+
const audio = new Audio(resolvedAudioUrl);
|
|
25
32
|
|
|
26
33
|
audio.addEventListener('durationchange', () => {
|
|
27
34
|
// webm often reports Infinity initially — skip until real
|
|
@@ -61,7 +68,7 @@ export default function AudioBubble({ audioData }: Props) {
|
|
|
61
68
|
audio.pause();
|
|
62
69
|
audio.src = '';
|
|
63
70
|
};
|
|
64
|
-
}, [
|
|
71
|
+
}, [resolvedAudioUrl]);
|
|
65
72
|
|
|
66
73
|
const togglePlay = useCallback(() => {
|
|
67
74
|
const audio = audioRef.current;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useAuthedFileUrl } from '../../lib/authedFile';
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
src: string;
|
|
5
|
+
alt?: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
onClick?: () => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* An `<img>` for `/api/files/*` attachments. The file is fetched with the auth token
|
|
12
|
+
* (see `useAuthedFileUrl`) and rendered from a blob URL, because a native `<img src>`
|
|
13
|
+
* request can't carry the Bearer token that `/api/files` now requires. While the fetch
|
|
14
|
+
* is in flight (or if it failed) a subtle pulsing placeholder is shown in its place so
|
|
15
|
+
* the layout doesn't jump.
|
|
16
|
+
*/
|
|
17
|
+
export default function AuthedImage({ src, alt, className, onClick }: Props) {
|
|
18
|
+
const resolvedSrc = useAuthedFileUrl(src);
|
|
19
|
+
|
|
20
|
+
if (!resolvedSrc) {
|
|
21
|
+
return <div className={`${className ?? ''} bg-white/10 animate-pulse`} onClick={onClick} />;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return <img src={resolvedSrc} alt={alt} className={className} onClick={onClick} />;
|
|
25
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
2
|
import { Download, ImageOff } from 'lucide-react';
|
|
3
|
+
import { authFetch } from '../../lib/auth';
|
|
4
|
+
import { useAuthedFileUrl } from '../../lib/authedFile';
|
|
3
5
|
|
|
4
6
|
interface Props {
|
|
5
7
|
src: string;
|
|
@@ -13,10 +15,14 @@ function getFilename(src: string): string {
|
|
|
13
15
|
|
|
14
16
|
export default function BlobyImageCard({ src, alt }: Props) {
|
|
15
17
|
const [failed, setFailed] = useState(false);
|
|
18
|
+
// `src` may be a same-origin /api/files/* path (needs the auth token, which a native
|
|
19
|
+
// <img> can't send) or an external URL — useAuthedFileUrl only fetches+authes the
|
|
20
|
+
// former and passes external URLs through untouched (so the token never leaves origin).
|
|
21
|
+
const resolvedSrc = useAuthedFileUrl(src);
|
|
16
22
|
|
|
17
23
|
const handleDownload = async () => {
|
|
18
24
|
try {
|
|
19
|
-
const res = await fetch(src);
|
|
25
|
+
const res = src.startsWith('/api/files/') ? await authFetch(src) : await fetch(src);
|
|
20
26
|
const blob = await res.blob();
|
|
21
27
|
const url = URL.createObjectURL(blob);
|
|
22
28
|
const a = document.createElement('a');
|
|
@@ -42,13 +48,17 @@ export default function BlobyImageCard({ src, alt }: Props) {
|
|
|
42
48
|
|
|
43
49
|
return (
|
|
44
50
|
<div className="relative group/img my-2 rounded-xl overflow-hidden border border-border/30 bg-black/20 w-fit max-w-full">
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
{resolvedSrc ? (
|
|
52
|
+
<img
|
|
53
|
+
src={resolvedSrc}
|
|
54
|
+
alt={alt || 'Generated image'}
|
|
55
|
+
className="max-w-full max-h-80 object-contain"
|
|
56
|
+
loading="lazy"
|
|
57
|
+
onError={() => setFailed(true)}
|
|
58
|
+
/>
|
|
59
|
+
) : (
|
|
60
|
+
<div className="h-40 w-40 bg-white/10 animate-pulse" />
|
|
61
|
+
)}
|
|
52
62
|
<div className="absolute top-2 right-2 flex gap-1.5 opacity-0 group-hover/img:opacity-100 transition-opacity">
|
|
53
63
|
<button
|
|
54
64
|
onClick={handleDownload}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { useCallback, useEffect } from 'react';
|
|
2
2
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
3
3
|
import { ChevronLeft, ChevronRight, X, Download } from 'lucide-react';
|
|
4
|
+
import { authFetch } from '../../lib/auth';
|
|
5
|
+
import { useAuthedFileUrl } from '../../lib/authedFile';
|
|
4
6
|
|
|
5
7
|
interface Props {
|
|
6
8
|
images: string[];
|
|
@@ -18,6 +20,10 @@ export default function ImageLightbox({ images, index, onClose, onNavigate }: Pr
|
|
|
18
20
|
if (index < images.length - 1) onNavigate(index + 1);
|
|
19
21
|
}, [index, images.length, onNavigate]);
|
|
20
22
|
|
|
23
|
+
// /api/files/* needs the auth token, which a native <img src> can't send — resolve
|
|
24
|
+
// the currently-shown image to a blob URL fetched with the Authorization header.
|
|
25
|
+
const resolvedSrc = useAuthedFileUrl(images[index]);
|
|
26
|
+
|
|
21
27
|
useEffect(() => {
|
|
22
28
|
const handleKey = (e: KeyboardEvent) => {
|
|
23
29
|
if (e.key === 'Escape') onClose();
|
|
@@ -44,7 +50,7 @@ export default function ImageLightbox({ images, index, onClose, onNavigate }: Pr
|
|
|
44
50
|
onClick={async (e) => {
|
|
45
51
|
e.stopPropagation();
|
|
46
52
|
try {
|
|
47
|
-
const res = await
|
|
53
|
+
const res = await authFetch(images[index]);
|
|
48
54
|
const blob = await res.blob();
|
|
49
55
|
const url = URL.createObjectURL(blob);
|
|
50
56
|
const a = document.createElement('a');
|
|
@@ -99,12 +105,19 @@ export default function ImageLightbox({ images, index, onClose, onNavigate }: Pr
|
|
|
99
105
|
)}
|
|
100
106
|
|
|
101
107
|
{/* Image */}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
+
{resolvedSrc ? (
|
|
109
|
+
<img
|
|
110
|
+
src={resolvedSrc}
|
|
111
|
+
alt=""
|
|
112
|
+
className="max-h-[85vh] max-w-[90vw] object-contain rounded-lg"
|
|
113
|
+
onClick={(e) => e.stopPropagation()}
|
|
114
|
+
/>
|
|
115
|
+
) : (
|
|
116
|
+
<div
|
|
117
|
+
className="h-40 w-40 rounded-lg bg-white/10 animate-pulse"
|
|
118
|
+
onClick={(e) => e.stopPropagation()}
|
|
119
|
+
/>
|
|
120
|
+
)}
|
|
108
121
|
</motion.div>
|
|
109
122
|
</AnimatePresence>
|
|
110
123
|
);
|
|
@@ -4,10 +4,12 @@ import { code } from '@streamdown/code';
|
|
|
4
4
|
import 'streamdown/styles.css';
|
|
5
5
|
import { Paperclip, Copy, Check, ExternalLink, Mic, Play, Pause, Laptop, Smartphone, Monitor, Globe, Volume2 } from 'lucide-react';
|
|
6
6
|
import AudioBubble from './AudioBubble';
|
|
7
|
+
import AuthedImage from './AuthedImage';
|
|
7
8
|
import EnvForm, { type EnvGroupData, type EnvField } from './EnvForm';
|
|
8
9
|
import BlobyImageCard from './BlobyImageCard';
|
|
9
10
|
import BlobyTextCard from './BlobyTextCard';
|
|
10
11
|
import NotchCard from './NotchCard';
|
|
12
|
+
import MorphyActionCard from './MorphyActionCard';
|
|
11
13
|
import type { StoredAttachment } from '../../hooks/useChat';
|
|
12
14
|
|
|
13
15
|
interface Props {
|
|
@@ -89,7 +91,7 @@ function preprocessContent(text: string): string {
|
|
|
89
91
|
return out;
|
|
90
92
|
}
|
|
91
93
|
|
|
92
|
-
type ContentSegment = { type: 'text'; value: string } | { type: 'env'; group: EnvGroupData } | { type: 'bloby-image'; src: string; alt: string } | { type: 'bloby-text'; title: string; content: string } | { type: 'notch'; format: 'html' | 'card'; content: string; cardType?: string };
|
|
94
|
+
type ContentSegment = { type: 'text'; value: string } | { type: 'env'; group: EnvGroupData } | { type: 'bloby-image'; src: string; alt: string } | { type: 'bloby-text'; title: string; content: string } | { type: 'notch'; format: 'html' | 'card'; content: string; cardType?: string } | { type: 'morphy-action'; actionType: string; content: string };
|
|
93
95
|
|
|
94
96
|
/** Extract <EnvGroup> and <BlobyImage> tags from content, splitting into typed segments */
|
|
95
97
|
function extractContentSegments(text: string): ContentSegment[] {
|
|
@@ -137,6 +139,13 @@ function extractContentSegments(text: string): ContentSegment[] {
|
|
|
137
139
|
matches.push({ start: match.index, end: match.index + match[0].length, segment: { type: 'notch', format: 'card', content: match[2].trim(), cardType: match[1] } });
|
|
138
140
|
}
|
|
139
141
|
|
|
142
|
+
// Find <morphy_action type="..."> blocks — Mac screen actions (spotlight/point/…),
|
|
143
|
+
// shown as a compact "Agent actions" chip rather than the raw tag + coordinates.
|
|
144
|
+
const morphyActionRegex = /<morphy_action\s+type="([^"]+)">([\s\S]*?)<\/morphy_action>/gi;
|
|
145
|
+
while ((match = morphyActionRegex.exec(text)) !== null) {
|
|
146
|
+
matches.push({ start: match.index, end: match.index + match[0].length, segment: { type: 'morphy-action', actionType: match[1], content: match[2].trim() } });
|
|
147
|
+
}
|
|
148
|
+
|
|
140
149
|
// Sort by position in text
|
|
141
150
|
matches.sort((a, b) => a.start - b.start);
|
|
142
151
|
|
|
@@ -161,7 +170,7 @@ function extractContentSegments(text: string): ContentSegment[] {
|
|
|
161
170
|
|
|
162
171
|
/** Check if content has any custom tags that need special rendering */
|
|
163
172
|
function hasCustomTags(text: string): boolean {
|
|
164
|
-
return /<EnvGroup\s+title="[^"]+">/i.test(text) || /<BlobyImage\s+src="/i.test(text) || /<BlobyText\s+title="/i.test(text) || /<notch_html>/i.test(text) || /<notch_card\s+type="/i.test(text);
|
|
173
|
+
return /<EnvGroup\s+title="[^"]+">/i.test(text) || /<BlobyImage\s+src="/i.test(text) || /<BlobyText\s+title="/i.test(text) || /<notch_html>/i.test(text) || /<notch_card\s+type="/i.test(text) || /<morphy_action\s+type="/i.test(text);
|
|
165
174
|
}
|
|
166
175
|
|
|
167
176
|
function CopyButton({ text }: { text: string }) {
|
|
@@ -245,7 +254,7 @@ export default function MessageBubble({ role, content, timestamp, hasAttachments
|
|
|
245
254
|
{imageUrls.length > 0 && (
|
|
246
255
|
<div className="flex gap-1.5 flex-wrap mb-2">
|
|
247
256
|
{imageUrls.map((url, i) => (
|
|
248
|
-
<
|
|
257
|
+
<AuthedImage
|
|
249
258
|
key={i}
|
|
250
259
|
src={url}
|
|
251
260
|
alt={imageAtts[i]?.name || 'attachment'}
|
|
@@ -387,6 +396,7 @@ export default function MessageBubble({ role, content, timestamp, hasAttachments
|
|
|
387
396
|
if (seg.type === 'bloby-image') return <BlobyImageCard key={i} src={seg.src} alt={seg.alt} />;
|
|
388
397
|
if (seg.type === 'bloby-text') return <BlobyTextCard key={i} title={seg.title} content={seg.content} />;
|
|
389
398
|
if (seg.type === 'notch') return <NotchCard key={i} format={seg.format} content={seg.content} cardType={seg.cardType} />;
|
|
399
|
+
if (seg.type === 'morphy-action') return <MorphyActionCard key={i} actionType={seg.actionType} content={seg.content} />;
|
|
390
400
|
return null;
|
|
391
401
|
})}
|
|
392
402
|
</div>
|
|
@@ -117,6 +117,9 @@ export default function MessageList({ messages, streaming, streamBuffer, tools,
|
|
|
117
117
|
.replace(/<notch_card\s+type="[^"]*">[\s\S]*?<\/notch_card>/gi, '')
|
|
118
118
|
.replace(/<notch_html>[\s\S]*?<\/notch_html>/gi, '')
|
|
119
119
|
.replace(/<notch_(?:html|card)\b[\s\S]*$/i, '')
|
|
120
|
+
// Same for <morphy_action> Mac screen actions (complete blocks, then a trailing unclosed one)
|
|
121
|
+
.replace(/<morphy_action\s+type="[^"]*">[\s\S]*?<\/morphy_action>/gi, '')
|
|
122
|
+
.replace(/<morphy_action\b[\s\S]*$/i, '')
|
|
120
123
|
.trimEnd()}
|
|
121
124
|
toolName={currentToolName}
|
|
122
125
|
/>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Crosshair, MousePointer2, Sparkles, type LucideIcon } from 'lucide-react';
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
/** The action verb from <morphy_action type="...">, e.g. "spotlight" | "point". */
|
|
5
|
+
actionType: string;
|
|
6
|
+
/** Raw JSON payload inside the tag — parsed here only to surface the screen number. */
|
|
7
|
+
content: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Known Mac action verbs → a friendly label + an icon. Unknown/future verbs fall back
|
|
11
|
+
// to a title-cased label and a generic icon, so new action types still render cleanly.
|
|
12
|
+
const ACTION_PRESENTATION: Record<string, { label: string; icon: LucideIcon }> = {
|
|
13
|
+
spotlight: { label: 'Spotlight', icon: Crosshair },
|
|
14
|
+
point: { label: 'Point', icon: MousePointer2 },
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function titleCase(value: string): string {
|
|
18
|
+
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function parseScreenNumber(rawJson: string): number | null {
|
|
22
|
+
try {
|
|
23
|
+
const data = JSON.parse(rawJson);
|
|
24
|
+
return typeof data?.screen === 'number' ? data.screen : null;
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Compact "Agent actions" chip for a <morphy_action> the agent sent to the Mac
|
|
32
|
+
* (spotlight, point, …). We surface only the action and which screen it ran on —
|
|
33
|
+
* never the raw coordinates — so the chat reads as a clean activity line.
|
|
34
|
+
*/
|
|
35
|
+
export default function MorphyActionCard({ actionType, content }: Props) {
|
|
36
|
+
const presentation = ACTION_PRESENTATION[actionType.toLowerCase()] ?? { label: titleCase(actionType), icon: Sparkles };
|
|
37
|
+
const screenNumber = parseScreenNumber(content);
|
|
38
|
+
const Icon = presentation.icon;
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div className="my-2 inline-flex items-center gap-2 rounded-xl border border-[#0069FE]/25 bg-[#0069FE]/10 px-3 py-1.5">
|
|
42
|
+
<Icon className="h-3.5 w-3.5 text-[#4AA8FF] shrink-0" />
|
|
43
|
+
<span className="text-[13px] text-[#9ecbff]">
|
|
44
|
+
<span className="text-[#9ecbff]/55">Agent actions:</span>{' '}
|
|
45
|
+
<span className="font-medium">{presentation.label}</span>
|
|
46
|
+
{screenNumber !== null && <span className="text-[#9ecbff]/80"> at screen {screenNumber}</span>}
|
|
47
|
+
</span>
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { authFetch } from './auth';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Resolve a same-origin `/api/files/*` path into a blob object URL that was fetched
|
|
6
|
+
* WITH the `Authorization: Bearer <token>` header.
|
|
7
|
+
*
|
|
8
|
+
* Why this exists: `/api/files/*` requires auth (it used to be an unauthenticated GET
|
|
9
|
+
* but was closed off in the "leaky endpoints" hardening). Native `<img>`/`<audio>`
|
|
10
|
+
* elements cannot attach a Bearer token to their `src` request, so a raw
|
|
11
|
+
* `<img src="/api/files/...">` now 401s and the picture/audio never loads. Fetching the
|
|
12
|
+
* file through `authFetch` (token in the header, never in the URL — so no new token-leak
|
|
13
|
+
* surface) and handing back a `blob:` object URL is the secure way to render it.
|
|
14
|
+
*
|
|
15
|
+
* `data:`, `blob:`, and other non-`/api/files` inputs (and `undefined`) pass through
|
|
16
|
+
* unchanged. The created object URL is revoked when the input changes or the component
|
|
17
|
+
* unmounts. Returns `undefined` while the fetch is in flight or if it failed, so callers
|
|
18
|
+
* can show a placeholder.
|
|
19
|
+
*/
|
|
20
|
+
export function useAuthedFileUrl(rawUrl: string | undefined): string | undefined {
|
|
21
|
+
const requiresAuthedFetch = !!rawUrl && rawUrl.startsWith('/api/files/');
|
|
22
|
+
const [resolvedUrl, setResolvedUrl] = useState<string | undefined>(
|
|
23
|
+
requiresAuthedFetch ? undefined : rawUrl,
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
// Pass through anything that isn't a protected file path (data:/blob:/undefined).
|
|
28
|
+
if (!rawUrl || !rawUrl.startsWith('/api/files/')) {
|
|
29
|
+
setResolvedUrl(rawUrl);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let createdObjectUrl: string | null = null;
|
|
34
|
+
let cancelled = false;
|
|
35
|
+
setResolvedUrl(undefined);
|
|
36
|
+
|
|
37
|
+
(async () => {
|
|
38
|
+
try {
|
|
39
|
+
const response = await authFetch(rawUrl);
|
|
40
|
+
if (!response.ok) return; // leave undefined → caller shows a placeholder
|
|
41
|
+
const blob = await response.blob();
|
|
42
|
+
if (cancelled) return;
|
|
43
|
+
createdObjectUrl = URL.createObjectURL(blob);
|
|
44
|
+
setResolvedUrl(createdObjectUrl);
|
|
45
|
+
} catch {
|
|
46
|
+
/* network error — leave undefined so the caller renders its placeholder */
|
|
47
|
+
}
|
|
48
|
+
})();
|
|
49
|
+
|
|
50
|
+
return () => {
|
|
51
|
+
cancelled = true;
|
|
52
|
+
if (createdObjectUrl) URL.revokeObjectURL(createdObjectUrl);
|
|
53
|
+
};
|
|
54
|
+
}, [rawUrl]);
|
|
55
|
+
|
|
56
|
+
return resolvedUrl;
|
|
57
|
+
}
|
package/supervisor/index.ts
CHANGED
|
@@ -120,7 +120,7 @@ const SW_JS = `// Service worker — app-shell caching + push notifications
|
|
|
120
120
|
// cached shell that masks a broken (or just-fixed) frontend and produces the confusing
|
|
121
121
|
// "normal refresh is broken but hard refresh works" split. Cache is a pure offline fallback.
|
|
122
122
|
|
|
123
|
-
var CACHE = 'bloby-
|
|
123
|
+
var CACHE = 'bloby-v19';
|
|
124
124
|
var HASHED_RE = new RegExp('/assets/.+-[a-zA-Z0-9]{6,}[.](js|css)$');
|
|
125
125
|
|
|
126
126
|
// Precache the HTML shell on install so the cache is never empty.
|
|
@@ -130,7 +130,7 @@ The cancel button's bottom-right, Bruno.
|
|
|
130
130
|
</mac_actions>
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
-
**Reply
|
|
133
|
+
**Reply vs proactive.** On a **reply** to a `[Mac]` turn you saw the screenshot, so coordinates are accurate — this is the reliable case. In a **proactive `<mac_push>`** these still work (the app maps your coordinate against a fresh capture of the *current* screen), but you didn't see that screen, so only point/spotlight proactively when you genuinely know where the thing is — otherwise send a card.
|
|
134
134
|
|
|
135
135
|
---
|
|
136
136
|
|
|
@@ -152,7 +152,7 @@ Opt-in and quiet by design:
|
|
|
152
152
|
</mac_push>
|
|
153
153
|
```
|
|
154
154
|
|
|
155
|
-
-
|
|
155
|
+
- **`point`/`spotlight` in a push work, but carefully** — the app maps the coordinate against a fresh capture of the current screen, which you haven't seen. Use them only when you truly know the location; otherwise a spoken line + a `card` (or `<notch_html>`) is the safe choice.
|
|
156
156
|
- **Fire-and-forget, online-only.** The push lands **only if the Mac is connected and the human isn't mid-interaction**; otherwise it's silently dropped (not queued). For must-not-miss updates, also emit a `<Message>` block (web/push) — `<mac_push>` and `<Message>` are independent.
|
|
157
157
|
- **Keep the reply discipline** (below): ≤ 2 sentences, no markdown, never read the card aloud. The human didn't ask, so be especially brief.
|
|
158
158
|
|
|
@@ -251,7 +251,7 @@ The rule is symmetric: if the **voice alone** is the right answer, send **no car
|
|
|
251
251
|
|
|
252
252
|
- ❌ **No long monologues.** Two sentences. If you can't, let the card carry it.
|
|
253
253
|
- ❌ **No reading the card aloud.** Voice + card complement, never duplicate.
|
|
254
|
-
-
|
|
254
|
+
- ⚠️ **Proactive `point`/`spotlight` is mapped against the current screen you can't see** — only use it when you truly know the location, else send a card.
|
|
255
255
|
- ❌ **No external assets** in custom HTML — no network in the notch view.
|
|
256
256
|
- ❌ **No interactive elements** in cards — buttons render but do nothing.
|
|
257
257
|
- ❌ **No light backgrounds** — the pill is black.
|
|
@@ -282,8 +282,8 @@ The rule is symmetric: if the **voice alone** is the right answer, send **no car
|
|
|
282
282
|
| **Action registry** | `<mac_actions>[ { "type": "…", … }, … ]</mac_actions>` — one block, JSON array, runs in order |
|
|
283
283
|
| Action types | `card` (preset), `point`, `spotlight` |
|
|
284
284
|
| `card` | `{ "type":"card", "preset":"…", "data":{…} }` — catalog: [`presets/PRESETS.md`](presets/PRESETS.md) |
|
|
285
|
-
| `point` | `{ "type":"point", "x", "y", "label"?, "screen"? }` — reply
|
|
286
|
-
| `spotlight` | `{ "type":"spotlight", "x","y", "r"?, "label"?, "screen"? }` — reply
|
|
285
|
+
| `point` | `{ "type":"point", "x", "y", "label"?, "screen"? }` — best on a reply; proactive maps to the current screen |
|
|
286
|
+
| `spotlight` | `{ "type":"spotlight", "x","y", "r"?, "label"?, "screen"? }` — best on a reply; proactive maps to the current screen |
|
|
287
287
|
| Custom card (raw) | `<notch_html>…</notch_html>` — raw markup, no escaping |
|
|
288
288
|
| Custom snippet library | [`frequentSnippets/`](frequentSnippets/)`*.html` |
|
|
289
289
|
| Proactive push | wrap payload in `<mac_push>…</mac_push>` (cards only, no point/spotlight) |
|