@bibobonking/opensol 3.1.5 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +8 -2
  2. package/LICENSE +21 -0
  3. package/README.md +24 -20
  4. package/desktop/README.md +1 -1
  5. package/dist/assets/{index-C0yvs6Vl.js → index-BUVnnhRH.js} +1 -1
  6. package/dist/assets/index-CyxlAgKM.js +271 -0
  7. package/dist/assets/index-DFeF90S8.css +1 -0
  8. package/dist/index.html +2 -2
  9. package/package.json +1 -1
  10. package/server/README.md +15 -68
  11. package/server/daemon.mjs +6 -1
  12. package/server/lib/deploy.mjs +5 -10
  13. package/server/lib/shell.mjs +149 -0
  14. package/server/lib/shell.test.mjs +72 -0
  15. package/server/lib/tools.mjs +8 -44
  16. package/src/agent/adapters/anthropic.ts +2 -3
  17. package/src/agent/adapters/gemini.ts +2 -3
  18. package/src/agent/adapters/openai-responses.ts +2 -3
  19. package/src/agent/adapters/openai.ts +2 -3
  20. package/src/agent/adapters/shared.ts +3 -0
  21. package/src/components/ChatView.tsx +17 -54
  22. package/src/components/Composer.tsx +143 -135
  23. package/src/components/ContextBar.tsx +2 -2
  24. package/src/components/HomeDashboard.tsx +7 -4
  25. package/src/components/MessageItem.tsx +33 -1
  26. package/src/components/ModelDeck.tsx +5 -27
  27. package/src/components/SettingsModal.tsx +8 -0
  28. package/src/components/ToolCallCard.tsx +2 -2
  29. package/src/components/TrajectoryView.tsx +1 -1
  30. package/src/components/composer/PlusMenu.tsx +117 -0
  31. package/src/components/composer/Popover.tsx +109 -0
  32. package/src/components/composer/WorkspacePicker.tsx +102 -0
  33. package/src/core/plugins/tools/shell.ts +2 -2
  34. package/src/core/plugins/tools/subagent.ts +18 -8
  35. package/src/core/services/agent-loop.ts +45 -43
  36. package/src/core/services/compaction.ts +289 -22
  37. package/src/core/services/llm.ts +6 -2
  38. package/src/core/services/subagents.ts +191 -3
  39. package/src/core/services/system-prompt.ts +35 -7
  40. package/src/core/services/tools.ts +2 -1
  41. package/src/core/types.ts +5 -0
  42. package/src/lib/compact-plan.test.mjs +62 -0
  43. package/src/lib/compact-plan.ts +188 -0
  44. package/src/lib/subagent-types.ts +54 -0
  45. package/src/lib/tool-meta.ts +40 -0
  46. package/src/store/settings.ts +3 -0
  47. package/src/store/ui.ts +12 -0
  48. package/src/types.ts +26 -0
  49. package/shared/plugin-builder.test.mjs +0 -43
  50. package/shared/plugin-package.d.mts +0 -34
  51. package/shared/plugin-package.mjs +0 -197
  52. package/shared/plugin-package.test.mjs +0 -94
  53. package/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1 @@
