@illuma-ai/code-sandbox 1.2.0 → 1.2.2

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.
@@ -24,7 +24,7 @@ type ErrorCallback = (error: SandboxError) => void;
24
24
  * - Write project files into the virtual filesystem
25
25
  * - Install npm dependencies from package.json
26
26
  * - Start the entry command (e.g., "node server.js")
27
- * - Track file modifications for git diffing
27
+ * - Track file modifications for diffing
28
28
  * - Provide preview URL for the iframe
29
29
  */
30
30
  export declare class NodepodRuntime {
@@ -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:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:Menlo,Monaco,Consolas,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,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}.container{width:100%}@media(min-width:640px){.container{max-width:640px}}@media(min-width:768px){.container{max-width:768px}}@media(min-width:1024px){.container{max-width:1024px}}@media(min-width:1280px){.container{max-width:1280px}}@media(min-width:1536px){.container{max-width:1536px}}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.right-4{right:1rem}.top-0{top:0}.top-4{top:1rem}.z-0{z-index:0}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.mx-auto{margin-left:auto;margin-right:auto}.-mb-\[1px\]{margin-bottom:-1px}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-0\.5{margin-left:.125rem}.ml-1{margin-left:.25rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mt-1{margin-top:.25rem}.mt-4{margin-top:1rem}.line-clamp-1{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.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-0\.5{height:.125rem}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-14{height:3.5rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3{height:.75rem}.h-48{height:12rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-full{height:100%}.h-screen{height:100vh}.min-h-0{min-height:0px}.min-h-\[36px\]{min-height:36px}.min-h-\[calc\(100vh-56px\)\]{min-height:calc(100vh - 56px)}.min-h-screen{min-height:100vh}.w-1\.5{width:.375rem}.w-10{width:2.5rem}.w-14{width:3.5rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-3{width:.75rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-full{width:100%}.w-screen{width:100vw}.min-w-0{min-width:0px}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-5xl{max-width:64rem}.max-w-6xl{max-width:72rem}.max-w-\[120px\]{max-width:120px}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.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 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 pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0{gap:0px}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.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))}.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))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overscroll-contain{overscroll-behavior:contain}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-t-2{border-top-width:2px}.border-none{border-style:none}.border-blue-500{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.border-gray-100{--tw-border-opacity: 1;border-color:rgb(243 244 246 / var(--tw-border-opacity, 1))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1))}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.border-gray-700{--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity, 1))}.border-sb-accent{border-color:var(--sb-accent, #007acc)}.border-sb-border{border-color:var(--sb-border, #3c3c3c)}.border-t-sb-accent{border-top-color:var(--sb-accent, #007acc)}.border-t-transparent{border-top-color:transparent}.bg-amber-100{--tw-bg-opacity: 1;background-color:rgb(254 243 199 / var(--tw-bg-opacity, 1))}.bg-amber-500{--tw-bg-opacity: 1;background-color:rgb(245 158 11 / var(--tw-bg-opacity, 1))}.bg-amber-700{--tw-bg-opacity: 1;background-color:rgb(180 83 9 / var(--tw-bg-opacity, 1))}.bg-blue-100{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.bg-blue-50{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity, 1))}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-blue-700{--tw-bg-opacity: 1;background-color:rgb(29 78 216 / var(--tw-bg-opacity, 1))}.bg-emerald-100{--tw-bg-opacity: 1;background-color:rgb(209 250 229 / var(--tw-bg-opacity, 1))}.bg-emerald-400{--tw-bg-opacity: 1;background-color:rgb(52 211 153 / var(--tw-bg-opacity, 1))}.bg-emerald-50{--tw-bg-opacity: 1;background-color:rgb(236 253 245 / var(--tw-bg-opacity, 1))}.bg-emerald-500{--tw-bg-opacity: 1;background-color:rgb(16 185 129 / var(--tw-bg-opacity, 1))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.bg-gray-300{--tw-bg-opacity: 1;background-color:rgb(209 213 219 / var(--tw-bg-opacity, 1))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.bg-gray-700{--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1))}.bg-gray-900{--tw-bg-opacity: 1;background-color:rgb(17 24 39 / var(--tw-bg-opacity, 1))}.bg-purple-100{--tw-bg-opacity: 1;background-color:rgb(243 232 255 / var(--tw-bg-opacity, 1))}.bg-red-100{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity, 1))}.bg-red-50{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity, 1))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-sb-accent{background-color:var(--sb-accent, #007acc)}.bg-sb-bg{background-color:var(--sb-bg, #1e1e1e)}.bg-sb-bg-active{background-color:var(--sb-bg-active, #37373d)}.bg-sb-bg-alt{background-color:var(--sb-bg-alt, #252526)}.bg-sb-editor{background-color:var(--sb-editor, #1e1e1e)}.bg-sb-sidebar{background-color:var(--sb-sidebar, #252526)}.bg-sb-success{background-color:var(--sb-success, #4ec9b0)}.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))}.from-blue-500{--tw-gradient-from: #3b82f6 var(--tw-gradient-from-position);--tw-gradient-to: rgb(59 130 246 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.to-purple-500{--tw-gradient-to: #a855f7 var(--tw-gradient-to-position)}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.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-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-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-20{padding-top:5rem;padding-bottom:5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.py-\[3px\]{padding-top:3px;padding-bottom:3px}.pt-2{padding-top:.5rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:Menlo,Monaco,Consolas,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-5xl{font-size:3rem;line-height:1}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[9px\]{font-size:9px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-relaxed{line-height:1.625}.tracking-tight{letter-spacing:-.025em}.tracking-wider{letter-spacing:.05em}.text-amber-700{--tw-text-opacity: 1;color:rgb(180 83 9 / var(--tw-text-opacity, 1))}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.text-blue-700{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.text-emerald-600{--tw-text-opacity: 1;color:rgb(5 150 105 / var(--tw-text-opacity, 1))}.text-emerald-700{--tw-text-opacity: 1;color:rgb(4 120 87 / var(--tw-text-opacity, 1))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity, 1))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.text-green-400{--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.text-purple-400{--tw-text-opacity: 1;color:rgb(192 132 252 / var(--tw-text-opacity, 1))}.text-purple-700{--tw-text-opacity: 1;color:rgb(126 34 206 / var(--tw-text-opacity, 1))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.text-red-700{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.text-sb-text{color:var(--sb-text, #cccccc)}.text-sb-text-active{color:var(--sb-text-active, #ffffff)}.text-sb-text-muted{color:var(--sb-text-muted, #858585)}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-400{--tw-text-opacity: 1;color:rgb(250 204 21 / var(--tw-text-opacity, 1))}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -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)}.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-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,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-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-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.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(0,0,.2,1)}:root{--sb-bg: #1e1e1e;--sb-bg-alt: #252526;--sb-bg-hover: #2a2d2e;--sb-bg-active: #37373d;--sb-sidebar: #252526;--sb-editor: #1e1e1e;--sb-terminal: #0d1117;--sb-terminal-header: #161b22;--sb-preview: #ffffff;--sb-border: #3c3c3c;--sb-text: #cccccc;--sb-text-muted: #858585;--sb-text-active: #ffffff;--sb-accent: #007acc;--sb-accent-hover: #1a8ad4;--sb-success: #3fb950;--sb-warning: #d29922;--sb-error: #f85149;--sb-info: #58a6ff;--sb-cyan: #56d4dd;--sb-magenta: #bc8cff;--sb-yellow: #e3b341;--sb-scrollbar-thumb: rgba(255, 255, 255, .12);--sb-scrollbar-thumb-hover: rgba(255, 255, 255, .25);--sb-scrollbar-track: transparent;--sb-scrollbar-width: 6px}.sb-root ::-webkit-scrollbar{width:var(--sb-scrollbar-width);height:var(--sb-scrollbar-width)}.sb-root ::-webkit-scrollbar-track{background:var(--sb-scrollbar-track)}.sb-root ::-webkit-scrollbar-thumb{background:var(--sb-scrollbar-thumb);border-radius:999px}.sb-root ::-webkit-scrollbar-thumb:hover{background:var(--sb-scrollbar-thumb-hover)}.sb-root ::-webkit-scrollbar-corner{background:transparent}.sb-root *{scrollbar-width:thin;scrollbar-color:var(--sb-scrollbar-thumb) var(--sb-scrollbar-track)}.sb-terminal-output{font-family:Cascadia Code,JetBrains Mono,Fira Code,Consolas,Monaco,Courier New,monospace;font-size:12.5px;line-height:1.6;letter-spacing:.01em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.sb-term-line{color:#c9d1d9}.sb-term-prompt{color:var(--sb-success);font-weight:600}.sb-term-cmd{color:#f0f6fc;font-weight:500}.sb-term-stderr{color:var(--sb-error)}.sb-term-success{color:var(--sb-success)}.sb-term-warning{color:var(--sb-warning)}.sb-term-info{color:var(--sb-info)}.sb-term-dim{color:#484f58}.sb-term-path{color:var(--sb-cyan)}.sb-term-pkg{color:var(--sb-magenta)}.sb-term-exit-ok{color:var(--sb-success)}.sb-term-exit-fail{color:var(--sb-error);font-weight:600}:root{--text-primary: #1a1a1a;--text-secondary: #565869;--text-tertiary: #8e8ea0;--surface-primary: #ffffff;--surface-secondary: #f9fafb;--surface-tertiary: #f3f4f6;--border-light: #e5e7eb;--border-medium: #d1d5db;--border-heavy: #9ca3af;--background: 0 0% 100%;--foreground: 0 0% 3.9%;--card: 0 0% 100%;--card-foreground: 0 0% 3.9%;--primary: 0 0% 9%;--primary-foreground: 0 0% 98%;--secondary: 0 0% 96.1%;--secondary-foreground: 0 0% 9%;--muted: 0 0% 96.1%;--muted-foreground: 0 0% 45.1%;--accent: 0 0% 96.1%;--accent-foreground: 0 0% 9%;--destructive: 0 84.2% 60.2%;--destructive-foreground: 0 0% 98%;--border: 0 0% 89.8%;--input: 0 0% 89.8%;--ring: 0 0% 3.9%;--radius: .5rem;--chart-1: 12 76% 61%;--chart-2: 173 58% 39%;--chart-3: 197 37% 24%;--chart-4: 43 74% 66%;--chart-5: 27 87% 67%}.dark{--text-primary: #f3f4f6;--text-secondary: #d1d5db;--text-tertiary: #6b7280;--surface-primary: #111827;--surface-secondary: #1f2937;--surface-tertiary: #374151;--border-light: #3a3a3b;--border-medium: #4b5563;--border-heavy: #6b7280;--background: 0 0% 7%;--foreground: 0 0% 98%;--card: 0 0% 3.9%;--card-foreground: 0 0% 98%;--primary: 0 0% 98%;--primary-foreground: 0 0% 9%;--secondary: 0 0% 14.9%;--secondary-foreground: 0 0% 98%;--muted: 0 0% 14.9%;--muted-foreground: 0 0% 63.9%;--accent: 0 0% 14.9%;--accent-foreground: 0 0% 98%;--destructive: 0 62.8% 40.6%;--destructive-foreground: 0 0% 98%;--border: 0 0% 14.9%;--input: 0 0% 14.9%;--ring: 0 0% 83.1%;--chart-1: 220 70% 50%;--chart-2: 160 60% 45%;--chart-3: 30 80% 55%;--chart-4: 280 65% 60%;--chart-5: 340 75% 55%}.hover\:bg-amber-600:hover{--tw-bg-opacity: 1;background-color:rgb(217 119 6 / var(--tw-bg-opacity, 1))}.hover\:bg-blue-600:hover{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-50:hover{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-600:hover{--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity, 1))}.hover\:bg-sb-bg-hover:hover{background-color:var(--sb-bg-hover, #2a2d2e)}.hover\:text-blue-700:hover{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.hover\:text-gray-800:hover{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity, 1))}.hover\:text-red-600:hover{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.hover\:text-sb-text:hover{color:var(--sb-text, #cccccc)}.hover\:text-sb-text-active:hover{color:var(--sb-text-active, #ffffff)}.focus\:border-transparent:focus{border-color:transparent}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--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)}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:opacity-100{opacity:1}@media(min-width:640px){.sm\:block{display:block}.sm\:flex{display:flex}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:text-5xl{font-size:3rem;line-height:1}}@media(min-width:1024px){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}:root{--separator-border: rgba(128, 128, 128, .35);--sash-hover-transition-duration: .1s}.allotment-module_splitView__L-yRc{height:100%;overflow:hidden;position:relative;width:100%}.allotment-module_splitView__L-yRc>.allotment-module_sashContainer__fzwJF{height:100%;pointer-events:none;position:absolute;width:100%}.allotment-module_splitView__L-yRc>.allotment-module_sashContainer__fzwJF>.allotment-module_sash__QA-2t{pointer-events:auto}.allotment-module_splitView__L-yRc>.allotment-module_splitViewContainer__rQnVa{height:100%;position:relative;white-space:nowrap;width:100%}.allotment-module_splitView__L-yRc>.allotment-module_splitViewContainer__rQnVa>.allotment-module_splitViewView__MGZ6O{overflow:hidden;position:absolute;white-space:initial}.allotment-module_splitView__L-yRc.allotment-module_vertical__WSwwa>.allotment-module_splitViewContainer__rQnVa>.allotment-module_splitViewView__MGZ6O{width:100%}.allotment-module_splitView__L-yRc.allotment-module_horizontal__7doS8>.allotment-module_splitViewContainer__rQnVa>.allotment-module_splitViewView__MGZ6O{height:100%}.allotment-module_splitView__L-yRc.allotment-module_separatorBorder__x-rDS>.allotment-module_splitViewContainer__rQnVa>.allotment-module_splitViewView__MGZ6O:not(:first-child):before{background-color:var(--separator-border);content:" ";left:0;pointer-events:none;position:absolute;top:0;z-index:5}.allotment-module_splitView__L-yRc.allotment-module_separatorBorder__x-rDS.allotment-module_vertical__WSwwa>.allotment-module_splitViewContainer__rQnVa>.allotment-module_splitViewView__MGZ6O:not(:first-child):before{height:1px;width:100%}.allotment-module_splitView__L-yRc.allotment-module_separatorBorder__x-rDS.allotment-module_horizontal__7doS8>.allotment-module_splitViewContainer__rQnVa>.allotment-module_splitViewView__MGZ6O:not(:first-child):before{height:100%;width:1px}:root{--focus-border: #007fd4;--sash-size: 8px;--sash-hover-size: 4px}.sash-module_sash__K-9lB{position:absolute;z-index:35;touch-action:none;pointer-events:auto;text-align:initial}.sash-module_sash__K-9lB.sash-module_disabled__Hm-wx{pointer-events:none}.sash-module_sash__K-9lB.sash-module_mac__Jf6OJ.sash-module_vertical__pB-rs{cursor:col-resize}.sash-module_sash__K-9lB.sash-module_vertical__pB-rs.sash-module_minimum__-UKxp{cursor:e-resize}.sash-module_sash__K-9lB.sash-module_vertical__pB-rs.sash-module_maximum__TCWxD{cursor:w-resize}.sash-module_sash__K-9lB.sash-module_mac__Jf6OJ.sash-module_horizontal__kFbiw{cursor:row-resize}.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw.sash-module_minimum__-UKxp{cursor:s-resize}.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw.sash-module_maximum__TCWxD{cursor:n-resize}.sash-module_sash__K-9lB.sash-module_disabled__Hm-wx{cursor:default!important;pointer-events:none!important}.sash-module_sash__K-9lB.sash-module_vertical__pB-rs{cursor:ew-resize;top:0;width:var(--sash-size);height:100%}.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw{cursor:ns-resize;left:0;width:100%;height:var(--sash-size)}.sash-module_sash__K-9lB:not(.sash-module_disabled__Hm-wx)>.sash-module_orthogonal-drag-handle__Yii2-{content:" ";height:calc(var(--sash-size) * 2);width:calc(var(--sash-size) * 2);z-index:100;display:block;cursor:all-scroll;position:absolute}.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw.sash-module_orthogonal-edge-north__f7Noe:not(.sash-module_disabled__Hm-wx)>.sash-module_orthogonal-drag-handle__Yii2-.sash-module_start__uZEDk,.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw.sash-module_orthogonal-edge-south__6ZrFC:not(.sash-module_disabled__Hm-wx)>.sash-module_orthogonal-drag-handle__Yii2-.sash-module_end__0TP-R{cursor:nwse-resize}.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw.sash-module_orthogonal-edge-north__f7Noe:not(.sash-module_disabled__Hm-wx)>.sash-module_orthogonal-drag-handle__Yii2-.sash-module_end__0TP-R,.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw.sash-module_orthogonal-edge-south__6ZrFC:not(.sash-module_disabled__Hm-wx)>.sash-module_orthogonal-drag-handle__Yii2-.sash-module_start__uZEDk{cursor:nesw-resize}.sash-module_sash__K-9lB.sash-module_vertical__pB-rs>.sash-module_orthogonal-drag-handle__Yii2-.sash-module_start__uZEDk{left:calc(var(--sash-size) * -.5);top:calc(var(--sash-size) * -1)}.sash-module_sash__K-9lB.sash-module_vertical__pB-rs>.sash-module_orthogonal-drag-handle__Yii2-.sash-module_end__0TP-R{left:calc(var(--sash-size) * -.5);bottom:calc(var(--sash-size) * -1)}.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw>.sash-module_orthogonal-drag-handle__Yii2-.sash-module_start__uZEDk{top:calc(var(--sash-size) * -.5);left:calc(var(--sash-size) * -1)}.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw>.sash-module_orthogonal-drag-handle__Yii2-.sash-module_end__0TP-R{top:calc(var(--sash-size) * -.5);right:calc(var(--sash-size) * -1)}.sash-module_sash__K-9lB:before{content:"";pointer-events:none;position:absolute;width:100%;height:100%;transition:background-color var(--sash-hover-transition-duration) ease-out;background:transparent}.sash-module_sash__K-9lB.sash-module_vertical__pB-rs:before{width:var(--sash-hover-size);left:calc(50% - (var(--sash-hover-size) / 2))}.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw:before{height:var(--sash-hover-size);top:calc(50% - (var(--sash-hover-size) / 2))}.sash-module_sash__K-9lB.sash-module_hover__80W6I:before,.sash-module_sash__K-9lB.sash-module_active__bJspD:before{background:var(--focus-border)}
package/dist/types.d.ts CHANGED
@@ -123,35 +123,6 @@ export interface RuntimeState {
123
123
  */
124
124
  errors: SandboxError[];
125
125
  }
126
- export interface GitHubRepo {
127
- owner: string;
128
- repo: string;
129
- branch?: string;
130
- path?: string;
131
- }
132
- export interface GitCommitRequest {
133
- owner: string;
134
- repo: string;
135
- /** Branch to create for the commit */
136
- branch: string;
137
- /** Base branch to fork from (default: 'main') */
138
- baseBranch?: string;
139
- /** Map of file paths to new contents (only changed files) */
140
- changes: FileMap;
141
- /** Commit message */
142
- message: string;
143
- }
144
- export interface GitPRRequest extends GitCommitRequest {
145
- /** PR title */
146
- title: string;
147
- /** PR body/description */
148
- body?: string;
149
- }
150
- export interface GitPRResult {
151
- number: number;
152
- url: string;
153
- branch: string;
154
- }
155
126
  /**
156
127
  * Imperative handle exposed by CodeSandbox via React.forwardRef.
157
128
  *
@@ -163,7 +134,7 @@ export interface GitPRResult {
163
134
  * ```tsx
164
135
  * const ref = useRef<CodeSandboxHandle>(null);
165
136
  *
166
- * // Push files from any source (GitHub, DB, S3, agent output)
137
+ * // Push files from any source
167
138
  * ref.current?.updateFiles(fileMap);
168
139
  *
169
140
  * // Push a single file (e.g., agent modified one file)
@@ -230,7 +201,7 @@ export interface CodeSandboxHandle {
230
201
  *
231
202
  * The sandbox is a pure renderer — it receives files via props and
232
203
  * exposes an imperative handle for programmatic updates. It does NOT
233
- * interact with any storage backend (GitHub, S3, DB) directly.
204
+ * interact with any storage backend directly.
234
205
  *
235
206
  * File sources (for initial load, pick ONE):
236
207
  * - `files` — pass a FileMap directly
@@ -245,7 +216,7 @@ export interface CodeSandboxHandle {
245
216
  * ```
246
217
  */
247
218
  export interface CodeSandboxProps {
248
- /** Pass files directly (from any source — GitHub, DB, S3, agent, etc.) */
219
+ /** Pass files directly (from any source) */
249
220
  files?: FileMap;
250
221
  /** OR use a built-in template name */
251
222
  template?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@illuma-ai/code-sandbox",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "type": "module",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Illuma AI (https://github.com/illuma-ai)",
@@ -231,7 +231,7 @@ export function FileTree({
231
231
  fileChanges,
232
232
  }: FileTreeProps) {
233
233
  return (
234
- <div className="h-full overflow-auto bg-sb-sidebar text-sm select-none">
234
+ <div className="h-full overflow-auto bg-sb-sidebar text-sm select-none overscroll-contain">
235
235
  <div className="px-3 py-2 text-[11px] font-semibold text-sb-text-muted uppercase tracking-wider border-b border-sb-border">
236
236
  Explorer
237
237
  </div>
@@ -1,19 +1,189 @@
1
1
  /**
2
- * Terminal — Display terminal output from Nodepod processes.
2
+ * Terminal — Git-bash inspired terminal output panel.
3
3
  *
4
- * Simple scrolling output panel styled like a terminal.
5
- * Auto-scrolls to the bottom as new output arrives.
4
+ * Renders process stdout/stderr with color-coded output:
5
+ * - Commands ($ ...) get a green prompt + white command
6
+ * - stderr lines get red text
7
+ * - Success markers (checkmarks) get green
8
+ * - Warnings get yellow
9
+ * - Package names get purple
10
+ * - URLs and paths get cyan
11
+ * - Exit codes get colored by status
12
+ *
13
+ * Uses a simple div-based approach (not xterm.js) to keep the bundle lean.
14
+ * Auto-scrolls to bottom as new output arrives.
6
15
  */
7
16
 
8
17
  import React, { useEffect, useRef } from "react";
9
18
  import type { TerminalProps } from "../types";
10
19
 
20
+ /** Classify a terminal output line for color coding */
21
+ type LineType =
22
+ | "prompt" // $ command
23
+ | "stderr" // [stderr] ...
24
+ | "success" // ✓ ...
25
+ | "error" // ✗ ... or error messages
26
+ | "warning" // warn / Warning
27
+ | "info" // Installing, Dependencies, info lines
28
+ | "exit-ok" // Process exited with code 0
29
+ | "exit-fail" // Process exited with non-zero code
30
+ | "dim" // Empty or separator lines
31
+ | "normal"; // Default output
32
+
11
33
  /**
12
- * Terminal component renders process stdout/stderr in a terminal-style panel.
34
+ * Classify a line of terminal output for styling.
13
35
  *
14
- * Uses a simple div-based approach (not xterm.js) for the initial version.
15
- * This keeps the bundle small and avoids the xterm peer dependency
16
- * for consumers who don't need full terminal emulation.
36
+ * Pattern matching order matters more specific patterns first.
37
+ */
38
+ function classifyLine(line: string): LineType {
39
+ const trimmed = line.trim();
40
+
41
+ // Empty or whitespace-only
42
+ if (!trimmed) return "dim";
43
+
44
+ // Explicit stderr prefix from runtime
45
+ if (trimmed.startsWith("[stderr]")) return "stderr";
46
+
47
+ // Command prompt ($ node server.js)
48
+ if (/^\$\s/.test(trimmed)) return "prompt";
49
+
50
+ // Success indicators
51
+ if (/^\s*✓/.test(line) || /^\s*✔/.test(line) || /^done$/i.test(trimmed))
52
+ return "success";
53
+
54
+ // Error indicators
55
+ if (
56
+ /^\s*✗/.test(line) ||
57
+ /^\s*✘/.test(line) ||
58
+ /^error\b/i.test(trimmed) ||
59
+ /^Error:/i.test(trimmed) ||
60
+ /^TypeError:/i.test(trimmed) ||
61
+ /^ReferenceError:/i.test(trimmed) ||
62
+ /^SyntaxError:/i.test(trimmed) ||
63
+ /ENOENT|EACCES|ECONNREFUSED/i.test(trimmed)
64
+ )
65
+ return "error";
66
+
67
+ // Process exit
68
+ if (/^Process exited with code\s+(\d+)/.test(trimmed)) {
69
+ const code = trimmed.match(/code\s+(\d+)/)?.[1];
70
+ return code === "0" ? "exit-ok" : "exit-fail";
71
+ }
72
+
73
+ // Warning
74
+ if (
75
+ /^warn\b/i.test(trimmed) ||
76
+ /^warning\b/i.test(trimmed) ||
77
+ /^Warning:/i.test(trimmed) ||
78
+ /deprecated/i.test(trimmed)
79
+ )
80
+ return "warning";
81
+
82
+ // Info / install progress
83
+ if (
84
+ /^Installing\b/i.test(trimmed) ||
85
+ /^Dependencies\s+installed/i.test(trimmed) ||
86
+ /^Listening\b/i.test(trimmed) ||
87
+ /^Server\s+(running|started|listening)/i.test(trimmed) ||
88
+ /^Starting\b/i.test(trimmed)
89
+ )
90
+ return "info";
91
+
92
+ return "normal";
93
+ }
94
+
95
+ /** CSS class name for each line type */
96
+ const LINE_CLASS: Record<LineType, string> = {
97
+ prompt: "", // handled specially (split into prompt + command)
98
+ stderr: "sb-term-stderr",
99
+ success: "sb-term-success",
100
+ error: "sb-term-stderr",
101
+ warning: "sb-term-warning",
102
+ info: "sb-term-info",
103
+ "exit-ok": "sb-term-exit-ok",
104
+ "exit-fail": "sb-term-exit-fail",
105
+ dim: "sb-term-dim",
106
+ normal: "sb-term-line",
107
+ };
108
+
109
+ /**
110
+ * Render a single terminal line with appropriate styling.
111
+ *
112
+ * Prompt lines are split into a green "$ " prefix and white command text.
113
+ * Stderr lines strip the "[stderr]" prefix and show in red.
114
+ * Package install lines highlight the package name in purple.
115
+ */
116
+ function TerminalLine({ line }: { line: string }) {
117
+ const type = classifyLine(line);
118
+
119
+ // Prompt line: split into green prompt + white command
120
+ if (type === "prompt") {
121
+ const commandText = line.replace(/^\$\s*/, "");
122
+ return (
123
+ <div className="whitespace-pre-wrap">
124
+ <span className="sb-term-prompt">{"$ "}</span>
125
+ <span className="sb-term-cmd">{commandText}</span>
126
+ </div>
127
+ );
128
+ }
129
+
130
+ // Stderr: strip prefix, show in red
131
+ if (type === "stderr") {
132
+ const message = line.replace(/^\[stderr\]\s*/, "");
133
+ return (
134
+ <div className="whitespace-pre-wrap sb-term-stderr">
135
+ <span className="sb-term-dim select-none">{"stderr "}</span>
136
+ {message}
137
+ </div>
138
+ );
139
+ }
140
+
141
+ // Package install success: " ✓ express@4.18.0" → green check + purple pkg
142
+ if (type === "success" && /✓\s+\S+@/.test(line)) {
143
+ const match = line.match(/(.*✓\s*)(\S+@\S+)(.*)/);
144
+ if (match) {
145
+ return (
146
+ <div className="whitespace-pre-wrap sb-term-success">
147
+ {match[1]}
148
+ <span className="sb-term-pkg">{match[2]}</span>
149
+ {match[3]}
150
+ </div>
151
+ );
152
+ }
153
+ }
154
+
155
+ // Info lines with port numbers: highlight the port
156
+ if (type === "info" && /:\d{4}/.test(line)) {
157
+ const parts = line.split(/(:\d{4,5})/);
158
+ return (
159
+ <div className="whitespace-pre-wrap sb-term-info">
160
+ {parts.map((part, i) =>
161
+ /^:\d{4,5}$/.test(part) ? (
162
+ <span key={i} className="sb-term-path">
163
+ {part}
164
+ </span>
165
+ ) : (
166
+ <span key={i}>{part}</span>
167
+ ),
168
+ )}
169
+ </div>
170
+ );
171
+ }
172
+
173
+ return (
174
+ <div className={`whitespace-pre-wrap ${LINE_CLASS[type]}`}>{line}</div>
175
+ );
176
+ }
177
+
178
+ /**
179
+ * Terminal component — renders process output in a git-bash inspired panel.
180
+ *
181
+ * Features:
182
+ * - Color-coded output (commands, errors, warnings, info, packages)
183
+ * - Monospace font stack (Cascadia Code → JetBrains Mono → Fira Code → fallback)
184
+ * - Auto-scroll to bottom on new output
185
+ * - Modern thin scrollbar matching the sandbox theme
186
+ * - Dark background separate from editor for visual distinction
17
187
  */
18
188
  export function Terminal({ output, className = "" }: TerminalProps) {
19
189
  const containerRef = useRef<HTMLDivElement>(null);
@@ -27,40 +197,54 @@ export function Terminal({ output, className = "" }: TerminalProps) {
27
197
  }, [output.length]);
28
198
 
29
199
  return (
30
- <div className={`flex flex-col h-full bg-sb-terminal ${className}`}>
31
- {/* Header */}
32
- <div className="flex items-center px-3 py-1 bg-sb-bg-alt border-b border-sb-border">
33
- <span className="text-xs font-medium text-sb-text-muted uppercase tracking-wider">
34
- Terminal
200
+ <div
201
+ className={`flex flex-col h-full ${className}`}
202
+ style={{ background: "var(--sb-terminal)" }}
203
+ >
204
+ {/* Header — styled like a real terminal tab bar */}
205
+ <div
206
+ className="flex items-center gap-2 px-3 py-1.5 border-b border-sb-border shrink-0"
207
+ style={{ background: "var(--sb-terminal-header)" }}
208
+ >
209
+ {/* Traffic light dots (decorative) */}
210
+ <div className="flex items-center gap-1.5 mr-1">
211
+ <span
212
+ className="w-2.5 h-2.5 rounded-full"
213
+ style={{ background: "#f85149" }}
214
+ />
215
+ <span
216
+ className="w-2.5 h-2.5 rounded-full"
217
+ style={{ background: "#d29922" }}
218
+ />
219
+ <span
220
+ className="w-2.5 h-2.5 rounded-full"
221
+ style={{ background: "#3fb950" }}
222
+ />
223
+ </div>
224
+ <span
225
+ className="text-[11px] font-medium tracking-wider"
226
+ style={{ color: "var(--sb-text-muted)" }}
227
+ >
228
+ TERMINAL
229
+ </span>
230
+ {/* Shell indicator */}
231
+ <span className="text-[10px] ml-auto" style={{ color: "#484f58" }}>
232
+ bash
35
233
  </span>
36
234
  </div>
37
235
 
38
- {/* Output */}
236
+ {/* Output area */}
39
237
  <div
40
238
  ref={containerRef}
41
- className="flex-1 overflow-auto p-3 font-mono text-xs leading-relaxed"
239
+ className="flex-1 overflow-auto px-3.5 py-2.5 sb-terminal-output overscroll-contain"
42
240
  >
43
241
  {output.length === 0 ? (
44
- <span className="text-sb-text-muted">Waiting for output...</span>
242
+ <div className="flex items-center gap-2 sb-term-dim">
243
+ <span className="sb-term-prompt">$</span>
244
+ <span className="animate-pulse">_</span>
245
+ </div>
45
246
  ) : (
46
- output.map((line, i) => (
47
- <div
48
- key={i}
49
- className={`whitespace-pre-wrap ${
50
- line.startsWith("[stderr]")
51
- ? "text-sb-error"
52
- : line.startsWith("$")
53
- ? "text-sb-success"
54
- : line.startsWith(" ✓")
55
- ? "text-sb-success"
56
- : line.startsWith(" ✗")
57
- ? "text-sb-error"
58
- : "text-sb-text"
59
- }`}
60
- >
61
- {line}
62
- </div>
63
- ))
247
+ output.map((line, i) => <TerminalLine key={i} line={line} />)
64
248
  )}
65
249
  </div>
66
250
  </div>
@@ -64,8 +64,8 @@ function computeFileChanges(
64
64
  /**
65
65
  * Hook that manages the full Nodepod runtime lifecycle.
66
66
  *
67
- * The sandbox is a pure renderer — files come in via props or the
68
- * imperative handle. No GitHub, no polling, no storage backends.
67
+ * The sandbox is a pure renderer — it receives files via props or the
68
+ * imperative handle. No polling, no storage backends.
69
69
  *
70
70
  * @param props - CodeSandbox component props
71
71
  * @returns Reactive runtime state + control functions + imperative methods
@@ -301,7 +301,7 @@ export function useRuntime(props: CodeSandboxProps) {
301
301
  *
302
302
  * Called by the imperative handle's updateFiles() method.
303
303
  * Also usable as the initial boot path when files arrive asynchronously
304
- * (e.g., host fetches from GitHub/DB/S3, then calls updateFiles).
304
+ * (e.g., host fetches from a remote source, then calls updateFiles).
305
305
  */
306
306
  const updateFiles = useCallback(
307
307
  async (newFiles: FileMap, options?: { restartServer?: boolean }) => {
package/src/index.ts CHANGED
@@ -5,6 +5,10 @@
5
5
  * Consumers import from here.
6
6
  */
7
7
 
8
+ // Styles — imported here so Vite extracts them into the library CSS bundle.
9
+ // Consumers must import: import "@illuma-ai/code-sandbox/styles.css";
10
+ import "./styles.css";
11
+
8
12
  // Main component
9
13
  export { CodeSandbox } from "./components/Workbench";
10
14
 
@@ -19,7 +23,6 @@ export type { WorkbenchView } from "./components/ViewSlider";
19
23
 
20
24
  // Services
21
25
  export { NodepodRuntime } from "./services/runtime";
22
- export { GitService } from "./services/git";
23
26
 
24
27
  // Hooks
25
28
  export { useRuntime } from "./hooks/useRuntime";
@@ -38,10 +41,6 @@ export type {
38
41
  BootProgress,
39
42
  RuntimeConfig,
40
43
  RuntimeState,
41
- GitHubRepo,
42
- GitCommitRequest,
43
- GitPRRequest,
44
- GitPRResult,
45
44
  CodeSandboxProps,
46
45
  CodeSandboxHandle,
47
46
  FileTreeProps,
@@ -38,7 +38,7 @@ const DBG = "[CodeSandbox:Runtime]";
38
38
  * - Write project files into the virtual filesystem
39
39
  * - Install npm dependencies from package.json
40
40
  * - Start the entry command (e.g., "node server.js")
41
- * - Track file modifications for git diffing
41
+ * - Track file modifications for diffing
42
42
  * - Provide preview URL for the iframe
43
43
  */
44
44
  export class NodepodRuntime {
package/src/styles.css CHANGED
@@ -10,7 +10,8 @@
10
10
  --sb-bg-active: #37373d;
11
11
  --sb-sidebar: #252526;
12
12
  --sb-editor: #1e1e1e;
13
- --sb-terminal: #1e1e1e;
13
+ --sb-terminal: #0d1117;
14
+ --sb-terminal-header: #161b22;
14
15
  --sb-preview: #ffffff;
15
16
  --sb-border: #3c3c3c;
16
17
  --sb-text: #cccccc;
@@ -18,9 +19,107 @@
18
19
  --sb-text-active: #ffffff;
19
20
  --sb-accent: #007acc;
20
21
  --sb-accent-hover: #1a8ad4;
21
- --sb-success: #4ec9b0;
22
- --sb-warning: #cca700;
23
- --sb-error: #f44747;
22
+ --sb-success: #3fb950;
23
+ --sb-warning: #d29922;
24
+ --sb-error: #f85149;
25
+ --sb-info: #58a6ff;
26
+ --sb-cyan: #56d4dd;
27
+ --sb-magenta: #bc8cff;
28
+ --sb-yellow: #e3b341;
29
+ --sb-scrollbar-thumb: rgba(255, 255, 255, 0.12);
30
+ --sb-scrollbar-thumb-hover: rgba(255, 255, 255, 0.25);
31
+ --sb-scrollbar-track: transparent;
32
+ --sb-scrollbar-width: 6px;
33
+ }
34
+
35
+ /* ---------------------------------------------------------------------------
36
+ * Modern thin scrollbars — applies to ALL scrollable elements in sandbox
37
+ * Auto-hides via opacity transition. Themed with CSS vars.
38
+ * --------------------------------------------------------------------------- */
39
+
40
+ /* Webkit (Chrome, Safari, Edge) */
41
+ .sb-root ::-webkit-scrollbar {
42
+ width: var(--sb-scrollbar-width);
43
+ height: var(--sb-scrollbar-width);
44
+ }
45
+
46
+ .sb-root ::-webkit-scrollbar-track {
47
+ background: var(--sb-scrollbar-track);
48
+ }
49
+
50
+ .sb-root ::-webkit-scrollbar-thumb {
51
+ background: var(--sb-scrollbar-thumb);
52
+ border-radius: 999px;
53
+ }
54
+
55
+ .sb-root ::-webkit-scrollbar-thumb:hover {
56
+ background: var(--sb-scrollbar-thumb-hover);
57
+ }
58
+
59
+ .sb-root ::-webkit-scrollbar-corner {
60
+ background: transparent;
61
+ }
62
+
63
+ /* Firefox */
64
+ .sb-root * {
65
+ scrollbar-width: thin;
66
+ scrollbar-color: var(--sb-scrollbar-thumb) var(--sb-scrollbar-track);
67
+ }
68
+
69
+ /* ---------------------------------------------------------------------------
70
+ * Terminal theme — git-bash inspired colors and styling
71
+ * --------------------------------------------------------------------------- */
72
+
73
+ .sb-terminal-output {
74
+ font-family:
75
+ "Cascadia Code", "JetBrains Mono", "Fira Code", "Consolas", "Monaco",
76
+ "Courier New", monospace;
77
+ font-size: 12.5px;
78
+ line-height: 1.6;
79
+ letter-spacing: 0.01em;
80
+ -webkit-font-smoothing: antialiased;
81
+ -moz-osx-font-smoothing: grayscale;
82
+ }
83
+
84
+ /* Terminal line colors via data attribute */
85
+ .sb-term-line {
86
+ color: #c9d1d9;
87
+ }
88
+ .sb-term-prompt {
89
+ color: var(--sb-success);
90
+ font-weight: 600;
91
+ }
92
+ .sb-term-cmd {
93
+ color: #f0f6fc;
94
+ font-weight: 500;
95
+ }
96
+ .sb-term-stderr {
97
+ color: var(--sb-error);
98
+ }
99
+ .sb-term-success {
100
+ color: var(--sb-success);
101
+ }
102
+ .sb-term-warning {
103
+ color: var(--sb-warning);
104
+ }
105
+ .sb-term-info {
106
+ color: var(--sb-info);
107
+ }
108
+ .sb-term-dim {
109
+ color: #484f58;
110
+ }
111
+ .sb-term-path {
112
+ color: var(--sb-cyan);
113
+ }
114
+ .sb-term-pkg {
115
+ color: var(--sb-magenta);
116
+ }
117
+ .sb-term-exit-ok {
118
+ color: var(--sb-success);
119
+ }
120
+ .sb-term-exit-fail {
121
+ color: var(--sb-error);
122
+ font-weight: 600;
24
123
  }
25
124
 
26
125
  /*