@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.
- package/dist/components/Terminal.d.ts +19 -7
- package/dist/hooks/useRuntime.d.ts +2 -2
- package/dist/index.cjs +78 -82
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6303 -6477
- package/dist/index.js.map +1 -1
- package/dist/services/runtime.d.ts +1 -1
- package/dist/styles.css +1 -0
- package/dist/types.d.ts +3 -32
- package/package.json +1 -1
- package/src/components/FileTree.tsx +1 -1
- package/src/components/Terminal.tsx +217 -33
- package/src/hooks/useRuntime.ts +3 -3
- package/src/index.ts +4 -5
- package/src/services/runtime.ts +1 -1
- package/src/styles.css +103 -4
- package/src/types.ts +3 -40
- package/dist/code-sandbox.css +0 -1
- package/dist/services/git.d.ts +0 -57
- package/src/services/git.ts +0 -415
|
@@ -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
|
|
27
|
+
* - Track file modifications for diffing
|
|
28
28
|
* - Provide preview URL for the iframe
|
|
29
29
|
*/
|
|
30
30
|
export declare class NodepodRuntime {
|
package/dist/styles.css
ADDED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
@@ -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 —
|
|
2
|
+
* Terminal — Git-bash inspired terminal output panel.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
-
*
|
|
34
|
+
* Classify a line of terminal output for styling.
|
|
13
35
|
*
|
|
14
|
-
*
|
|
15
|
-
|
|
16
|
-
|
|
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
|
|
31
|
-
{
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
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
|
-
<
|
|
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>
|
package/src/hooks/useRuntime.ts
CHANGED
|
@@ -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 —
|
|
68
|
-
* imperative handle. No
|
|
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
|
|
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,
|
package/src/services/runtime.ts
CHANGED
|
@@ -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
|
|
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: #
|
|
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: #
|
|
22
|
-
--sb-warning: #
|
|
23
|
-
--sb-error: #
|
|
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
|
/*
|