1
+ *,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Geist,Inter,system-ui,-apple-system,Segoe UI,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:Geist Mono,JetBrains Mono,ui-monospace,SFMono-Regular,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root,[data-theme=light]{--canvas: 248 248 246;--panel: 255 255 255;--raised: 240 240 237;--line: 232 232 228;--ink: 23 23 21;--muted: 98 98 93;--faint: 148 148 141;--accent: 217 119 6;--accent-soft: 254 244 224;--on-accent: 255 255 255;--success: 22 128 74;--warning: 180 100 8;--danger: 207 56 48;--syn-keyword: 124 58 237;--syn-string: 21 128 61;--syn-number: 194 85 8;--syn-title: 37 99 235;--syn-attr: 14 116 144;--chat-font-size: 15px;color-scheme:light}[data-theme=dark]{--canvas: 15 15 14;--panel: 20 20 19;--raised: 33 33 31;--line: 42 42 39;--ink: 237 237 233;--muted: 160 160 153;--faint: 112 112 106;--accent: 245 158 11;--accent-soft: 46 34 12;--on-accent: 26 17 3;--success: 74 205 130;--warning: 245 180 70;--danger: 248 113 104;--syn-keyword: 196 160 255;--syn-string: 130 218 160;--syn-number: 244 184 110;--syn-title: 140 184 255;--syn-attr: 120 214 226;--chat-font-size: 15px;color-scheme:dark}[data-theme=night-owl]{--canvas: 1 17 30;--panel: 1 22 39;--raised: 11 38 60;--line: 22 55 82;--ink: 214 222 235;--muted: 141 168 197;--faint: 95 122 153;--accent: 130 170 255;--accent-soft: 16 48 77;--on-accent: 1 22 39;--success: 34 210 156;--warning: 236 196 141;--danger: 239 83 80;--syn-keyword: 197 147 249;--syn-string: 144 209 148;--syn-number: 247 190 116;--syn-title: 130 170 255;--syn-attr: 33 193 220;color-scheme:dark}[data-theme=claude-code]{--canvas: 30 29 27;--panel: 38 37 34;--raised: 49 48 44;--line: 62 61 56;--ink: 232 230 224;--muted: 175 171 162;--faint: 129 126 118;--accent: 217 119 87;--accent-soft: 62 45 38;--on-accent: 28 22 18;--success: 143 191 140;--warning: 222 178 112;--danger: 224 122 112;--syn-keyword: 213 145 122;--syn-string: 143 187 137;--syn-number: 221 176 116;--syn-title: 158 184 222;--syn-attr: 135 189 191;color-scheme:dark}[data-theme=flame]{--canvas: 16 11 8;--panel: 22 15 11;--raised: 36 25 18;--line: 56 38 27;--ink: 250 238 224;--muted: 190 160 138;--faint: 134 106 88;--accent: 255 138 30;--accent-soft: 58 32 14;--on-accent: 26 12 4;--success: 146 206 138;--warning: 250 200 100;--danger: 255 106 92;--syn-keyword: 255 150 90;--syn-string: 170 210 138;--syn-number: 250 194 108;--syn-title: 250 176 128;--syn-attr: 168 200 224;color-scheme:dark}*{border-color:rgb(var(--line))}html,body,#root{height:100%}body{--tw-bg-opacity: 1;background-color:rgb(var(--panel) / var(--tw-bg-opacity, 1));font-family:Geist,Inter,system-ui,-apple-system,Segoe UI,sans-serif;--tw-text-opacity: 1;color:rgb(var(--ink) / var(--tw-text-opacity, 1));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-feature-settings:"ss01" 1,"cv11" 1;letter-spacing:-.003em;text-rendering:optimizeLegibility;overscroll-behavior:none}::-moz-selection{background:rgb(var(--accent) / .22)}::selection{background:rgb(var(--accent) / .22)}:focus-visible{outline:2px solid rgb(var(--accent) / .6);outline-offset:2px;border-radius:6px}button,input,textarea,select{font:inherit}button:not(:disabled){cursor:pointer}input::-moz-placeholder,textarea::-moz-placeholder{color:rgb(var(--faint))}input::placeholder,textarea::placeholder{color:rgb(var(--faint))}.icon-button{display:inline-flex;height:2rem;width:2rem;flex-shrink:0;align-items:center;justify-content:center;border-radius:.5rem;--tw-text-opacity: 1;color:rgb(var(--muted) / var(--tw-text-opacity, 1));transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;transition-timing-function:cubic-bezier(.16,1,.3,1)}.icon-button:hover{--tw-bg-opacity: 1;background-color:rgb(var(--raised) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(var(--ink) / var(--tw-text-opacity, 1))}.icon-button:active{--tw-scale-x: .9;--tw-scale-y: .9;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.icon-button:disabled{pointer-events:none;opacity:.4}.chip{display:inline-flex;height:2rem;align-items:center;gap:.375rem;border-radius:.5rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--line) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--panel) / var(--tw-bg-opacity, 1));padding-left:.75rem;padding-right:.75rem;font-size:12.5px;font-weight:500;--tw-text-opacity: 1;color:rgb(var(--muted) / var(--tw-text-opacity, 1));transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.chip:hover{border-color:rgb(var(--faint) / .4);background-color:rgb(var(--raised) / .6);--tw-text-opacity: 1;color:rgb(var(--ink) / var(--tw-text-opacity, 1))}.chip:active{--tw-scale-x: .97;--tw-scale-y: .97;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.eyebrow{font-size:10.5px;font-weight:500;text-transform:uppercase;letter-spacing:.14em;--tw-text-opacity: 1;color:rgb(var(--faint) / var(--tw-text-opacity, 1))}.sidebar-item{position:relative;display:flex;height:2rem;width:100%;align-items:center;gap:.625rem;border-radius:.5rem;padding-left:.625rem;padding-right:.625rem;text-align:left;font-size:13px;--tw-text-opacity: 1;color:rgb(var(--muted) / var(--tw-text-opacity, 1));transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.sidebar-item:hover{background-color:rgb(var(--raised) / .8);--tw-text-opacity: 1;color:rgb(var(--ink) / var(--tw-text-opacity, 1))}.sidebar-item-active{--tw-bg-opacity: 1;background-color:rgb(var(--raised) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(var(--ink) / var(--tw-text-opacity, 1))}.sidebar-item-active:hover{--tw-bg-opacity: 1;background-color:rgb(var(--raised) / var(--tw-bg-opacity, 1))}.sidebar-item-active:before{content:"";position:absolute;left:0;top:8px;bottom:8px;width:2px;border-radius:2px;background:rgb(var(--accent));animation:scalein .3s cubic-bezier(.16,1,.3,1) both}.nav-item{display:flex;height:2rem;width:100%;align-items:center;gap:.625rem;border-radius:.5rem;padding-left:.625rem;padding-right:.625rem;text-align:left;font-size:13px;--tw-text-opacity: 1;color:rgb(var(--muted) / var(--tw-text-opacity, 1));transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.nav-item:hover{background-color:rgb(var(--raised) / .8);--tw-text-opacity: 1;color:rgb(var(--ink) / var(--tw-text-opacity, 1))}.nav-item:active{--tw-scale-x: .99;--tw-scale-y: .99;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.surface-lift{background:rgb(var(--panel))}.chat-text{font-size:var(--chat-font-size, 15px)}.settings-row{margin-left:-.75rem;margin-right:-.75rem;display:flex;flex-direction:column;gap:.5rem;border-radius:1rem;border-bottom-width:1px;border-color:transparent;padding:1rem .75rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s}.settings-row:hover{background-color:rgb(var(--raised) / .5)}@media(min-width:640px){.settings-row{flex-direction:row;align-items:center;justify-content:space-between;gap:1.5rem}}.settings-card{position:relative;border-radius:1rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--line) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--panel) / var(--tw-bg-opacity, 1));padding:1rem;--tw-shadow: 0 1px 2px rgba(0,0,0,.06);--tw-shadow-colored: 0 1px 2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.3s}@media(min-width:640px){.settings-card{padding:1.25rem}}.settings-card:hover{border-color:rgb(var(--accent) / .25)}.settings-label{font-size:13px;font-weight:500;--tw-text-opacity: 1;color:rgb(var(--ink) / var(--tw-text-opacity, 1))}.settings-hint{margin-top:.125rem;font-size:12px;line-height:1.625;--tw-text-opacity: 1;color:rgb(var(--muted) / var(--tw-text-opacity, 1))}.settings-select{height:2.25rem;flex-shrink:0;border-radius:.5rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--line) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--panel) / var(--tw-bg-opacity, 1));padding-left:.625rem;padding-right:.625rem;font-size:12.5px;--tw-text-opacity: 1;color:rgb(var(--ink) / var(--tw-text-opacity, 1));outline:2px solid transparent;outline-offset:2px;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.settings-select:focus{border-color:rgb(var(--accent) / .6)}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.inset-\[5px\]{inset:5px}.inset-x-0{left:0;right:0}.inset-x-\[13px\]{left:13px;right:13px}.inset-y-0{top:0;bottom:0}.inset-y-1{top:.25rem;bottom:.25rem}.-right-1\.5{right:-.375rem}.-top-1\.5{top:-.375rem}.-top-\[34px\]{top:-34px}.bottom-0\.5{bottom:.125rem}.bottom-1{bottom:.25rem}.bottom-3{bottom:.75rem}.bottom-4{bottom:1rem}.bottom-56{bottom:14rem}.bottom-\[calc\(100\%\+8px\)\]{bottom:calc(100% + 8px)}.left-0{left:0}.left-1\/2{left:50%}.left-2{left:.5rem}.left-2\.5{left:.625rem}.left-3{left:.75rem}.left-3\.5{left:.875rem}.left-\[13px\]{left:13px}.right-0{right:0}.right-1{right:.25rem}.right-1\.5{right:.375rem}.right-2{right:.5rem}.right-3{right:.75rem}.right-4{right:1rem}.top-0{top:0}.top-1{top:.25rem}.top-1\.5{top:.375rem}.top-1\/2{top:50%}.top-2{top:.5rem}.top-2\.5{top:.625rem}.top-3{top:.75rem}.top-\[1px\]{top:1px}.top-\[calc\(100\%\+6px\)\]{top:calc(100% + 6px)}.-z-10{z-index:-10}.z-10{z-index:10}.z-20{z-index:20}.z-40{z-index:40}.z-50{z-index:50}.z-\[100\]{z-index:100}.z-\[60\]{z-index:60}.z-\[70\]{z-index:70}.z-\[80\]{z-index:80}.z-\[90\]{z-index:90}.z-\[95\]{z-index:95}.m-auto{margin:auto}.mx-5{margin-left:1.25rem;margin-right:1.25rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-4{margin-top:1rem;margin-bottom:1rem}.-mr-1{margin-right:-.25rem}.-mt-1{margin-top:-.25rem}.-mt-2{margin-top:-.5rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-2\.5{margin-bottom:.625rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-\[2px\]{margin-bottom:2px}.ml-1\.5{margin-left:.375rem}.ml-2{margin-left:.5rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-3{margin-right:.75rem}.mr-auto{margin-right:auto}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-10{margin-top:2.5rem}.mt-12{margin-top:3rem}.mt-2{margin-top:.5rem}.mt-2\.5{margin-top:.625rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.mt-9{margin-top:2.25rem}.mt-\[3px\]{margin-top:3px}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.line-clamp-3{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3}.line-clamp-4{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-1{height:.25rem}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-2{height:.5rem}.h-20{height:5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-32{height:8rem}.h-4{height:1rem}.h-40{height:10rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-52{height:13rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-\[11px\]{height:11px}.h-\[120px\]{height:120px}.h-\[16px\]{height:16px}.h-\[18px\]{height:18px}.h-\[22px\]{height:22px}.h-\[26px\]{height:26px}.h-\[280px\]{height:280px}.h-\[2px\]{height:2px}.h-\[3px\]{height:3px}.h-\[420px\]{height:420px}.h-\[46px\]{height:46px}.h-\[7px\]{height:7px}.h-\[92dvh\]{height:92dvh}.h-\[94dvh\]{height:94dvh}.h-\[min\(92dvh\,640px\)\]{height:min(92dvh,640px)}.h-dvh{height:100dvh}.h-full{height:100%}.h-px{height:1px}.max-h-0{max-height:0px}.max-h-24{max-height:6rem}.max-h-40{max-height:10rem}.max-h-48{max-height:12rem}.max-h-52{max-height:13rem}.max-h-64{max-height:16rem}.max-h-72{max-height:18rem}.max-h-8{max-height:2rem}.max-h-\[32dvh\]{max-height:32dvh}.max-h-\[92dvh\]{max-height:92dvh}.max-h-\[calc\(100dvh-80px\)\]{max-height:calc(100dvh - 80px)}.max-h-\[min\(72dvh\,560px\)\]{max-height:min(72dvh,560px)}.min-h-0{min-height:0px}.min-h-\[200px\]{min-height:200px}.min-h-\[220px\]{min-height:220px}.min-h-\[22px\]{min-height:22px}.min-h-\[28px\]{min-height:28px}.min-h-\[320px\]{min-height:320px}.min-h-\[92px\]{min-height:92px}.min-h-full{min-height:100%}.w-1{width:.25rem}.w-1\.5{width:.375rem}.w-10{width:2.5rem}.w-11{width:2.75rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-2{width:.5rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-\[11px\]{width:11px}.w-\[16px\]{width:16px}.w-\[184px\]{width:184px}.w-\[18px\]{width:18px}.w-\[232px\]{width:232px}.w-\[264px\]{width:264px}.w-\[38px\]{width:38px}.w-\[3px\]{width:3px}.w-\[74px\]{width:74px}.w-\[7px\]{width:7px}.w-\[84px\]{width:84px}.w-\[calc\(100\%-20px\)\]{width:calc(100% - 20px)}.w-\[min\(420px\,92vw\)\]{width:min(420px,92vw)}.w-\[min\(92vw\,440px\)\]{width:min(92vw,440px)}.w-\[min\(94vw\,360px\)\]{width:min(94vw,360px)}.w-\[min\(96vw\,440px\)\]{width:min(96vw,440px)}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.w-px{width:1px}.min-w-0{min-width:0px}.min-w-\[220px\]{min-width:220px}.min-w-\[58px\]{min-width:58px}.min-w-max{min-width:-moz-max-content;min-width:max-content}.max-w-\[120px\]{max-width:120px}.max-w-\[140px\]{max-width:140px}.max-w-\[170px\]{max-width:170px}.max-w-\[180px\]{max-width:180px}.max-w-\[220px\]{max-width:220px}.max-w-\[230px\]{max-width:230px}.max-w-\[240px\]{max-width:240px}.max-w-\[260px\]{max-width:260px}.max-w-\[280px\]{max-width:280px}.max-w-\[300px\]{max-width:300px}.max-w-\[320px\]{max-width:320px}.max-w-\[400px\]{max-width:400px}.max-w-\[460px\]{max-width:460px}.max-w-\[520px\]{max-width:520px}.max-w-\[560px\]{max-width:560px}.max-w-\[620px\]{max-width:620px}.max-w-\[720px\]{max-width:720px}.max-w-\[760px\]{max-width:760px}.max-w-\[800px\]{max-width:800px}.max-w-\[88\%\]{max-width:88%}.max-w-\[calc\(100vw-24px\)\]{max-width:calc(100vw - 24px)}.max-w-full{max-width:100%}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-full{--tw-translate-x: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\[19px\]{--tw-translate-x: 19px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\[3px\]{--tw-translate-x: 3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-1\/2{--tw-translate-y: 50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-45{--tw-rotate: 45deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-90{--tw-rotate: 90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-100{--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-110{--tw-scale-x: 1.1;--tw-scale-y: 1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes blurin{0%{opacity:0;filter:blur(8px);transform:translateY(6px)}to{opacity:1;filter:blur(0);transform:translateY(0)}}.animate-blurin{animation:blurin .7s cubic-bezier(.16,1,.3,1) both}.animate-bob{animation:bob 1.6s ease-in-out infinite}@keyframes bob{0%,to{transform:translateY(0)}50%{transform:translateY(-2px)}}.animate-bob-fast{animation:bob .8s ease-in-out infinite}@keyframes bounce{0%,to{transform:translateY(-25%);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:none;animation-timing-function:cubic-bezier(0,0,.2,1)}}.animate-bounce{animation:bounce 1s infinite}@keyframes breathe{0%,to{transform:scale(1);opacity:1}50%{transform:scale(.8);opacity:.6}}.animate-breathe{animation:breathe 1.6s ease-in-out infinite}@keyframes fade{0%{opacity:0}to{opacity:1}}.animate-fade{animation:fade .25s ease-out both}.animate-float{animation:float 2.4s ease-in-out infinite}@keyframes float{0%,to{transform:translateY(0)}50%{transform:translateY(-3px)}}.animate-float-slow{animation:float 3.4s ease-in-out infinite}@keyframes ping{75%,to{transform:scale(2);opacity:0}0%{transform:scale(1);opacity:.5}80%,to{transform:scale(2.2);opacity:0}}.animate-ping{animation:ping 1.8s cubic-bezier(0,0,.2,1) infinite}@keyframes pop{0%,to{transform:scale(1)}50%{transform:scale(1.1)}}.animate-pop{animation:pop 1.4s ease-in-out infinite}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes rise{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}.animate-rise{animation:rise .6s cubic-bezier(.16,1,.3,1) both}@keyframes scalein{0%{opacity:0;transform:scale(.96)}to{opacity:1;transform:scale(1)}}.animate-scalein{animation:scalein .28s cubic-bezier(.16,1,.3,1) both}@keyframes shake{0%,to{transform:translate(0)}25%{transform:translate(-1.5px)}75%{transform:translate(1.5px)}}.animate-shake{animation:shake .35s ease-in-out infinite}@keyframes slideleft{0%{opacity:0;transform:translate(-10px)}to{opacity:1;transform:translate(0)}}.animate-slideleft{animation:slideleft .4s cubic-bezier(.16,1,.3,1) both}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.animate-spin-slow{animation:spinslow 18s linear infinite}.cursor-default{cursor:default}.cursor-grab{cursor:grab}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize-y{resize:vertical}.resize{resize:both}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-rows-7{grid-template-rows:repeat(7,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-3\.5{gap:.875rem}.gap-4{gap:1rem}.gap-\[3px\]{gap:3px}.gap-x-1{-moz-column-gap:.25rem;column-gap:.25rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-y-0\.5{row-gap:.125rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-2\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.625rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.625rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-line>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(var(--line) / var(--tw-divide-opacity, 1))}.self-start{align-self:flex-start}.self-center{align-self:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overscroll-contain{overscroll-behavior:contain}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre{white-space:pre}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-\[2px\]{border-radius:2px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.rounded-r-full{border-top-right-radius:9999px;border-bottom-right-radius:9999px}.rounded-t-2xl{border-top-left-radius:1rem;border-top-right-radius:1rem}.rounded-t-\[28px\]{border-top-left-radius:28px;border-top-right-radius:28px}.rounded-br-md{border-bottom-right-radius:.375rem}.border{border-width:1px}.border-0{border-width:0px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-accent{--tw-border-opacity: 1;border-color:rgb(var(--accent) / var(--tw-border-opacity, 1))}.border-accent\/30{border-color:rgb(var(--accent) / .3)}.border-accent\/35{border-color:rgb(var(--accent) / .35)}.border-accent\/40{border-color:rgb(var(--accent) / .4)}.border-accent\/45{border-color:rgb(var(--accent) / .45)}.border-accent\/50{border-color:rgb(var(--accent) / .5)}.border-accent\/60{border-color:rgb(var(--accent) / .6)}.border-current{border-color:currentColor}.border-danger\/20{border-color:rgb(var(--danger) / .2)}.border-danger\/25{border-color:rgb(var(--danger) / .25)}.border-danger\/30{border-color:rgb(var(--danger) / .3)}.border-faint{--tw-border-opacity: 1;border-color:rgb(var(--faint) / var(--tw-border-opacity, 1))}.border-line{--tw-border-opacity: 1;border-color:rgb(var(--line) / var(--tw-border-opacity, 1))}.border-line\/60{border-color:rgb(var(--line) / .6)}.border-line\/70{border-color:rgb(var(--line) / .7)}.border-line\/80{border-color:rgb(var(--line) / .8)}.border-on-accent\/40{border-color:rgb(var(--on-accent) / .4)}.border-success\/25{border-color:rgb(var(--success) / .25)}.border-success\/30{border-color:rgb(var(--success) / .3)}.border-transparent{border-color:transparent}.border-warning\/25{border-color:rgb(var(--warning) / .25)}.border-warning\/30{border-color:rgb(var(--warning) / .3)}.border-warning\/40{border-color:rgb(var(--warning) / .4)}.border-t-transparent{border-top-color:transparent}.bg-\[\#011627\]{--tw-bg-opacity: 1;background-color:rgb(1 22 39 / var(--tw-bg-opacity, 1))}.bg-\[\#09090b\]{--tw-bg-opacity: 1;background-color:rgb(9 9 11 / var(--tw-bg-opacity, 1))}.bg-\[\#130d0c\]{--tw-bg-opacity: 1;background-color:rgb(19 13 12 / var(--tw-bg-opacity, 1))}.bg-\[\#1a3e5a\]{--tw-bg-opacity: 1;background-color:rgb(26 62 90 / var(--tw-bg-opacity, 1))}.bg-\[\#262624\]{--tw-bg-opacity: 1;background-color:rgb(38 38 36 / var(--tw-bg-opacity, 1))}.bg-\[\#2a2a31\]{--tw-bg-opacity: 1;background-color:rgb(42 42 49 / var(--tw-bg-opacity, 1))}.bg-\[\#3e2621\]{--tw-bg-opacity: 1;background-color:rgb(62 38 33 / var(--tw-bg-opacity, 1))}.bg-\[\#42423e\]{--tw-bg-opacity: 1;background-color:rgb(66 66 62 / var(--tw-bg-opacity, 1))}.bg-\[\#8a8a92\]{--tw-bg-opacity: 1;background-color:rgb(138 138 146 / var(--tw-bg-opacity, 1))}.bg-\[\#e2e2e5\]{--tw-bg-opacity: 1;background-color:rgb(226 226 229 / var(--tw-bg-opacity, 1))}.bg-\[\#fcfcfc\]{--tw-bg-opacity: 1;background-color:rgb(252 252 252 / var(--tw-bg-opacity, 1))}.bg-accent{--tw-bg-opacity: 1;background-color:rgb(var(--accent) / var(--tw-bg-opacity, 1))}.bg-accent-soft{--tw-bg-opacity: 1;background-color:rgb(var(--accent-soft) / var(--tw-bg-opacity, 1))}.bg-accent-soft\/40{background-color:rgb(var(--accent-soft) / .4)}.bg-accent-soft\/50{background-color:rgb(var(--accent-soft) / .5)}.bg-accent-soft\/60{background-color:rgb(var(--accent-soft) / .6)}.bg-accent\/10{background-color:rgb(var(--accent) / .1)}.bg-accent\/20{background-color:rgb(var(--accent) / .2)}.bg-accent\/35{background-color:rgb(var(--accent) / .35)}.bg-accent\/55{background-color:rgb(var(--accent) / .55)}.bg-accent\/70{background-color:rgb(var(--accent) / .7)}.bg-accent\/80{background-color:rgb(var(--accent) / .8)}.bg-black\/30{background-color:#0000004d}.bg-black\/35{background-color:#00000059}.bg-black\/40{background-color:#0006}.bg-canvas{--tw-bg-opacity: 1;background-color:rgb(var(--canvas) / var(--tw-bg-opacity, 1))}.bg-canvas\/40{background-color:rgb(var(--canvas) / .4)}.bg-canvas\/60{background-color:rgb(var(--canvas) / .6)}.bg-canvas\/70{background-color:rgb(var(--canvas) / .7)}.bg-canvas\/95{background-color:rgb(var(--canvas) / .95)}.bg-current{background-color:currentColor}.bg-danger{--tw-bg-opacity: 1;background-color:rgb(var(--danger) / var(--tw-bg-opacity, 1))}.bg-danger\/10{background-color:rgb(var(--danger) / .1)}.bg-danger\/\[0\.02\]{background-color:rgb(var(--danger) / .02)}.bg-danger\/\[0\.045\]{background-color:rgb(var(--danger) / .045)}.bg-danger\/\[0\.04\]{background-color:rgb(var(--danger) / .04)}.bg-danger\/\[0\.05\]{background-color:rgb(var(--danger) / .05)}.bg-danger\/\[0\.10\]{background-color:rgb(var(--danger) / .1)}.bg-faint{--tw-bg-opacity: 1;background-color:rgb(var(--faint) / var(--tw-bg-opacity, 1))}.bg-faint\/60{background-color:rgb(var(--faint) / .6)}.bg-ink{--tw-bg-opacity: 1;background-color:rgb(var(--ink) / var(--tw-bg-opacity, 1))}.bg-ink\/20{background-color:rgb(var(--ink) / .2)}.bg-line{--tw-bg-opacity: 1;background-color:rgb(var(--line) / var(--tw-bg-opacity, 1))}.bg-line\/70{background-color:rgb(var(--line) / .7)}.bg-on-accent\/80{background-color:rgb(var(--on-accent) / .8)}.bg-panel{--tw-bg-opacity: 1;background-color:rgb(var(--panel) / var(--tw-bg-opacity, 1))}.bg-panel\/60{background-color:rgb(var(--panel) / .6)}.bg-panel\/80{background-color:rgb(var(--panel) / .8)}.bg-panel\/95{background-color:rgb(var(--panel) / .95)}.bg-raised{--tw-bg-opacity: 1;background-color:rgb(var(--raised) / var(--tw-bg-opacity, 1))}.bg-raised\/20{background-color:rgb(var(--raised) / .2)}.bg-raised\/25{background-color:rgb(var(--raised) / .25)}.bg-raised\/30{background-color:rgb(var(--raised) / .3)}.bg-raised\/40{background-color:rgb(var(--raised) / .4)}.bg-raised\/50{background-color:rgb(var(--raised) / .5)}.bg-raised\/60{background-color:rgb(var(--raised) / .6)}.bg-raised\/70{background-color:rgb(var(--raised) / .7)}.bg-raised\/80{background-color:rgb(var(--raised) / .8)}.bg-success{--tw-bg-opacity: 1;background-color:rgb(var(--success) / var(--tw-bg-opacity, 1))}.bg-success\/10{background-color:rgb(var(--success) / .1)}.bg-success\/15{background-color:rgb(var(--success) / .15)}.bg-success\/40{background-color:rgb(var(--success) / .4)}.bg-success\/\[0\.04\]{background-color:rgb(var(--success) / .04)}.bg-success\/\[0\.05\]{background-color:rgb(var(--success) / .05)}.bg-success\/\[0\.11\]{background-color:rgb(var(--success) / .11)}.bg-transparent{background-color:transparent}.bg-warning{--tw-bg-opacity: 1;background-color:rgb(var(--warning) / var(--tw-bg-opacity, 1))}.bg-warning\/10{background-color:rgb(var(--warning) / .1)}.bg-warning\/70{background-color:rgb(var(--warning) / .7)}.bg-warning\/\[0\.04\]{background-color:rgb(var(--warning) / .04)}.bg-warning\/\[0\.05\]{background-color:rgb(var(--warning) / .05)}.bg-warning\/\[0\.06\]{background-color:rgb(var(--warning) / .06)}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-gradient-to-t{background-image:linear-gradient(to top,var(--tw-gradient-stops))}.from-\[\#fcfcfc\]{--tw-gradient-from: #fcfcfc var(--tw-gradient-from-position);--tw-gradient-to: rgb(252 252 252 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-accent-soft{--tw-gradient-from: rgb(var(--accent-soft) / 1) var(--tw-gradient-from-position);--tw-gradient-to: rgb(var(--accent-soft) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-accent\/40{--tw-gradient-from: rgb(var(--accent) / .4) var(--tw-gradient-from-position);--tw-gradient-to: rgb(var(--accent) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.via-accent{--tw-gradient-to: rgb(var(--accent) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), rgb(var(--accent) / 1) var(--tw-gradient-via-position), var(--tw-gradient-to)}.to-\[\#09090b\]{--tw-gradient-to: #09090b var(--tw-gradient-to-position)}.to-accent{--tw-gradient-to: rgb(var(--accent) / 1) var(--tw-gradient-to-position)}.to-panel{--tw-gradient-to: rgb(var(--panel) / 1) var(--tw-gradient-to-position)}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:0}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-3\.5{padding:.875rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.px-0\.5{padding-left:.125rem;padding-right:.125rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-3\.5{padding-left:.875rem;padding-right:.875rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-3\.5{padding-top:.875rem;padding-bottom:.875rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-7{padding-top:1.75rem;padding-bottom:1.75rem}.py-8{padding-top:2rem;padding-bottom:2rem}.py-\[3px\]{padding-top:3px;padding-bottom:3px}.py-px{padding-top:1px;padding-bottom:1px}.pb-0{padding-bottom:0}.pb-1{padding-bottom:.25rem}.pb-1\.5{padding-bottom:.375rem}.pb-12{padding-bottom:3rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pb-6{padding-bottom:1.5rem}.pl-10{padding-left:2.5rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pl-7{padding-left:1.75rem}.pl-8{padding-left:2rem}.pl-9{padding-left:2.25rem}.pl-\[17px\]{padding-left:17px}.pl-\[18px\]{padding-left:18px}.pl-\[19px\]{padding-left:19px}.pl-\[34px\]{padding-left:34px}.pr-1{padding-right:.25rem}.pr-1\.5{padding-right:.375rem}.pr-14{padding-right:3.5rem}.pr-2{padding-right:.5rem}.pr-2\.5{padding-right:.625rem}.pr-3{padding-right:.75rem}.pr-8{padding-right:2rem}.pr-9{padding-right:2.25rem}.pt-0\.5{padding-top:.125rem}.pt-1{padding-top:.25rem}.pt-1\.5{padding-top:.375rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-3\.5{padding-top:.875rem}.pt-5{padding-top:1.25rem}.pt-6{padding-top:1.5rem}.pt-7{padding-top:1.75rem}.pt-8{padding-top:2rem}.pt-\[10vh\]{padding-top:10vh}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-display{font-family:Geist,Inter,system-ui,-apple-system,sans-serif}.font-mono{font-family:Geist Mono,JetBrains Mono,ui-monospace,SFMono-Regular,monospace}.font-sans{font-family:Geist,Inter,system-ui,-apple-system,Segoe UI,sans-serif}.text-\[10\.5px\]{font-size:10.5px}.text-\[10px\]{font-size:10px}.text-\[11\.5px\]{font-size:11.5px}.text-\[11px\]{font-size:11px}.text-\[12\.5px\]{font-size:12.5px}.text-\[12px\]{font-size:12px}.text-\[13\.5px\]{font-size:13.5px}.text-\[13px\]{font-size:13px}.text-\[14\.5px\]{font-size:14.5px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[16px\]{font-size:16px}.text-\[19px\]{font-size:19px}.text-\[20px\]{font-size:20px}.text-\[22px\]{font-size:22px}.text-\[26px\]{font-size:26px}.text-\[28px\]{font-size:28px}.text-\[8\.5px\]{font-size:8.5px}.text-\[8px\]{font-size:8px}.text-\[9\.5px\]{font-size:9.5px}.text-\[9px\]{font-size:9px}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.normal-case{text-transform:none}.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)}.leading-\[1\.55\]{line-height:1.55}.leading-\[1\.65\]{line-height:1.65}.leading-\[1\.6\]{line-height:1.6}.leading-\[1\.75\]{line-height:1.75}.leading-\[1\.7\]{line-height:1.7}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-\[-0\.01em\]{letter-spacing:-.01em}.tracking-\[-0\.025em\]{letter-spacing:-.025em}.tracking-\[-0\.02em\]{letter-spacing:-.02em}.tracking-\[-0\.035em\]{letter-spacing:-.035em}.tracking-\[-0\.03em\]{letter-spacing:-.03em}.tracking-\[-0\.04em\]{letter-spacing:-.04em}.tracking-\[0\.01em\]{letter-spacing:.01em}.tracking-\[0\.08em\]{letter-spacing:.08em}.tracking-\[0\.12em\]{letter-spacing:.12em}.tracking-\[0\.13em\]{letter-spacing:.13em}.tracking-\[0\.14em\]{letter-spacing:.14em}.tracking-\[0\.1em\]{letter-spacing:.1em}.tracking-\[0\.22em\]{letter-spacing:.22em}.tracking-\[0\.24em\]{letter-spacing:.24em}.tracking-\[0\.2em\]{letter-spacing:.2em}.tracking-normal{letter-spacing:0em}.tracking-tight{letter-spacing:-.025em}.text-accent{--tw-text-opacity: 1;color:rgb(var(--accent) / var(--tw-text-opacity, 1))}.text-accent\/80{color:rgb(var(--accent) / .8)}.text-current{color:currentColor}.text-danger{--tw-text-opacity: 1;color:rgb(var(--danger) / var(--tw-text-opacity, 1))}.text-faint{--tw-text-opacity: 1;color:rgb(var(--faint) / var(--tw-text-opacity, 1))}.text-faint\/50{color:rgb(var(--faint) / .5)}.text-faint\/70{color:rgb(var(--faint) / .7)}.text-faint\/80{color:rgb(var(--faint) / .8)}.text-ink{--tw-text-opacity: 1;color:rgb(var(--ink) / var(--tw-text-opacity, 1))}.text-ink\/80{color:rgb(var(--ink) / .8)}.text-ink\/85{color:rgb(var(--ink) / .85)}.text-line{--tw-text-opacity: 1;color:rgb(var(--line) / var(--tw-text-opacity, 1))}.text-muted{--tw-text-opacity: 1;color:rgb(var(--muted) / var(--tw-text-opacity, 1))}.text-on-accent{--tw-text-opacity: 1;color:rgb(var(--on-accent) / var(--tw-text-opacity, 1))}.text-panel{--tw-text-opacity: 1;color:rgb(var(--panel) / var(--tw-text-opacity, 1))}.text-success{--tw-text-opacity: 1;color:rgb(var(--success) / var(--tw-text-opacity, 1))}.text-warning{--tw-text-opacity: 1;color:rgb(var(--warning) / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.decoration-ink\/30{text-decoration-color:rgb(var(--ink) / .3)}.underline-offset-\[3px\]{text-underline-offset:3px}.accent-\[rgb\(var\(--accent\)\)\]{accent-color:rgb(var(--accent))}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.shadow-\[0_0_0_3px_rgb\(var\(--success\)\/0\.18\)\]{--tw-shadow: 0 0 0 3px rgb(var(--success)/.18);--tw-shadow-colored: 0 0 0 3px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_0_0_3px_rgb\(var\(--warning\)\/0\.18\)\]{--tw-shadow: 0 0 0 3px rgb(var(--warning)/.18);--tw-shadow-colored: 0 0 0 3px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_1px_2px_rgba\(20\,22\,30\,0\.08\)\]{--tw-shadow: 0 1px 2px rgba(20,22,30,.08);--tw-shadow-colored: 0 1px 2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[inset_0_1px_3px_rgba\(0\,0\,0\,0\.12\)\]{--tw-shadow: inset 0 1px 3px rgba(0,0,0,.12);--tw-shadow-colored: inset 0 1px 3px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-composer{--tw-shadow: 0 1px 2px rgba(0,0,0,.04), 0 8px 28px -12px rgba(0,0,0,.12);--tw-shadow-colored: 0 1px 2px var(--tw-shadow-color), 0 8px 28px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-float{--tw-shadow: 0 24px 64px -20px rgba(0,0,0,.28), 0 0 0 1px rgb(var(--line));--tw-shadow-colored: 0 24px 64px -20px var(--tw-shadow-color), 0 0 0 1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-pill{--tw-shadow: 0 1px 2px rgba(0,0,0,.06);--tw-shadow-colored: 0 1px 2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-2{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-4{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-accent\/10{--tw-ring-color: rgb(var(--accent) / .1)}.ring-accent\/40{--tw-ring-color: rgb(var(--accent) / .4)}.ring-accent\/\[0\.03\]{--tw-ring-color: rgb(var(--accent) / .03)}.ring-line{--tw-ring-opacity: 1;--tw-ring-color: rgb(var(--line) / var(--tw-ring-opacity, 1))}.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.blur-2xl{--tw-blur: blur(40px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-\[1px\]{--tw-backdrop-blur: blur(1px);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-\[2px\]{--tw-backdrop-blur: blur(2px);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-\[3px\]{--tw-backdrop-blur: blur(3px);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-\[6px\]{--tw-backdrop-blur: blur(6px);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(4px);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-xl{--tw-backdrop-blur: blur(24px);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,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\[bottom\]{transition-property:bottom;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\[height\]{transition-property:height;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\[width\]{transition-property:width;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.\!duration-75{transition-duration:75ms!important}.duration-150{transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.ease-out{transition-timing-function:cubic-bezier(.16,1,.3,1)}.ease-spring{transition-timing-function:cubic-bezier(.34,1.56,.64,1)}.\[animation-delay\:0\.8s\]{animation-delay:.8s}.\[animation-delay\:1\.2s\]{animation-delay:1.2s}.\[animation-delay\:120ms\]{animation-delay:.12s}.\[animation-delay\:160ms\]{animation-delay:.16s}.\[animation-delay\:1s\]{animation-delay:1s}.\[animation-delay\:320ms\]{animation-delay:.32s}.\[animation-delay\:420ms\]{animation-delay:.42s}.md{font-family:Geist,Inter,system-ui,-apple-system,Segoe UI,sans-serif;line-height:1.72;--tw-text-opacity: 1;color:rgb(var(--ink) / var(--tw-text-opacity, 1));font-size:var(--chat-font-size, 15px);font-feature-settings:"kern" 1,"liga" 1;word-break:break-word}.md p,.md li{text-wrap:pretty}.md h1,.md h2,.md h3,.md h4{text-wrap:balance}.md>:first-child{margin-top:0}.md>:last-child{margin-bottom:0}.md p{margin:.7em 0}.md h1,.md h2,.md h3,.md h4{font-weight:600;letter-spacing:-.02em;--tw-text-opacity: 1;color:rgb(var(--ink) / var(--tw-text-opacity, 1));margin:1.4em 0 .55em;line-height:1.3}.md h1,.md h2{font-weight:600}.md h1{font-size:1.45em}.md h2{font-size:1.22em}.md h3{font-weight:600;font-size:1.08em}.md h4{font-weight:600;font-size:1em}.md ul,.md ol{margin:.65em 0;padding-left:1.35em}.md ul{list-style:disc}.md ol{list-style:decimal}.md li{margin:.28em 0}.md li>p{margin:.25em 0}.md li::marker{color:rgb(var(--faint))}.md a{--tw-text-opacity: 1;color:rgb(var(--accent) / var(--tw-text-opacity, 1));text-decoration-line:underline;text-decoration-color:rgb(var(--accent) / .3);text-underline-offset:2px;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.md a:hover{text-decoration-color:rgb(var(--accent) / 1)}.md strong{font-weight:600;--tw-text-opacity: 1;color:rgb(var(--ink) / var(--tw-text-opacity, 1))}.md code{border-radius:5px;--tw-bg-opacity: 1;background-color:rgb(var(--raised) / var(--tw-bg-opacity, 1));padding:.12em .36em;font-family:Geist Mono,JetBrains Mono,ui-monospace,SFMono-Regular,monospace;font-size:.845em;--tw-text-opacity: 1;color:rgb(var(--ink) / var(--tw-text-opacity, 1))}.md pre code{background:transparent;padding:0;border-radius:0;font-size:inherit;color:inherit}.md blockquote{margin:.9em 0;border-left:2px solid rgb(var(--accent) / .35);padding:.15em 0 .15em .9em;color:rgb(var(--muted))}.md hr{margin:1.5em 0;border:0;border-top:1px solid rgb(var(--line))}.md table{margin:1em 0;width:100%;border-collapse:collapse;font-size:.9em}.md th,.md td{border:1px solid rgb(var(--line));padding:.45em .7em;text-align:left;vertical-align:top}.md th{background-color:rgb(var(--raised) / .7);font-weight:500}.md input[type=checkbox]{margin-right:.4em;accent-color:rgb(var(--accent))}.md img{max-width:100%;border-radius:10px;border:1px solid rgb(var(--line))}.code-shell{margin-top:1rem;margin-bottom:1rem;overflow:hidden;border-radius:.75rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--line) / var(--tw-border-opacity, 1));background:rgb(var(--canvas))}.code-head{display:flex;height:2.25rem;align-items:center;justify-content:space-between;border-bottom-width:1px;border-color:rgb(var(--line) / .7);background-color:rgb(var(--raised) / .4);padding-left:.75rem;padding-right:.75rem}.code-lang{font-family:Geist Mono,JetBrains Mono,ui-monospace,SFMono-Regular,monospace;font-size:10.5px;letter-spacing:.025em;--tw-text-opacity: 1;color:rgb(var(--faint) / var(--tw-text-opacity, 1))}.code-pre{overflow-x:auto;padding:.875rem;font-family:Geist Mono,JetBrains Mono,ui-monospace,SFMono-Regular,monospace;font-size:12.5px;line-height:1.7;-moz-tab-size:2;-o-tab-size:2;tab-size:2}.code-pre code{background:transparent!important;padding:0!important;font-size:inherit!important;white-space:pre}.hljs{color:rgb(var(--ink));background:transparent}.hljs-comment,.hljs-quote{color:rgb(var(--faint));font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-literal,.hljs-type{color:rgb(var(--syn-keyword))}.hljs-string,.hljs-regexp,.hljs-addition{color:rgb(var(--syn-string))}.hljs-number,.hljs-symbol,.hljs-bullet{color:rgb(var(--syn-number))}.hljs-title,.hljs-section,.hljs-name,.hljs-selector-id,.hljs-selector-class{color:rgb(var(--syn-title))}.hljs-attr,.hljs-attribute,.hljs-variable,.hljs-template-variable,.hljs-property{color:rgb(var(--syn-attr))}.hljs-built_in,.hljs-class .hljs-title{color:rgb(var(--syn-title))}.hljs-meta,.hljs-deletion{color:rgb(var(--danger))}.thin-scroll{scrollbar-width:thin;scrollbar-color:rgb(var(--line)) transparent}.thin-scroll::-webkit-scrollbar{width:10px;height:10px}.thin-scroll::-webkit-scrollbar-track{background:transparent}.thin-scroll::-webkit-scrollbar-thumb{border:3px solid transparent;border-radius:999px;background-clip:content-box;background-color:rgb(var(--line))}.thin-scroll::-webkit-scrollbar-thumb:hover{background-color:rgb(var(--faint) / .6)}.hero-wash{background:radial-gradient(60% 50% at 50% 0%,rgb(var(--accent) / .07),transparent 70%)}.bg-dots{background-image:radial-gradient(rgb(var(--faint) / .28) 1px,transparent 1px);background-size:24px 24px;-webkit-mask-image:radial-gradient(70% 60% at 50% 30%,#000 10%,transparent 75%);mask-image:radial-gradient(70% 60% at 50% 30%,#000 10%,transparent 75%)}.ambient-blob{position:absolute;border-radius:9999px;filter:blur(64px);opacity:.35;pointer-events:none}.card-lift{transition:transform .3s cubic-bezier(.16,1,.3,1),box-shadow .3s ease,border-color .2s ease,background-color .2s ease}.card-lift:hover{transform:translateY(-2px);box-shadow:0 14px 32px -20px #0000004d;border-color:rgb(var(--faint) / .4)}@keyframes glow-pulse{0%,to{box-shadow:0 0 rgb(var(--accent) / .2)}50%{box-shadow:0 0 0 7px rgb(var(--accent) / 0)}}.composer-glow{animation:glow-pulse 1.9s ease-out infinite}.composer-shadow{box-shadow:0 1px 2px #0000000a,0 10px 30px -14px #00000024;transition:box-shadow .25s ease,border-color .25s ease}.composer-shadow:focus-within{border-color:rgb(var(--accent) / .45);box-shadow:0 0 0 4px rgb(var(--accent) / .08),0 12px 34px -14px #0000002e}.dark .composer-shadow{box-shadow:0 1px 1px #0006,0 16px 40px -16px #000000b3}.dark .composer-shadow:focus-within{box-shadow:0 0 0 4px rgb(var(--accent) / .1),0 16px 40px -16px #000000b3}.dark .card-lift:hover{box-shadow:0 14px 32px -18px #000c}.modal-panel{animation:modal-in .28s cubic-bezier(.16,1,.3,1) backwards}.modal-scrim{animation:fade .2s ease-out both}@keyframes modal-in{0%{opacity:0;transform:translateY(10px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}.stagger>*{animation:rise .6s cubic-bezier(.16,1,.3,1) both}.stagger>*:nth-child(1){animation-delay:40ms}.stagger>*:nth-child(2){animation-delay:.11s}.stagger>*:nth-child(3){animation-delay:.18s}.stagger>*:nth-child(4){animation-delay:.25s}.stagger>*:nth-child(5){animation-delay:.32s}.stagger>*:nth-child(6){animation-delay:.39s}.text-solar{background:linear-gradient(100deg,rgb(var(--ink)) 20%,rgb(var(--accent)) 120%);-webkit-background-clip:text;background-clip:text;color:transparent}.loading-bar{position:relative;overflow:hidden;background:rgb(var(--line))}.loading-bar:after{content:"";position:absolute;inset:0;width:40%;border-radius:inherit;background:linear-gradient(90deg,transparent,rgb(var(--accent)),transparent);animation:sweep 1.4s cubic-bezier(.65,0,.35,1) infinite}.splash{position:fixed;inset:0;z-index:200;display:flex;align-items:center;justify-content:center;background:rgb(var(--panel));transition:opacity .5s ease,transform .5s cubic-bezier(.16,1,.3,1),filter .5s ease}.splash.is-leaving{opacity:0;transform:scale(1.03);filter:blur(6px);pointer-events:none}.splash-sun .ray{stroke-dasharray:8;stroke-dashoffset:8;animation:draw .5s cubic-bezier(.16,1,.3,1) forwards}.splash-sun .core{transform-origin:32px 32px;animation:core-in .7s cubic-bezier(.34,1.56,.64,1) both}.splash-sun .rays{transform-origin:32px 32px;animation:spinslow 14s linear infinite}.splash-word span{display:inline-block;opacity:0;animation:blurin .7s cubic-bezier(.16,1,.3,1) forwards}@keyframes draw{to{stroke-dashoffset:0}}@keyframes core-in{0%{transform:scale(0);opacity:0}to{transform:scale(1);opacity:1}}@keyframes spinslow{to{transform:rotate(360deg)}}.md.is-streaming>:last-child:after{content:"";display:inline-block;width:7px;height:1.05em;margin-left:2px;border-radius:2px;vertical-align:-.16em;background:rgb(var(--accent));animation:caret 1.1s ease-in-out infinite}@keyframes caret{0%,to{opacity:1}50%{opacity:.15}}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-duration:.01ms!important}}.pxs-a{animation:px-a 1s steps(1) infinite}.pxs-b{animation:px-b 1s steps(1) infinite}@keyframes px-a{0%,to{opacity:1}50%{opacity:.25}}@keyframes px-b{0%,to{opacity:.25}50%{opacity:1}}.text-shimmer{background:linear-gradient(90deg,rgb(var(--muted)),rgb(var(--ink)) 45%,rgb(var(--accent)),rgb(var(--ink)) 55%,rgb(var(--muted)));background-size:250% 100%;-webkit-background-clip:text;background-clip:text;color:transparent;animation:shimmer 2.2s linear infinite}.pxs-blink,.pxs-scan{transform-box:fill-box;transform-origin:center}.pxs-blink{animation:px-blink 4.2s steps(1) infinite}.pxs-scan{animation:px-scan 1.2s steps(1) infinite}@keyframes px-blink{0%,94%,to{transform:scaleY(1)}96%{transform:scaleY(.2)}}@keyframes px-scan{0%,to{transform:translate(-1px)}33%{transform:translate(0)}66%{transform:translate(1px)}}.settings-enter>*{animation:rise .55s cubic-bezier(.16,1,.3,1) both}.settings-enter>*:nth-child(2){animation-delay:60ms}.settings-enter>*:nth-child(3){animation-delay:.12s}.settings-enter>*:nth-child(4){animation-delay:.18s}.settings-enter>*:nth-child(n+5){animation-delay:.24s}.settings-title-in{animation:blurin .55s cubic-bezier(.16,1,.3,1) both}.settings-shell{animation:shell-in .42s cubic-bezier(.16,1,.3,1) backwards}.settings-glow{background:radial-gradient(120% 100% at 0% 0%,rgb(var(--accent) / .16),transparent 65%),radial-gradient(80% 80% at 100% 0%,rgb(var(--accent) / .06),transparent 70%)}@keyframes shell-in{0%{opacity:0;transform:translateY(18px) scale(.975);filter:blur(6px)}to{opacity:1;transform:none;filter:blur(0)}}.deck-scrim{animation:fade .25s ease-out both}.deck-panel{animation:deck-in .5s cubic-bezier(.16,1,.3,1) backwards}.deck-row{animation:deck-row .4s cubic-bezier(.16,1,.3,1) backwards}.deck-pop{animation:scalein .5s cubic-bezier(.34,1.56,.64,1) both}.deck-aurora{background:radial-gradient(70% 120% at 12% 0%,rgb(var(--accent) / .18),transparent 70%),radial-gradient(50% 100% at 95% 0%,rgb(var(--accent) / .07),transparent 70%)}.deck-throttle{background-image:radial-gradient(rgb(var(--line)) 1px,transparent 1px);background-size:14px 14px;background-color:rgb(var(--canvas) / .7)}.throttle-knob{box-shadow:0 0 0 4px rgb(var(--accent) / .16),0 6px 18px -6px rgb(var(--accent) / .55)}.throttle-knob:after{content:"";position:absolute;inset:-6px;border-radius:9999px;border:1px solid rgb(var(--accent) / .5);animation:ping 2.4s cubic-bezier(0,0,.2,1) infinite}.deck-trigger:active{transform:scale(.96)}@keyframes deck-in{0%{opacity:0;transform:translateY(24px) scale(.96);filter:blur(8px)}to{opacity:1;transform:none;filter:blur(0)}}@keyframes deck-row{0%{opacity:0;transform:translate(-10px)}to{opacity:1;transform:none}}.diff-row{animation:deck-row .35s cubic-bezier(.16,1,.3,1) backwards}.diff-badge{animation:scalein .4s cubic-bezier(.34,1.56,.64,1) both}.msg-enter{animation:rise .5s cubic-bezier(.16,1,.3,1) both}button:not(:disabled){-webkit-tap-highlight-color:transparent}.chip,.nav-item,.sidebar-item{will-change:transform}.session-card:hover{transform:translate(2px)}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important;scroll-behavior:auto!important}}.placeholder\:text-faint::-moz-placeholder{--tw-text-opacity: 1;color:rgb(var(--faint) / var(--tw-text-opacity, 1))}.placeholder\:text-faint::placeholder{--tw-text-opacity: 1;color:rgb(var(--faint) / var(--tw-text-opacity, 1))}.placeholder\:text-muted::-moz-placeholder{--tw-text-opacity: 1;color:rgb(var(--muted) / var(--tw-text-opacity, 1))}.placeholder\:text-muted::placeholder{--tw-text-opacity: 1;color:rgb(var(--muted) / var(--tw-text-opacity, 1))}.focus-within\:opacity-100:focus-within{opacity:1}.hover\:border-accent\/40:hover{border-color:rgb(var(--accent) / .4)}.hover\:border-accent\/50:hover{border-color:rgb(var(--accent) / .5)}.hover\:border-faint\/50:hover{border-color:rgb(var(--faint) / .5)}.hover\:border-line:hover{--tw-border-opacity: 1;border-color:rgb(var(--line) / var(--tw-border-opacity, 1))}.hover\:border-warning\/30:hover{border-color:rgb(var(--warning) / .3)}.hover\:bg-accent\/90:hover{background-color:rgb(var(--accent) / .9)}.hover\:bg-danger\/10:hover{background-color:rgb(var(--danger) / .1)}.hover\:bg-danger\/90:hover{background-color:rgb(var(--danger) / .9)}.hover\:bg-danger\/\[0\.06\]:hover{background-color:rgb(var(--danger) / .06)}.hover\:bg-panel:hover{--tw-bg-opacity: 1;background-color:rgb(var(--panel) / var(--tw-bg-opacity, 1))}.hover\:bg-raised:hover{--tw-bg-opacity: 1;background-color:rgb(var(--raised) / var(--tw-bg-opacity, 1))}.hover\:bg-raised\/40:hover{background-color:rgb(var(--raised) / .4)}.hover\:bg-raised\/60:hover{background-color:rgb(var(--raised) / .6)}.hover\:bg-raised\/70:hover{background-color:rgb(var(--raised) / .7)}.hover\:bg-raised\/80:hover{background-color:rgb(var(--raised) / .8)}.hover\:\!text-danger:hover{--tw-text-opacity: 1 !important;color:rgb(var(--danger) / var(--tw-text-opacity, 1))!important}.hover\:text-danger:hover{--tw-text-opacity: 1;color:rgb(var(--danger) / var(--tw-text-opacity, 1))}.hover\:text-ink:hover{--tw-text-opacity: 1;color:rgb(var(--ink) / var(--tw-text-opacity, 1))}.hover\:text-warning:hover{--tw-text-opacity: 1;color:rgb(var(--warning) / var(--tw-text-opacity, 1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:decoration-ink:hover{text-decoration-color:rgb(var(--ink) / 1)}.hover\:opacity-85:hover{opacity:.85}.hover\:shadow-composer:hover{--tw-shadow: 0 1px 2px rgba(0,0,0,.04), 0 8px 28px -12px rgba(0,0,0,.12);--tw-shadow-colored: 0 1px 2px var(--tw-shadow-color), 0 8px 28px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.hover\:brightness-110:hover{--tw-brightness: brightness(1.1);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.focus\:border-accent\/50:focus{border-color:rgb(var(--accent) / .5)}.focus\:border-line:focus{--tw-border-opacity: 1;border-color:rgb(var(--line) / var(--tw-border-opacity, 1))}.focus\:bg-panel:focus{--tw-bg-opacity: 1;background-color:rgb(var(--panel) / var(--tw-bg-opacity, 1))}.focus\:opacity-100:focus{opacity:1}.focus\:shadow-\[0_0_0_3px_rgb\(var\(--accent\)\/0\.10\)\]:focus{--tw-shadow: 0 0 0 3px rgb(var(--accent)/.1);--tw-shadow-colored: 0 0 0 3px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus\:shadow-\[0_0_0_4px_rgb\(var\(--accent\)\/0\.10\)\]:focus{--tw-shadow: 0 0 0 4px rgb(var(--accent)/.1);--tw-shadow-colored: 0 0 0 4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus-visible\:opacity-100:focus-visible{opacity:1}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-accent\/50:focus-visible{--tw-ring-color: rgb(var(--accent) / .5)}.active\:scale-95:active{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.active\:scale-\[0\.985\]:active{--tw-scale-x: .985;--tw-scale-y: .985;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.active\:scale-\[0\.98\]:active{--tw-scale-x: .98;--tw-scale-y: .98;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.active\:cursor-grabbing:active{cursor:grabbing}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-35:disabled{opacity:.35}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-45:disabled{opacity:.45}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}.group\/advanced[open] .group-open\/advanced\:rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:block{display:block}.group:hover .group-hover\:flex{display:flex}.group\/item:hover .group-hover\/item\:hidden,.group:hover .group-hover\:hidden{display:none}.group\/logo:hover .group-hover\/logo\:rotate-90,.group\/new:hover .group-hover\/new\:rotate-90{--tw-rotate: 90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/ws:hover .group-hover\/ws\:-rotate-6{--tw-rotate: -6deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/tab:hover .group-hover\/tab\:scale-110,.group\/ws:hover .group-hover\/ws\:scale-110{--tw-scale-x: 1.1;--tw-scale-y: 1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/row:hover .group-hover\/row\:bg-panel{--tw-bg-opacity: 1;background-color:rgb(var(--panel) / var(--tw-bg-opacity, 1))}.group\/starter:hover .group-hover\/starter\:bg-accent-soft{--tw-bg-opacity: 1;background-color:rgb(var(--accent-soft) / var(--tw-bg-opacity, 1))}.group\/compact:hover .group-hover\/compact\:text-ink,.group\/row:hover .group-hover\/row\:text-ink{--tw-text-opacity: 1;color:rgb(var(--ink) / var(--tw-text-opacity, 1))}.group\/starter:hover .group-hover\/starter\:text-accent{--tw-text-opacity: 1;color:rgb(var(--accent) / var(--tw-text-opacity, 1))}.group\/task:hover .group-hover\/task\:text-ink,.group\/think:hover .group-hover\/think\:text-ink{--tw-text-opacity: 1;color:rgb(var(--ink) / var(--tw-text-opacity, 1))}.group\/item:hover .group-hover\/item\:opacity-100,.group\/session:hover .group-hover\/session\:opacity-100,.group\/user:hover .group-hover\/user\:opacity-100{opacity:1}.group\/ws:hover .group-hover\/ws\:opacity-0{opacity:0}.group\/ws:hover .group-hover\/ws\:opacity-100{opacity:1}.dark\:bg-black\/45:is(.dark *){background-color:#00000073}.dark\:bg-black\/60:is(.dark *){background-color:#0009}.dark\:bg-black\/65:is(.dark *){background-color:#000000a6}@media not all and (min-width:768px){.max-md\:bg-accent-soft{--tw-bg-opacity: 1;background-color:rgb(var(--accent-soft) / var(--tw-bg-opacity, 1))}}@media(min-width:640px){.sm\:bottom-48{bottom:12rem}.sm\:col-span-2{grid-column:span 2 / span 2}.sm\:mx-8{margin-left:2rem;margin-right:2rem}.sm\:ml-auto{margin-left:auto}.sm\:block{display:block}.sm\:inline{display:inline}.sm\:flex{display:flex}.sm\:inline-flex{display:inline-flex}.sm\:hidden{display:none}.sm\:h-\[min\(88dvh\,780px\)\]{height:min(88dvh,780px)}.sm\:h-\[min\(90dvh\,780px\)\]{height:min(90dvh,780px)}.sm\:max-h-\[86dvh\]{max-height:86dvh}.sm\:w-\[180px\]{width:180px}.sm\:w-\[210px\]{width:210px}.sm\:w-\[360px\]{width:360px}.sm\:w-\[420px\]{width:420px}.sm\:w-\[min\(1040px\,96vw\)\]{width:min(1040px,96vw)}.sm\:w-\[min\(1080px\,96vw\)\]{width:min(1080px,96vw)}.sm\:w-\[min\(760px\,94vw\)\]{width:min(760px,94vw)}.sm\:w-\[min\(920px\,94vw\)\]{width:min(920px,94vw)}.sm\:w-\[min\(920px\,96vw\)\]{width:min(920px,96vw)}.sm\:w-\[min\(96vw\,620px\)\]{width:min(96vw,620px)}.sm\:max-w-\[260px\]{max-width:260px}.sm\:max-w-\[82\%\]{max-width:82%}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-\[160px_1fr\]{grid-template-columns:160px 1fr}.sm\:grid-cols-\[1fr_auto\]{grid-template-columns:1fr auto}.sm\:flex-row{flex-direction:row}.sm\:items-center{align-items:center}.sm\:justify-between{justify-content:space-between}.sm\:self-auto{align-self:auto}.sm\:\!rounded-\[28px\]{border-radius:28px!important}.sm\:rounded-\[28px\]{border-radius:28px}.sm\:rounded-xl{border-radius:.75rem}.sm\:border-l{border-left-width:1px}.sm\:border-line{--tw-border-opacity: 1;border-color:rgb(var(--line) / var(--tw-border-opacity, 1))}.sm\:p-5{padding:1.25rem}.sm\:p-6{padding:1.5rem}.sm\:px-4{padding-left:1rem;padding-right:1rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:px-7{padding-left:1.75rem;padding-right:1.75rem}.sm\:px-8{padding-left:2rem;padding-right:2rem}.sm\:py-6{padding-top:1.5rem;padding-bottom:1.5rem}.sm\:pb-4{padding-bottom:1rem}.sm\:pl-0{padding-left:0}.sm\:pt-10{padding-top:2.5rem}.sm\:pt-7{padding-top:1.75rem}.sm\:pt-\[14vh\]{padding-top:14vh}.sm\:text-\[34px\]{font-size:34px}}@media(min-width:768px){.md\:block{display:block}.md\:inline{display:inline}.md\:flex{display:flex}.md\:inline-flex{display:inline-flex}.md\:hidden{display:none}.md\:h-\[280px\]{height:280px}.md\:w-\[258px\]{width:258px}.md\:w-\[300px\]{width:300px}.md\:w-\[78px\]{width:78px}.md\:min-w-0{min-width:0px}.md\:flex-row{flex-direction:row}.md\:flex-col{flex-direction:column}.md\:overflow-y-auto{overflow-y:auto}.md\:overflow-x-hidden{overflow-x:hidden}.md\:border-b-0{border-bottom-width:0px}.md\:border-l{border-left-width:1px}.md\:border-r{border-right-width:1px}.md\:border-t-0{border-top-width:0px}.md\:border-line{--tw-border-opacity: 1;border-color:rgb(var(--line) / var(--tw-border-opacity, 1))}.md\:p-2\.5{padding:.625rem}}@media(min-width:1024px){.lg\:static{position:static}.lg\:z-auto{z-index:auto}.lg\:my-1\.5{margin-top:.375rem;margin-bottom:.375rem}.lg\:mr-1\.5{margin-right:.375rem}.lg\:inline-flex{display:inline-flex}.lg\:hidden{display:none}.lg\:translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:grid-cols-\[minmax\(0\,390px\)_minmax\(0\,1fr\)\]{grid-template-columns:minmax(0,390px) minmax(0,1fr)}.lg\:overflow-hidden{overflow:hidden}.lg\:rounded-xl{border-radius:.75rem}.lg\:border{border-width:1px}.lg\:border-b-0{border-bottom-width:0px}.lg\:border-r{border-right-width:1px}.lg\:border-line{--tw-border-opacity: 1;border-color:rgb(var(--line) / var(--tw-border-opacity, 1))}.lg\:shadow-none{--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.lg\:shadow-pill{--tw-shadow: 0 1px 2px rgba(0,0,0,.06);--tw-shadow-colored: 0 1px 2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}}@media(min-width:1280px){.xl\:static{position:static}.xl\:z-auto{z-index:auto}.xl\:hidden{display:none}.xl\:max-h-\[38\%\]{max-height:38%}.xl\:w-\[390px\]{width:390px}.xl\:w-\[560px\]{width:560px}.xl\:shadow-none{--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}}.\[\&\:\:-webkit-details-marker\]\:hidden::-webkit-details-marker{display:none}
package/dist/index.html CHANGED
@@ -31,8 +31,8 @@
31
31
  if (DARK.includes(theme)) root.classList.add('dark')
