bloby-bot 0.51.5 → 0.52.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-vi0Xitb-.js → bloby-CjvuL1QI.js} +77 -77
- package/dist-bloby/assets/{globals-DNO3ilRx.js → globals-UaNdQXf5.js} +3 -3
- package/dist-bloby/assets/globals-ZdFBsH0Q.css +2 -0
- package/dist-bloby/assets/{highlighted-body-OFNGDK62-DMeCY5Rc.js → highlighted-body-OFNGDK62-D0QQRXpE.js} +1 -1
- package/dist-bloby/assets/mermaid-GHXKKRXX-D9GshF2B.js +1 -0
- package/dist-bloby/assets/{onboard-D8sRPjz2.js → onboard-DU3OfA5h.js} +1 -1
- package/dist-bloby/bloby.html +3 -3
- package/dist-bloby/onboard.html +3 -3
- package/package.json +5 -3
- package/supervisor/chat/bloby-main.tsx +40 -7
- package/supervisor/chat/src/components/Chat/MessageBubble.tsx +16 -2
- package/supervisor/chat/src/components/Chat/MessageList.tsx +7 -1
- package/supervisor/chat/src/components/Chat/NotchCard.tsx +70 -0
- package/supervisor/harnesses/claude.ts +31 -1
- package/supervisor/harnesses/codex.ts +15 -1
- package/supervisor/index.ts +31 -2
- package/worker/prompts/bloby-system-prompt.txt +1 -1
- package/workspace/skills/mac/SKILL.md +102 -22
- package/workspace/skills/mac/presets/PRESETS.md +226 -0
- package/dist-bloby/assets/globals-D60b-8LY.css +0 -2
- package/dist-bloby/assets/mermaid-GHXKKRXX-BOqNyL14.js +0 -1
|
@@ -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-\[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-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-\[\#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-CjvuL1QI.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-CjvuL1QI.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-UaNdQXf5.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-CjvuL1QI.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-UaNdQXf5.js">
|
|
10
|
+
<link rel="stylesheet" crossorigin href="/bloby/assets/globals-ZdFBsH0Q.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-DU3OfA5h.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-UaNdQXf5.js">
|
|
10
|
+
<link rel="stylesheet" crossorigin href="/bloby/assets/globals-ZdFBsH0Q.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body class="bg-background text-foreground">
|
|
13
13
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bloby-bot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.52.0",
|
|
4
4
|
"releaseNotes": [
|
|
5
5
|
"1. New Morphy animation system: config-driven sprites loaded from /morphy/*.json",
|
|
6
6
|
"2. Swapped teleporting (splash) and headphones (bubble + chat) to the new format",
|
|
@@ -53,9 +53,11 @@
|
|
|
53
53
|
"sync:pi-models": "tsx scripts/sync-pi-models.ts"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@anthropic-ai/claude-agent-sdk": "^0.
|
|
56
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.154",
|
|
57
|
+
"@anthropic-ai/sdk": "^0.100.0",
|
|
57
58
|
"@clack/prompts": "^1.1.0",
|
|
58
|
-
"@
|
|
59
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
60
|
+
"@openai/codex": "^0.135.0",
|
|
59
61
|
"@streamdown/code": "^1.1.1",
|
|
60
62
|
"@tailwindcss/vite": "^4.2.0",
|
|
61
63
|
"@vitejs/plugin-react": "^6.0.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from 'react';
|
|
2
2
|
import ReactDOM from 'react-dom/client';
|
|
3
|
-
import { ArrowLeft, EllipsisVertical, WandSparkles, Download, X, Share, Bell, BellRing, BellOff } from 'lucide-react';
|
|
3
|
+
import { ArrowLeft, EllipsisVertical, WandSparkles, Download, X, Share, Bell, BellRing, BellOff, MessageSquarePlus } from 'lucide-react';
|
|
4
4
|
import { WsClient } from './src/lib/ws-client';
|
|
5
5
|
import { useBlobyChat } from './src/hooks/useBlobyChat';
|
|
6
6
|
import OnboardWizard from './OnboardWizard';
|
|
@@ -17,6 +17,7 @@ function BlobyApp() {
|
|
|
17
17
|
const [botName, setBotName] = useState('Bloby');
|
|
18
18
|
const [whisperEnabled, setWhisperEnabled] = useState(false);
|
|
19
19
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
20
|
+
const [confirmReset, setConfirmReset] = useState(false);
|
|
20
21
|
const [showWizard, setShowWizard] = useState(false);
|
|
21
22
|
const [reloadTrigger, setReloadTrigger] = useState(0);
|
|
22
23
|
const menuRef = useRef<HTMLDivElement>(null);
|
|
@@ -288,7 +289,7 @@ function BlobyApp() {
|
|
|
288
289
|
useEffect(() => {
|
|
289
290
|
if (!menuOpen) return;
|
|
290
291
|
const handler = (e: MouseEvent) => {
|
|
291
|
-
if (menuRef.current && !menuRef.current.contains(e.target as Node)) setMenuOpen(false);
|
|
292
|
+
if (menuRef.current && !menuRef.current.contains(e.target as Node)) { setMenuOpen(false); setConfirmReset(false); }
|
|
292
293
|
};
|
|
293
294
|
document.addEventListener('mousedown', handler);
|
|
294
295
|
return () => document.removeEventListener('mousedown', handler);
|
|
@@ -358,8 +359,8 @@ function BlobyApp() {
|
|
|
358
359
|
<ArrowLeft className="h-[18px] w-[18px]" />
|
|
359
360
|
</button>
|
|
360
361
|
|
|
361
|
-
{/* Mascot / headphones animation */}
|
|
362
|
-
<div className="relative ml-1.5 shrink-0">
|
|
362
|
+
{/* Mascot / headphones animation (nudged up 5px so it sits visually centered with the name) */}
|
|
363
|
+
<div className="relative ml-1.5 shrink-0 -translate-y-[5px]">
|
|
363
364
|
<HeadphonesAnimation recording={chatRecording} height={36} />
|
|
364
365
|
</div>
|
|
365
366
|
|
|
@@ -462,24 +463,56 @@ function BlobyApp() {
|
|
|
462
463
|
)}
|
|
463
464
|
<div className="relative" ref={menuRef}>
|
|
464
465
|
<button
|
|
465
|
-
onClick={() => setMenuOpen((v) => !v)}
|
|
466
|
+
onClick={() => setMenuOpen((v) => { const next = !v; if (!next) setConfirmReset(false); return next; })}
|
|
466
467
|
className="flex items-center justify-center h-8 w-8 rounded-full text-muted-foreground hover:text-foreground hover:bg-white/[0.06] transition-colors"
|
|
467
468
|
>
|
|
468
469
|
<EllipsisVertical className="h-[18px] w-[18px]" />
|
|
469
470
|
</button>
|
|
470
471
|
{menuOpen && (
|
|
471
|
-
<div className="absolute right-0 top-full mt-1.5 min-w-[
|
|
472
|
+
<div className="absolute right-0 top-full mt-1.5 min-w-[200px] rounded-xl border border-white/[0.06] bg-popover py-1.5 shadow-xl z-50">
|
|
472
473
|
<button
|
|
473
|
-
onClick={() => { setShowWizard(true); setMenuOpen(false); }}
|
|
474
|
+
onClick={() => { setShowWizard(true); setMenuOpen(false); setConfirmReset(false); }}
|
|
474
475
|
className="flex w-full items-center gap-2.5 px-3.5 py-2 text-sm text-muted-foreground hover:text-foreground hover:bg-white/[0.06] transition-colors"
|
|
475
476
|
>
|
|
476
477
|
<WandSparkles className="h-4 w-4" />
|
|
477
478
|
Settings
|
|
478
479
|
</button>
|
|
480
|
+
{/* New conversation — resets the live agent session so heavy/long chats don't hit the context wall.
|
|
481
|
+
Non-destructive: past messages stay saved under the old conversation; this just starts a fresh one. */}
|
|
482
|
+
{!confirmReset ? (
|
|
483
|
+
<button
|
|
484
|
+
onClick={() => setConfirmReset(true)}
|
|
485
|
+
className="flex w-full items-center gap-2.5 px-3.5 py-2 text-sm text-muted-foreground hover:text-foreground hover:bg-white/[0.06] transition-colors"
|
|
486
|
+
>
|
|
487
|
+
<MessageSquarePlus className="h-4 w-4" />
|
|
488
|
+
New conversation
|
|
489
|
+
</button>
|
|
490
|
+
) : (
|
|
491
|
+
<div className="px-3.5 py-2">
|
|
492
|
+
<p className="text-[12px] text-muted-foreground/70 mb-2 leading-snug">
|
|
493
|
+
Start fresh? This clears the agent's context — your past messages stay saved.
|
|
494
|
+
</p>
|
|
495
|
+
<div className="flex gap-2">
|
|
496
|
+
<button
|
|
497
|
+
onClick={() => { clearContext(); setConfirmReset(false); setMenuOpen(false); }}
|
|
498
|
+
className="flex-1 text-[12px] font-medium text-white bg-[#0069FE] hover:bg-[#0069FE]/90 px-2.5 py-1.5 rounded-lg transition-colors"
|
|
499
|
+
>
|
|
500
|
+
New chat
|
|
501
|
+
</button>
|
|
502
|
+
<button
|
|
503
|
+
onClick={() => setConfirmReset(false)}
|
|
504
|
+
className="flex-1 text-[12px] font-medium text-muted-foreground bg-white/[0.06] hover:bg-white/[0.1] px-2.5 py-1.5 rounded-lg transition-colors"
|
|
505
|
+
>
|
|
506
|
+
Cancel
|
|
507
|
+
</button>
|
|
508
|
+
</div>
|
|
509
|
+
</div>
|
|
510
|
+
)}
|
|
479
511
|
{isMobile && !isStandalone && (
|
|
480
512
|
<button
|
|
481
513
|
onClick={() => {
|
|
482
514
|
setMenuOpen(false);
|
|
515
|
+
setConfirmReset(false);
|
|
483
516
|
if (isInIframe) {
|
|
484
517
|
window.parent.postMessage({ type: 'bloby:install-app' }, '*');
|
|
485
518
|
} else {
|
|
@@ -7,6 +7,7 @@ import AudioBubble from './AudioBubble';
|
|
|
7
7
|
import EnvForm, { type EnvGroupData, type EnvField } from './EnvForm';
|
|
8
8
|
import BlobyImageCard from './BlobyImageCard';
|
|
9
9
|
import BlobyTextCard from './BlobyTextCard';
|
|
10
|
+
import NotchCard from './NotchCard';
|
|
10
11
|
import type { StoredAttachment } from '../../hooks/useChat';
|
|
11
12
|
|
|
12
13
|
interface Props {
|
|
@@ -88,7 +89,7 @@ function preprocessContent(text: string): string {
|
|
|
88
89
|
return out;
|
|
89
90
|
}
|
|
90
91
|
|
|
91
|
-
type ContentSegment = { type: 'text'; value: string } | { type: 'env'; group: EnvGroupData } | { type: 'bloby-image'; src: string; alt: string } | { type: 'bloby-text'; title: string; content: string };
|
|
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 };
|
|
92
93
|
|
|
93
94
|
/** Extract <EnvGroup> and <BlobyImage> tags from content, splitting into typed segments */
|
|
94
95
|
function extractContentSegments(text: string): ContentSegment[] {
|
|
@@ -124,6 +125,18 @@ function extractContentSegments(text: string): ContentSegment[] {
|
|
|
124
125
|
matches.push({ start: match.index, end: match.index + match[0].length, segment: { type: 'bloby-text', title: match[1], content: match[2].trim() } });
|
|
125
126
|
}
|
|
126
127
|
|
|
128
|
+
// Find <notch_html> blocks — custom Mac-notch cards (rendered as a live preview)
|
|
129
|
+
const notchHtmlRegex = /<notch_html>([\s\S]*?)<\/notch_html>/gi;
|
|
130
|
+
while ((match = notchHtmlRegex.exec(text)) !== null) {
|
|
131
|
+
matches.push({ start: match.index, end: match.index + match[0].length, segment: { type: 'notch', format: 'html', content: match[1].trim() } });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Find <notch_card type="..."> blocks — preset Mac-notch cards (shown as JSON)
|
|
135
|
+
const notchCardRegex = /<notch_card\s+type="([^"]+)">([\s\S]*?)<\/notch_card>/gi;
|
|
136
|
+
while ((match = notchCardRegex.exec(text)) !== null) {
|
|
137
|
+
matches.push({ start: match.index, end: match.index + match[0].length, segment: { type: 'notch', format: 'card', content: match[2].trim(), cardType: match[1] } });
|
|
138
|
+
}
|
|
139
|
+
|
|
127
140
|
// Sort by position in text
|
|
128
141
|
matches.sort((a, b) => a.start - b.start);
|
|
129
142
|
|
|
@@ -148,7 +161,7 @@ function extractContentSegments(text: string): ContentSegment[] {
|
|
|
148
161
|
|
|
149
162
|
/** Check if content has any custom tags that need special rendering */
|
|
150
163
|
function hasCustomTags(text: string): boolean {
|
|
151
|
-
return /<EnvGroup\s+title="[^"]+">/i.test(text) || /<BlobyImage\s+src="/i.test(text) || /<BlobyText\s+title="/i.test(text);
|
|
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);
|
|
152
165
|
}
|
|
153
166
|
|
|
154
167
|
function CopyButton({ text }: { text: string }) {
|
|
@@ -373,6 +386,7 @@ export default function MessageBubble({ role, content, timestamp, hasAttachments
|
|
|
373
386
|
if (seg.type === 'env') return <EnvForm key={i} group={seg.group} />;
|
|
374
387
|
if (seg.type === 'bloby-image') return <BlobyImageCard key={i} src={seg.src} alt={seg.alt} />;
|
|
375
388
|
if (seg.type === 'bloby-text') return <BlobyTextCard key={i} title={seg.title} content={seg.content} />;
|
|
389
|
+
if (seg.type === 'notch') return <NotchCard key={i} format={seg.format} content={seg.content} cardType={seg.cardType} />;
|
|
376
390
|
return null;
|
|
377
391
|
})}
|
|
378
392
|
</div>
|
|
@@ -111,7 +111,13 @@ export default function MessageList({ messages, streaming, streamBuffer, tools,
|
|
|
111
111
|
Strip the leading "[Mac] " / "[Alexa] " / etc. that the agent sometimes echoes. */}
|
|
112
112
|
{streaming && (
|
|
113
113
|
<TypingIndicator
|
|
114
|
-
text={streamBuffer
|
|
114
|
+
text={streamBuffer
|
|
115
|
+
.replace(/^\[(Mac|Alexa|WhatsApp|Chat|PWA|Workspace|workspace)\]\s*/i, '')
|
|
116
|
+
// Hide Mac-notch card markup as it streams (complete blocks, then any trailing unclosed one)
|
|
117
|
+
.replace(/<notch_card\s+type="[^"]*">[\s\S]*?<\/notch_card>/gi, '')
|
|
118
|
+
.replace(/<notch_html>[\s\S]*?<\/notch_html>/gi, '')
|
|
119
|
+
.replace(/<notch_(?:html|card)\b[\s\S]*$/i, '')
|
|
120
|
+
.trimEnd()}
|
|
115
121
|
toolName={currentToolName}
|
|
116
122
|
/>
|
|
117
123
|
)}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { ChevronRight, Laptop } from 'lucide-react';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
/** 'html' → custom <notch_html> markup (rendered as a live preview);
|
|
6
|
+
* 'card' → <notch_card> preset payload (shown as formatted JSON). */
|
|
7
|
+
format: 'html' | 'card';
|
|
8
|
+
content: string;
|
|
9
|
+
/** Preset name for 'card' format, e.g. "email" | "calendar". */
|
|
10
|
+
cardType?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Wrap the agent's raw notch markup in a minimal black document so the preview
|
|
14
|
+
* mirrors what showed on the Mac notch (white text on a transparent/black canvas). */
|
|
15
|
+
function buildSrcDoc(html: string): string {
|
|
16
|
+
return `<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">` +
|
|
17
|
+
`<style>html,body{margin:0;padding:0;background:#000;color:#fff;` +
|
|
18
|
+
`font-family:-apple-system,BlinkMacSystemFont,system-ui,sans-serif;}*{box-sizing:border-box;}</style>` +
|
|
19
|
+
`</head><body>${html}</body></html>`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function prettyJson(raw: string): string {
|
|
23
|
+
try { return JSON.stringify(JSON.parse(raw), null, 2); } catch { return raw.trim(); }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Collapsible "Sent to your Mac" card. The agent emits <notch_html>/<notch_card>
|
|
28
|
+
* blocks that Morphy renders in the MacBook notch — in the chat the user usually
|
|
29
|
+
* doesn't want to see them, so we collapse them behind this card and let them
|
|
30
|
+
* expand to preview exactly what landed on their Mac.
|
|
31
|
+
*/
|
|
32
|
+
export default function NotchCard({ format, content, cardType }: Props) {
|
|
33
|
+
const [expanded, setExpanded] = useState(false);
|
|
34
|
+
const label = cardType ? `Sent to your Mac · ${cardType}` : 'Sent to your Mac';
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<div className="my-2 rounded-xl border border-[#0069FE]/25 overflow-hidden">
|
|
38
|
+
{/* Header */}
|
|
39
|
+
<div
|
|
40
|
+
onClick={() => setExpanded((v) => !v)}
|
|
41
|
+
className="flex items-center gap-2.5 px-3.5 py-2.5 bg-[#0069FE]/10 hover:bg-[#0069FE]/[0.16] transition-colors cursor-pointer select-none"
|
|
42
|
+
>
|
|
43
|
+
<ChevronRight
|
|
44
|
+
className={`h-3.5 w-3.5 text-[#4AA8FF] shrink-0 transition-transform duration-200 ${expanded ? 'rotate-90' : ''}`}
|
|
45
|
+
/>
|
|
46
|
+
<Laptop className="h-4 w-4 text-[#4AA8FF] shrink-0" />
|
|
47
|
+
<span className="text-[13px] font-medium text-[#9ecbff] truncate min-w-0">{label}</span>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
{/* Collapsible content */}
|
|
51
|
+
{expanded && (
|
|
52
|
+
<div className="border-t border-[#0069FE]/15 p-3 bg-black/40">
|
|
53
|
+
{format === 'html' ? (
|
|
54
|
+
<iframe
|
|
55
|
+
title="Mac notch card preview"
|
|
56
|
+
sandbox=""
|
|
57
|
+
srcDoc={buildSrcDoc(content)}
|
|
58
|
+
className="w-full rounded-lg border border-white/10 bg-black block"
|
|
59
|
+
style={{ height: 147 }}
|
|
60
|
+
/>
|
|
61
|
+
) : (
|
|
62
|
+
<pre className="text-[12px] leading-relaxed text-foreground/80 overflow-x-auto whitespace-pre-wrap break-words font-mono max-h-[300px]">
|
|
63
|
+
{prettyJson(content)}
|
|
64
|
+
</pre>
|
|
65
|
+
)}
|
|
66
|
+
</div>
|
|
67
|
+
)}
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -77,6 +77,9 @@ interface LiveConversation {
|
|
|
77
77
|
onMessage: (type: string, data: any) => void;
|
|
78
78
|
/** True while the model is actively processing (between message push and result) */
|
|
79
79
|
busy: boolean;
|
|
80
|
+
/** Messages pushed but not yet completed (1 result per message). Used to know when
|
|
81
|
+
* the session is truly idle — i.e. no queued message — so it's safe to recycle. */
|
|
82
|
+
pendingCount: number;
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
const liveConversations = new Map<string, LiveConversation>();
|
|
@@ -217,6 +220,12 @@ async function buildConversationOptions(
|
|
|
217
220
|
mcpServers,
|
|
218
221
|
agents,
|
|
219
222
|
agentProgressSummaries: true,
|
|
223
|
+
// Auto-compaction: the live conversation is a single long-lived query() whose
|
|
224
|
+
// context grows every turn (messages + tool results + sub-agent transcripts).
|
|
225
|
+
// Enable it explicitly via inline settings so it does NOT depend on filesystem
|
|
226
|
+
// settings.json being present — when context fills, the SDK summarizes older
|
|
227
|
+
// history and continues instead of hitting the hard context wall.
|
|
228
|
+
settings: { autoCompactEnabled: true },
|
|
220
229
|
env: {
|
|
221
230
|
...process.env as Record<string, string>,
|
|
222
231
|
CLAUDE_CODE_OAUTH_TOKEN: oauthToken,
|
|
@@ -297,6 +306,7 @@ export async function startConversation(
|
|
|
297
306
|
queryHandle: null,
|
|
298
307
|
onMessage,
|
|
299
308
|
busy: false,
|
|
309
|
+
pendingCount: 0,
|
|
300
310
|
};
|
|
301
311
|
liveConversations.set(conversationId, conv);
|
|
302
312
|
|
|
@@ -369,7 +379,26 @@ export async function startConversation(
|
|
|
369
379
|
// Signal turn complete — backend restart + UI update
|
|
370
380
|
const FILE_TOOLS = ['Write', 'Edit'];
|
|
371
381
|
const usedFileTools = FILE_TOOLS.some((t) => usedTools.has(t));
|
|
372
|
-
|
|
382
|
+
|
|
383
|
+
// Context-size signal for the orchestrator's proactive session recycling.
|
|
384
|
+
// Prefer modelUsage (carries the per-model contextWindow); fall back to raw usage.
|
|
385
|
+
let contextTokens = 0;
|
|
386
|
+
let contextWindow = 0;
|
|
387
|
+
const modelUsage = (msg as any).modelUsage as Record<string, any> | undefined;
|
|
388
|
+
if (modelUsage) {
|
|
389
|
+
for (const mu of Object.values(modelUsage)) {
|
|
390
|
+
const used = (mu?.inputTokens || 0) + (mu?.cacheReadInputTokens || 0) + (mu?.cacheCreationInputTokens || 0);
|
|
391
|
+
if (used > contextTokens) { contextTokens = used; contextWindow = mu?.contextWindow || 0; }
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (!contextTokens) {
|
|
395
|
+
const u = (msg as any).usage || {};
|
|
396
|
+
contextTokens = (u.input_tokens || 0) + (u.cache_read_input_tokens || 0) + (u.cache_creation_input_tokens || 0);
|
|
397
|
+
}
|
|
398
|
+
// One result per pushed message → decrement; idle when nothing else is queued.
|
|
399
|
+
conv.pendingCount = Math.max(0, (conv.pendingCount || 0) - 1);
|
|
400
|
+
const idle = conv.pendingCount === 0;
|
|
401
|
+
onMessage('bot:turn-complete', { conversationId, usedFileTools, contextTokens, contextWindow, idle });
|
|
373
402
|
|
|
374
403
|
// Reset per-turn state
|
|
375
404
|
usedTools.clear();
|
|
@@ -482,6 +511,7 @@ export function pushMessage(
|
|
|
482
511
|
|
|
483
512
|
const userMessage = buildUserMessage(content, attachments, savedFiles);
|
|
484
513
|
conv.busy = true;
|
|
514
|
+
conv.pendingCount = (conv.pendingCount || 0) + 1;
|
|
485
515
|
conv.inputQueue.push(userMessage);
|
|
486
516
|
|
|
487
517
|
// Emit typing indicator
|
|
@@ -483,7 +483,16 @@ function handleNotification(conv: CodexConversation, n: { method: string; params
|
|
|
483
483
|
conv.onMessage('bot:done', { conversationId: conv.id, usedFileTools: conv.usedFileTools });
|
|
484
484
|
teardownConversation(conv.id);
|
|
485
485
|
} else {
|
|
486
|
-
|
|
486
|
+
// Context-size signal for the orchestrator's proactive session recycling.
|
|
487
|
+
// The codex app-server reports token usage on turn/completed; field names vary
|
|
488
|
+
// across versions, so probe defensively (0 if absent → falls back to codex's
|
|
489
|
+
// own built-in auto-compaction).
|
|
490
|
+
const tu: any = p.turn?.usage || p.usage || {};
|
|
491
|
+
const contextTokens = tu.input_tokens ?? tu.inputTokens ?? tu.total_tokens ?? tu.totalTokens ?? tu.tokens ?? 0;
|
|
492
|
+
const contextWindow = tu.context_window ?? tu.contextWindow ?? 0;
|
|
493
|
+
// idle = no message queued behind this turn (the drain happens just below).
|
|
494
|
+
const idle = conv.pendingInputs.length === 0;
|
|
495
|
+
conv.onMessage('bot:turn-complete', { conversationId: conv.id, usedFileTools: conv.usedFileTools, contextTokens, contextWindow, idle });
|
|
487
496
|
|
|
488
497
|
// Drain any messages that were submitted while we were busy.
|
|
489
498
|
const next = conv.pendingInputs.shift();
|
|
@@ -558,6 +567,11 @@ async function spawnAndInitialize(
|
|
|
558
567
|
log.info(`[codex] init conversation ${conversationId} (model=${modelId}${effort ? `, effort=${effort}` : ''})`);
|
|
559
568
|
await rpc.request('initialize', { clientInfo: CLIENT_INFO });
|
|
560
569
|
rpc.notify('initialized', {});
|
|
570
|
+
// Context auto-compaction is ON by default in the codex app-server: when the
|
|
571
|
+
// thread's token count crosses the model's threshold it compacts history in
|
|
572
|
+
// place (emitting a `contextCompaction` item) and continues — no flag needed
|
|
573
|
+
// here. A manual trigger also exists (`thread/compact/start`) if we ever want
|
|
574
|
+
// to force it from the UI.
|
|
561
575
|
const startResult = await rpc.request<{ thread: { id: string } }>('thread/start', {
|
|
562
576
|
cwd: WORKSPACE_DIR,
|
|
563
577
|
model: modelId,
|
package/supervisor/index.ts
CHANGED
|
@@ -31,6 +31,19 @@ import { ChannelManager } from './channels/manager.js';
|
|
|
31
31
|
const DIST_BLOBY = path.join(PKG_DIR, 'dist-bloby');
|
|
32
32
|
const SUPERVISOR_PUBLIC = path.join(PKG_DIR, 'supervisor', 'public');
|
|
33
33
|
|
|
34
|
+
// Proactive context recycling. The chat runs as one long-lived agent session per
|
|
35
|
+
// conversation (so the user can keep talking while the agent works). That session's
|
|
36
|
+
// context grows every turn and would eventually hit the wall. But continuity does NOT
|
|
37
|
+
// live in that session — every fresh session re-injects the recent messages + memory
|
|
38
|
+
// files — so when the context grows large AND the agent is idle, we end the session;
|
|
39
|
+
// the next message starts a clean one. This keeps heavy/long chats off the wall
|
|
40
|
+
// without lossy compaction, while preserving mid-turn responsiveness (we only recycle
|
|
41
|
+
// between turns). When the harness reports the model's context window we recycle at
|
|
42
|
+
// RECYCLE_FRACTION of it (adaptive to 200k vs 1M windows); otherwise we fall back to a
|
|
43
|
+
// fixed token budget. Auto-compaction stays on as the in-turn safety net.
|
|
44
|
+
const CONTEXT_RECYCLE_TOKENS = Number(process.env.BLOBY_CONTEXT_RECYCLE_TOKENS) || 140_000;
|
|
45
|
+
const CONTEXT_RECYCLE_FRACTION = Number(process.env.BLOBY_CONTEXT_RECYCLE_FRACTION) || 0.7;
|
|
46
|
+
|
|
34
47
|
// Platform assets that must survive workspace swaps — served directly by supervisor
|
|
35
48
|
const PLATFORM_ASSETS = new Set([
|
|
36
49
|
'/spritesheet.webp',
|
|
@@ -1429,7 +1442,7 @@ mint();
|
|
|
1429
1442
|
try {
|
|
1430
1443
|
const [status, recentRaw] = await Promise.all([
|
|
1431
1444
|
workerApi('/api/onboard/status'),
|
|
1432
|
-
workerApi(`/api/conversations/${convId}/messages/recent?limit=
|
|
1445
|
+
workerApi(`/api/conversations/${convId}/messages/recent?limit=30`),
|
|
1433
1446
|
]);
|
|
1434
1447
|
botName = status.agentName || 'Bloby';
|
|
1435
1448
|
humanName = status.userName || 'Human';
|
|
@@ -1894,6 +1907,22 @@ mint();
|
|
|
1894
1907
|
endConversation(convId);
|
|
1895
1908
|
runDeferredUpdate();
|
|
1896
1909
|
}
|
|
1910
|
+
|
|
1911
|
+
// Proactive session recycling (see CONTEXT_RECYCLE_TOKENS). Only when the
|
|
1912
|
+
// harness reports the session idle (no queued message) — and this handler runs
|
|
1913
|
+
// synchronously from the harness callback, so nothing can be pushed between the
|
|
1914
|
+
// idle check and endConversation. Recycling here therefore never drops a queued
|
|
1915
|
+
// message; the next user message re-injects recent history + memory.
|
|
1916
|
+
if (eventData.idle && hasConversation(convId)) {
|
|
1917
|
+
const used = typeof eventData.contextTokens === 'number' ? eventData.contextTokens : 0;
|
|
1918
|
+
const window = typeof eventData.contextWindow === 'number' ? eventData.contextWindow : 0;
|
|
1919
|
+
const recycleAt = window > 0 ? Math.floor(window * CONTEXT_RECYCLE_FRACTION) : CONTEXT_RECYCLE_TOKENS;
|
|
1920
|
+
if (used > recycleAt) {
|
|
1921
|
+
log.info(`[orchestrator] Context ~${used} tok > ${recycleAt} (window=${window || 'n/a'}) — recycling session ${convId}; next message re-injects recent + memory.`);
|
|
1922
|
+
endConversation(convId);
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1897
1926
|
broadcastBloby('bot:idle', { conversationId: convId });
|
|
1898
1927
|
return;
|
|
1899
1928
|
}
|
|
@@ -2227,7 +2256,7 @@ mint();
|
|
|
2227
2256
|
try {
|
|
2228
2257
|
const [status, recentRaw] = await Promise.all([
|
|
2229
2258
|
workerApi('/api/onboard/status') as Promise<any>,
|
|
2230
|
-
workerApi(`/api/conversations/${convId}/messages/recent?limit=
|
|
2259
|
+
workerApi(`/api/conversations/${convId}/messages/recent?limit=30`) as Promise<any[]>,
|
|
2231
2260
|
]);
|
|
2232
2261
|
botName = status.agentName || 'Bloby';
|
|
2233
2262
|
humanName = status.userName || 'Human';
|
|
@@ -279,7 +279,7 @@ If your human asks you to update a skill's behavior, edit the files INSIDE `skil
|
|
|
279
279
|
You can communicate through several surfaces at once. The two built-in ones are:
|
|
280
280
|
|
|
281
281
|
- **`[PWA]`** — the chat bubble in the dashboard (web app / PWA). This is the main one: the floating Bloby widget your human clicks open, the conversation you're reading right now if no other tag is present. Treat it as your home base.
|
|
282
|
-
- **`[Mac]`** — the Morphy native Mac app living in the MacBook notch. Your human held a hotkey, spoke, and Morphy sent the transcript here. Screenshots of their screen may be attached. Keep replies concise — they'll be spoken aloud via TTS. No markdown, no bullet lists — plain spoken sentences only.
|
|
282
|
+
- **`[Mac]`** — the Morphy native Mac app living in the MacBook notch. Your human held a hotkey, spoke, and Morphy sent the transcript here. Screenshots of their screen may be attached. Keep replies concise — they'll be spoken aloud via TTS. No markdown, no bullet lists — plain spoken sentences only. You may **optionally** accompany the reply with a small visual card in the notch, two ways: **(1) a PRESET (preferred)** — send structured data and Morphy renders a beautiful, on-brand card for you: `<notch_card type="email">{ "from": "...", "subject": "...", "time": "...", "body": "..." }</notch_card>`. Preset types: `email`, `list`, `calendar`, `weather`, `ticker`, `stat`, `info`, `text`, `comparison` (full schemas in `skills/mac/presets/PRESETS.md`). The body is one JSON object; you never write CSS. **(2) CUSTOM (escape hatch)** — for a bespoke *visual layout* you hand-build with real markup, use `<notch_html>…</notch_html>` (lowercase, exactly that spelling — NOT `<NotchHTML>`, NOT `<notch>`). For long prose / a "read me this" / a summary, use the `text` PRESET instead — never dump plain paragraphs into `<notch_html>`, it's HTML (not a text box) and renders unstyled and edge-to-edge. Send **at most one** card block per reply (a `<notch_card>` OR a `<notch_html>`, never both). Both tags are stripped from TTS, so card contents are **never** spoken. Canvas is **fixed 383 × 147 pt, transparent over BLACK**; custom cards use light/white text, no external assets (no `<img src>`, no fonts, no JS network) and no interactive elements (clicks do nothing) — though long content IS scrollable, the user scrolls it with the trackpad, so letting content overflow is fine. **CRITICAL: never speak the contents of your card.** If the card carries a list / calendar / email / news / comparison / any structured answer, the spoken text MUST be a short lead-in ONLY ("Here are today's top five, Bruno.") and then stop — do not recite the items, the human is already looking at them. If the answer fits in one spoken sentence, send NO card. Voice and card are complementary, never redundant — pick which one carries the detail per reply, and let the other be brief or absent. When in doubt, **open `skills/mac/SKILL.md` and follow it** — it has the preset catalog, examples (including the canonical bad/good comparison of the speak-the-card duplication failure), custom templates under `skills/mac/frequentSnippets/`, and a pre-send checklist. **Mis-spelling a tag means the markup reaches TTS and gets spoken at the human** — that's a visible failure, not a silent one.
|
|
283
283
|
- **`[workspace]`** — a chat-shaped widget your human placed somewhere inside their dashboard *workspace*. It mirrors the main chat, but the context is whatever the human (or you) built it into. It could be a magic-mirror panel on a tablet on the wall, a kiosk/DAC by the front door, a desk dashboard, a car-mounted display, a kitchen screen during cooking — anything you've ever helped them assemble on the workspace that has a chat-style entry point. **Check `MEMORY.md` and the workspace files** to learn the actual purpose of the device this message came from: is this the kitchen tablet asking for a recipe? The hallway mirror asking what's on today's schedule? The garage panel asking about the car? Tailor tone, brevity, and content to that role. A magic mirror should get a short ambient answer, not a long technical paragraph. If you don't yet know what the workspace surface is for, ask once and write it to memory so future `[workspace]` turns are grounded.
|
|
284
284
|
|
|
285
285
|
Beyond those, your human can install additional channels (WhatsApp, Telegram, Discord, Alexa…) as **skills** from the Bloby Marketplace. Each channel skill teaches you the conventions for that surface.
|