32
32
  } catch {}
33
33
  </script>
34
- <script type="module" crossorigin src="./assets/index-C0yvs6Vl.js"></script>
35
- <link rel="stylesheet" crossorigin href="./assets/index-CxNPLBg7.css">
34
+ <script type="module" crossorigin src="./assets/index-CyxlAgKM.js"></script>
35
+ <link rel="stylesheet" crossorigin href="./assets/index-DFeF90S8.css">
36
36
  </head>
37
37
  <body>
38
38
  <div id="root"><div class="splash" id="boot-splash" aria-hidden="true">
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bibobonking/opensol",
3
3
  "private": false,
4
- "version": "3.1.5",
4
+ "version": "3.2.0",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "opensol": "./server/opensol.mjs"
package/server/README.md CHANGED
@@ -1,75 +1,22 @@
1
- # OpenSol
1
+ # OpenSol daemon
2
2
 
3
- A local-first AI coding agent by OpenSoftX. OpenSol pairs a warm React chat interface with a zero-dependency Node daemon that owns the real workspace, shell, git, search, deploy and provider credentials on your machine.
4
-
5
- The daemon binds to `127.0.0.1` only. It serves the prebuilt app from `dist/` and stores everything under `~/.maxcode`. API keys and hosting tokens are encrypted with AES-256-GCM using a local `master.key`; the browser only ever receives a masked hint.
6
-
7
- ## Run the built app
8
-
9
- Requires Node.js 20 or newer. No `npm install` is needed to run the built app.
10
-
11
- ```bash
12
- npm start
13
- ```
14
-
15
- `npm start` launches the daemon in the background and opens `http://127.0.0.1:4174`. Equivalent commands:
16
-
17
- ```bash
18
- node server/opensol.mjs start --open
19
- node server/opensol.mjs status
20
- node server/opensol.mjs logs
21
- node server/opensol.mjs stop
22
- ```
23
-
24
- On first launch, choose a real project folder, then add a provider key in **Settings → Models** and pick a live model. Everything else — workspace tree, editor, git, search, build/plan modes, subagents and deploys — runs through the local daemon.
25
-
26
- ## What is in the app
27
-
28
- - **Build and Plan modes.** Build can edit files and run commands; Plan is read-only investigation.
29
- - **Live models and reasoning.** Model lists come from each provider; the models.dev catalog is only a fallback. Thinking is the provider's job: an effort control appears only when the selected model advertises effort levels or a token budget, and it is sent automatically.
30
- - **Themes.** Light, Dark, Night Owl, Claude Code and Flame, plus System, which follows the OS preference. Syntax highlighting follows the theme.
31
- - **Real tools.** Read/write/edit files, grep, list files, shell, git, web search, URL reading and a read-only SubAgent. Each user turn renders as one answer, with consecutive tool rounds collapsed into a single “Used N tools” group.
32
- - **Turn queue.** A prompt sent while a turn is streaming waits its turn and runs next, instead of splitting into a second reply.
33
- - **Local plugins.** Two plugin modes:
34
- - **API v1 (sandboxed):** Install a package, review its declared workspace capabilities and HTTPS domains, preview in a sandbox, mark it Safe. Plugin code gets a restricted API (`registerCommand`, `registerPanel`, `registerTheme`, workspace read/write, HTTPS-only network to declared hosts).
35
- - **API v2 (free):** Plugin receives the full Cordis kernel context — register custom AI tools, hook into `agent/request` / `tools/execute` / `system-prompt/assemble` events, patch any app behaviour at runtime. No capability declarations needed. When removed, the Cordis fiber disposes automatically and the app returns to its original state — no source files are ever modified.
36
- The same panel builds a package from a folder you pick. Packages live under `~/.maxcode/plugins`, outside the selected workspace.
37
- - **Workspace panel.** Folder tree, file editor, git status and quick file actions.
38
- - **Deploy.** Cloudflare Pages, Netlify and Vercel, for the open workspace or another existing folder. Tokens stay in the daemon and are passed to CLIs through environment variables.
39
- - **Local history.** Conversations, settings, workspaces and encrypted keys survive restarts.
40
-
41
- Slash commands include `/search`, `/plan`, `/build`, `/new`, `/workspace`, `/deploy`, `/settings` and `/clear`.
42
-
43
- ## Development
3
+ `server/` is the local Node daemon (`127.0.0.1:4174`, no runtime dependencies besides `fflate` for plugin packages). It owns everything privileged: provider credentials, workspace files, shell, git, search, MCP connections, plugins, skills and deploys. The React app in `src/` only talks to it over `/api`.
44
4
 
45
5
  ```bash
46
- npm install
47
- npm run dev # starts the daemon and Vite on http://127.0.0.1:5173
48
- npm run build # typecheck + production build into dist/
49
- npm run typecheck
6
+ node server/opensol.mjs start --open # background daemon + browser (also: npm start)
7
+ node server/opensol.mjs status | logs | stop
8
+ node server/daemon.mjs # foreground, for debugging
50
9
  ```
51
10
 
52
- `npm run dev` proxies `/api` to the daemon on port 4174. For a production-style run, use `npm run build` followed by `npm start`.
53
-
54
- Remote models need provider access from this machine. Local providers such as Ollama are keyless but must already be running; OpenSol reports an actionable error when they are not.
55
-
56
- OpenCode free-tier models only work inside OpenCode itself, so they are hidden here. Paid OpenCode models work with an API key. Deploys require the matching CLI (`wrangler`, `netlify` or `vercel`) or `npx`, plus credentials in **Settings → Deploy**.
11
+ | File | Role |
12
+ |---|---|
13
+ | `daemon.mjs` | HTTP server, session cookie + CSRF guard, `/api` routes, static `dist/` |
14
+ | `opensol.mjs` | CLI: start, stop, status, logs, open |
15
+ | `lib/store.mjs` | data directory (`~/.opensol`, or `OPENSOL_DATA`), state, AES-256-GCM secrets |
16
+ | `lib/tools.mjs` | file, grep, git and shell tools, workspace path guard, checkpoints |
17
+ | `lib/shell.mjs` | picks bash/zsh/PowerShell/cmd per OS, kills process trees, Plan-mode allowlist |
18
+ | `lib/providers.mjs`, `lib/mcp*.mjs`, `lib/plugins.mjs`, `lib/skills.mjs`, `lib/deploy.mjs` | providers, MCP (+OAuth), plugins, skills, deploys |
57
19
 
58
- ## Data and security
20
+ Shell selection: Linux → bash; macOS → your `$SHELL` (zsh/bash) as a login shell; Windows → `pwsh`, else Windows PowerShell, else `cmd`. Set `OPENSOL_SHELL` to force one. Commands run in the workspace root with `OPENSOL=1` and `OPENSOL_WORKSPACE` set.
59
21
 
60
- - Data directory: `~/.maxcode` (override with `MAXCODE_DATA`).
61
- - `secrets.enc` and `master.key` are created with mode `600`.
62
- - All API routes require the local session cookie and a CSRF header; Host and Origin are checked.
63
- - The daemon rejects code execution outside the selected workspace except for an explicit, existing deploy folder.
64
- - No telemetry or OpenSoftX-hosted proxy. Provider requests go directly from the daemon to the provider you configured.
65
-
66
- ## Stack
67
-
68
- TypeScript, React 19, Vite, Tailwind CSS, Zustand, direct provider adapters (OpenAI, Anthropic, Gemini, OpenCode and OpenAI-compatible endpoints), and a Node HTTP daemon with no runtime dependencies.
69
-
70
- ```
71
- src/ React app, stores, agent loop, adapters and tools
72
- server/ local daemon, encrypted store, workspace tools and deploy
73
- dist/ verified production build
74
- public/ favicon
75
- ```
22
+ See the root `README.md` for the full feature list and `CLAUDE.md` for architecture notes.
package/server/daemon.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { describeShell } from './lib/shell.mjs'
1
2
  import { randomBytes } from 'node:crypto'
2
3
  import { mkdir, readFile, rm, stat, writeFile } from 'node:fs/promises'
3
4
  import http from 'node:http'
@@ -92,7 +93,7 @@ import { mcp, sanitizeServerConfig } from './lib/mcp.mjs'
92
93
 
93
94
  const HERE = path.dirname(fileURLToPath(import.meta.url))
94
95
  const DIST = path.resolve(HERE, '..', 'dist')
95
- const VERSION = '3.1.1'
96
+ const VERSION = '3.2.0'
96
97
  const SESSION_COOKIE = 'maxcode_session'
97
98
  const CSRF_HEADER = 'x-maxcode-csrf'
98
99
  const SESSION_TTL = 14 * 24 * 60 * 60 * 1000
@@ -236,6 +237,7 @@ function sanitizeSettings(patch, current = {}) {
236
237
  if (typeof source.theme === 'string' && /^[a-z0-9-]{1,64}$/.test(source.theme)) next.theme = source.theme
237
238
  if (source.mode === 'build' || source.mode === 'plan') next.mode = source.mode
238
239
  if (typeof source.aiSessionTitles === 'boolean') next.aiSessionTitles = source.aiSessionTitles
240
+ if (typeof source.showMascot === 'boolean') next.showMascot = source.showMascot
239
241
  if (source.workspacePrompts && typeof source.workspacePrompts === 'object' && !Array.isArray(source.workspacePrompts)) {
240
242
  const prompts = {}
241
243
  for (const [root, prompt] of Object.entries(source.workspacePrompts).slice(0, 300)) {
@@ -331,6 +333,9 @@ async function buildStatePayload() {
331
333
  dataDir: DATA_DIR,
332
334
  home: os.homedir(),
333
335
  platform: `${os.platform()} ${os.release()}`,
336
+ os: process.platform,
337
+ arch: os.arch(),
338
+ shell: describeShell(),
334
339
  node: process.version,
335
340
  settings: state.settings ?? {},
336
341
  chats: state.chats ?? { sessions: [], activeId: null },
@@ -1,4 +1,5 @@
1
1
  import { spawn } from 'node:child_process'
2
+ import { currentShell, killTree } from './shell.mjs'
2
3
  import { readFile, readdir, realpath, stat } from 'node:fs/promises'
3
4
  import os from 'node:os'
4
5
  import path from 'node:path'
@@ -34,7 +35,8 @@ async function commandExists(bin) {
34
35
  const direct = await runCapture(bin, ['--version'], { timeoutMs: 15_000, shell: IS_WINDOWS })
35
36
  if (direct.code === 0) return { installed: true, version: direct.stdout.split('\n')[0]?.trim() ?? '' }
36
37
  if (IS_WINDOWS) return { installed: false, version: '' }
37
- const result = await runCapture('bash', ['-lc', `command -v ${bin} >/dev/null 2>&1 && ${bin} --version`], {
38
+ const shell = currentShell()
39
+ const result = await runCapture(shell.file, shell.args(`command -v ${bin} >/dev/null 2>&1 && ${bin} --version`), {
38
40
  timeoutMs: 20_000,
39
41
  })
40
42
  return { installed: result.code === 0, version: result.stdout.split('\n')[0]?.trim() ?? '' }
@@ -61,14 +63,7 @@ function runCapture(command, args, { cwd, env, timeoutMs = 120_000, shell = fals
61
63
  detached: process.platform !== 'win32',
62
64
  shell,
63
65
  })
64
- const timer = setTimeout(() => {
65
- try {
66
- if (process.platform !== 'win32' && child.pid) process.kill(-child.pid, 'SIGKILL')
67
- else child.kill('SIGKILL')
68
- } catch {
69
- child.kill('SIGKILL')
70
- }
71
- }, timeoutMs)
66
+ const timer = setTimeout(() => killTree(child), timeoutMs)
72
67
  child.stdout.on('data', (chunk) => {
73
68
  if (stdout.length < 300_000) stdout += chunk.toString('utf8')
74
69
  })
@@ -306,7 +301,7 @@ export async function detectProject(raw) {
306
301
  async function runBuild(cwd, command, onLog, signal) {
307
302
  const result = IS_WINDOWS
308
303
  ? await runStreaming(command, [], { cwd, onLog, signal, env: { MAXCODE_DEPLOY: '1' } })
309
- : await runStreaming('/bin/bash', ['-lc', command], { cwd, onLog, signal, env: { MAXCODE_DEPLOY: '1' } })
304
+ : await runStreaming(currentShell().file, currentShell().args(command), { cwd, onLog, signal, env: { MAXCODE_DEPLOY: '1' } })
310
305
  if (result.code !== 0) {
311
306
  throw new HttpError(500, `"${command}" failed with exit code ${result.code}. Fix the error in the log, then deploy again.`, 'build_failed')
312
307
  }
@@ -0,0 +1,149 @@
1
+ // Cross-platform shell resolution for the `shell` tool and deploy builds.
2
+ // Pure helpers (resolveShell, planShellAllowed, describeShell) take injected platform/env so
3
+ // Windows and macOS behaviour is unit-tested from any OS.
4
+ import { existsSync } from 'node:fs'
5
+ import path from 'node:path'
6
+ import os from 'node:os'
7
+ import { spawn } from 'node:child_process'
8
+
9
+ const PS_PROLOGUE = '[Console]::OutputEncoding=[System.Text.Encoding]::UTF8;$ErrorActionPreference="Continue";'
10
+ // Keeps the exit code of the last native command; PowerShell otherwise reports 0.
11
+ const PS_EPILOGUE = ';if($LASTEXITCODE -is [int] -and $LASTEXITCODE -ne 0){exit $LASTEXITCODE}elseif(-not $?){exit 1}'
12
+
13
+ function platformName(platform) {
14
+ return platform === 'win32' ? 'Windows' : platform === 'darwin' ? 'macOS' : 'Linux'
15
+ }
16
+
17
+ function posixShell(id, file) {
18
+ return { id, file, family: 'posix', label: id, args: (command) => ['-lc', command] }
19
+ }
20
+
21
+ function powershell(id, file) {
22
+ return {
23
+ id,
24
+ file,
25
+ family: 'powershell',
26
+ label: id === 'pwsh' ? 'PowerShell 7' : 'PowerShell',
27
+ args: (command) => [
28
+ '-NoLogo',
29
+ '-NoProfile',
30
+ '-NonInteractive',
31
+ '-ExecutionPolicy',
32
+ 'Bypass',
33
+ '-Command',
34
+ `${PS_PROLOGUE}${command}${PS_EPILOGUE}`,
35
+ ],
36
+ }
37
+ }
38
+
39
+ function cmdShell(file) {
40
+ return { id: 'cmd', file, family: 'cmd', label: 'cmd', args: (command) => ['/d', '/s', '/c', command] }
41
+ }
42
+
43
+ function findOnPath(name, env, platform, exists) {
44
+ const sep = platform === 'win32' ? ';' : ':'
45
+ const exts = platform === 'win32' ? ['.exe', '.cmd', '.bat'] : ['']
46
+ const join = platform === 'win32' ? path.win32.join : path.posix.join
47
+ for (const dir of String(env.PATH ?? env.Path ?? '').split(sep).filter(Boolean)) {
48
+ for (const ext of exts) {
49
+ const candidate = join(dir, `${name}${ext}`)
50
+ if (exists(candidate)) return candidate
51
+ }
52
+ }
53
+ return ''
54
+ }
55
+
56
+ /** Picks the shell used to run agent commands. OPENSOL_SHELL (path or name) overrides detection. */
57
+ export function resolveShell({ platform = process.platform, env = process.env, exists = existsSync } = {}) {
58
+ const override = String(env.OPENSOL_SHELL ?? '').trim()
59
+ if (override) {
60
+ const base = path.basename(override.replace(/\\/g, '/')).toLowerCase().replace(/\.exe$/, '')
61
+ if (base === 'pwsh' || base === 'powershell') return powershell(base, override)
62
+ if (base === 'cmd') return cmdShell(override)
63
+ return posixShell(base || 'sh', override)
64
+ }
65
+
66
+ if (platform === 'win32') {
67
+ const pwsh = findOnPath('pwsh', env, platform, exists)
68
+ if (pwsh) return powershell('pwsh', pwsh)
69
+ const root = env.SystemRoot ?? env.SYSTEMROOT ?? 'C:\\Windows'
70
+ const legacy = path.win32.join(root, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe')
71
+ if (exists(legacy)) return powershell('powershell', legacy)
72
+ const onPath = findOnPath('powershell', env, platform, exists)
73
+ if (onPath) return powershell('powershell', onPath)
74
+ return cmdShell(env.ComSpec ?? env.COMSPEC ?? 'cmd.exe')
75
+ }
76
+
77
+ if (platform === 'darwin') {
78
+ const user = String(env.SHELL ?? '')
79
+ const base = path.posix.basename(user)
80
+ if ((base === 'zsh' || base === 'bash') && user && exists(user)) return posixShell(base, user)
81
+ for (const [id, file] of [['zsh', '/bin/zsh'], ['bash', '/bin/bash'], ['sh', '/bin/sh']]) {
82
+ if (exists(file)) return posixShell(id, file)
83
+ }
84
+ return posixShell('sh', '/bin/sh')
85
+ }
86
+
87
+ for (const [id, file] of [['bash', '/bin/bash'], ['bash', '/usr/bin/bash'], ['bash', '/usr/local/bin/bash']]) {
88
+ if (exists(file)) return posixShell(id, file)
89
+ }
90
+ const bash = findOnPath('bash', env, platform, exists)
91
+ if (bash) return posixShell('bash', bash)
92
+ return posixShell('sh', exists('/bin/sh') ? '/bin/sh' : 'sh')
93
+ }
94
+
95
+ let cached
96
+ export function currentShell() {
97
+ cached ??= resolveShell()
98
+ return cached
99
+ }
100
+
101
+ export function describeShell(shell = currentShell(), { platform = process.platform, arch = os.arch() } = {}) {
102
+ const system = platformName(platform)
103
+ return `${shell.label} on ${system}${platform === 'darwin' ? ` (${arch})` : ''}`
104
+ }
105
+
106
+ /** Kills a spawned command and everything it started. */
107
+ export function killTree(child) {
108
+ if (!child?.pid) return
109
+ try {
110
+ if (process.platform === 'win32') {
111
+ const killer = spawn('taskkill', ['/pid', String(child.pid), '/T', '/F'], { stdio: 'ignore', windowsHide: true })
112
+ killer.on('error', () => child.kill('SIGKILL'))
113
+ } else {
114
+ process.kill(-child.pid, 'SIGKILL')
115
+ }
116
+ } catch {
117
+ try {
118
+ child.kill('SIGKILL')
119
+ } catch {
120
+ // Already gone.
121
+ }
122
+ }
123
+ }
124
+
125
+ const GIT_READ = new Set(['status', 'diff', 'log', 'show', 'branch', 'remote', 'rev-parse', 'ls-files'])
126
+ const POSIX_READ = new Set([
127
+ 'pwd', 'ls', 'cat', 'head', 'tail', 'wc', 'grep', 'rg', 'find', 'tree', 'file', 'stat', 'du', 'df', 'date', 'whoami', 'git',
128
+ ])
129
+ const WINDOWS_READ = new Set([
130
+ 'dir', 'type', 'cd', 'where', 'where.exe', 'findstr', 'hostname', 'whoami', 'echo', 'git',
131
+ 'get-childitem', 'gci', 'ls', 'get-content', 'gc', 'cat', 'select-string', 'sls', 'get-location', 'pwd',
132
+ 'get-item', 'gi', 'test-path', 'get-date', 'get-command', 'measure-object',
133
+ ])
134
+
135
+ /**
136
+ * Plan mode runs only read-only commands. Chaining, redirection and substitution are refused
137
+ * outright so an allowlisted head cannot smuggle a second command.
138
+ */
139
+ export function planShellAllowed(command, shell = currentShell()) {
140
+ if (/[;&|><`$(){}[\]\n\r%^]/.test(command)) return false
141
+ const tokens = command.trim().split(/\s+/).filter(Boolean)
142
+ if (tokens.length === 0) return false
143
+ const windows = shell.family !== 'posix'
144
+ const head = windows ? tokens[0].toLowerCase() : tokens[0]
145
+ if (!(windows ? WINDOWS_READ : POSIX_READ).has(head)) return false
146
+ if (head === 'git' && !GIT_READ.has(tokens[1] ?? '')) return false
147
+ if (head === 'find' && tokens.some((t) => /^-(delete|exec|execdir|ok|okdir|fprint\w*|fls)$/.test(t))) return false
148
+ return true
149
+ }
@@ -0,0 +1,72 @@
1
+ import test from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import { resolveShell, planShellAllowed, describeShell } from './shell.mjs'
4
+
5
+ const has = (...files) => (file) => files.includes(file)
6
+
7
+ test('linux prefers bash with a login shell', () => {
8
+ const shell = resolveShell({ platform: 'linux', env: {}, exists: has('/bin/bash') })
9
+ assert.equal(shell.file, '/bin/bash')
10
+ assert.deepEqual(shell.args('echo hi'), ['-lc', 'echo hi'])
11
+ assert.equal(describeShell(shell, { platform: 'linux' }), 'bash on Linux')
12
+ })
13
+
14
+ test('linux falls back to sh', () => {
15
+ assert.equal(resolveShell({ platform: 'linux', env: {}, exists: () => false }).id, 'sh')
16
+ })
17
+
18
+ test('macOS uses the user zsh, else /bin/zsh', () => {
19
+ const user = resolveShell({ platform: 'darwin', env: { SHELL: '/opt/homebrew/bin/zsh' }, exists: has('/opt/homebrew/bin/zsh') })
20
+ assert.equal(user.file, '/opt/homebrew/bin/zsh')
21
+ const fallback = resolveShell({ platform: 'darwin', env: { SHELL: '/usr/bin/fish' }, exists: has('/bin/zsh', '/bin/bash') })
22
+ assert.equal(fallback.file, '/bin/zsh')
23
+ assert.equal(describeShell(fallback, { platform: 'darwin', arch: 'arm64' }), 'zsh on macOS (arm64)')
24
+ })
25
+
26
+ test('windows prefers pwsh, then Windows PowerShell, then cmd', () => {
27
+ const env = { PATH: 'C:\\Program Files\\PowerShell\\7', SystemRoot: 'C:\\Windows' }
28
+ const pwsh = resolveShell({ platform: 'win32', env, exists: has('C:\\Program Files\\PowerShell\\7\\pwsh.exe') })
29
+ assert.equal(pwsh.id, 'pwsh')
30
+ const legacy = resolveShell({
31
+ platform: 'win32',
32
+ env: { SystemRoot: 'C:\\Windows' },
33
+ exists: has('C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe'),
34
+ })
35
+ assert.equal(legacy.id, 'powershell')
36
+ const args = legacy.args('dir')
37
+ assert.ok(args.includes('-NonInteractive') && args.at(-2) === '-Command')
38
+ assert.match(args.at(-1), /dir.*exit \$LASTEXITCODE/)
39
+ const cmd = resolveShell({ platform: 'win32', env: { ComSpec: 'C:\\Windows\\System32\\cmd.exe' }, exists: () => false })
40
+ assert.equal(cmd.id, 'cmd')
41
+ assert.deepEqual(cmd.args('dir'), ['/d', '/s', '/c', 'dir'])
42
+ assert.equal(describeShell(legacy, { platform: 'win32' }), 'PowerShell on Windows')
43
+ })
44
+
45
+ test('OPENSOL_SHELL overrides detection', () => {
46
+ assert.equal(resolveShell({ platform: 'linux', env: { OPENSOL_SHELL: '/usr/bin/zsh' }, exists: () => false }).id, 'zsh')
47
+ assert.equal(resolveShell({ platform: 'linux', env: { OPENSOL_SHELL: 'pwsh' }, exists: () => false }).family, 'powershell')
48
+ })
49
+
50
+ test('plan mode allows only read-only posix commands', () => {
51
+ const sh = resolveShell({ platform: 'linux', env: {}, exists: has('/bin/bash') })
52
+ assert.equal(planShellAllowed('ls -la src', sh), true)
53
+ assert.equal(planShellAllowed('git log', sh), true)
54
+ assert.equal(planShellAllowed('git push', sh), false)
55
+ assert.equal(planShellAllowed('cat a > b', sh), false)
56
+ assert.equal(planShellAllowed('ls; rm -rf x', sh), false)
57
+ assert.equal(planShellAllowed('find . -delete', sh), false)
58
+ assert.equal(planShellAllowed('rm file', sh), false)
59
+ })
60
+
61
+ test('plan mode allows only read-only PowerShell/cmd commands', () => {
62
+ const ps = resolveShell({ platform: 'win32', env: { SystemRoot: 'C:\\Windows' }, exists: () => false })
63
+ assert.equal(ps.family, 'cmd')
64
+ assert.equal(planShellAllowed('dir src', ps), true)
65
+ assert.equal(planShellAllowed('Get-ChildItem src', ps), true)
66
+ assert.equal(planShellAllowed('Get-Content package.json', ps), true)
67
+ assert.equal(planShellAllowed('Remove-Item x', ps), false)
68
+ assert.equal(planShellAllowed('Set-Content a b', ps), false)
69
+ assert.equal(planShellAllowed('Invoke-Expression foo', ps), false)
70
+ assert.equal(planShellAllowed('type a.txt > b.txt', ps), false)
71
+ assert.equal(planShellAllowed('Get-Content a | Out-File b', ps), false)
72
+ })