opencode-pixel-office 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,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}:root{--background: 206 60% 94%;--foreground: 200 15% 28%;--card: 0 0% 100%;--card-foreground: 200 15% 28%;--primary: 217 73% 65%;--primary-foreground: 0 0% 100%;--secondary: 200 8% 90%;--secondary-foreground: 200 15% 28%;--muted: 204 30% 90%;--muted-foreground: 215 20% 45%;--accent: 188 95% 75%;--accent-foreground: 200 15% 28%;--destructive: 349 61% 55%;--destructive-foreground: 0 0% 100%;--border: 217 73% 65%;--input: 217 73% 65%;--ring: 217 73% 65%;--radius: 0px;--retro-light: #ffffff;--retro-shadow: #3d5052;--retro-mid: #6296e8}*{border-color:hsl(var(--border))}body{background-color:hsl(var(--background));color:hsl(var(--foreground));background-color:#e5f2fb;background-image:linear-gradient(#12101000 50%,#0000000d 50%),linear-gradient(90deg,#ff000008,#00ff0003,#0000ff08);background-size:100% 4px,6px 100%;font-family:Inter,system-ui,sans-serif}.static{position:static}.absolute{position:absolute}.relative{position:relative}.right-0{right:0}.top-8{top:2rem}.z-50{z-index:50}.col-span-2{grid-column:span 2 / span 2}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-8{height:2rem}.h-9{height:2.25rem}.max-h-\[220px\]{max-height:220px}.max-h-\[300px\]{max-height:300px}.w-1\.5{width:.375rem}.w-10{width:2.5rem}.w-9{width:2.25rem}.w-full{width:100%}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.cursor-pointer{cursor:pointer}.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}.items-baseline{align-items:baseline}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-amber-700\/30{border-color:#b453094d}.border-emerald-900\/50{border-color:#064e3b80}.border-foreground{border-color:hsl(var(--foreground))}.border-input{border-color:hsl(var(--input))}.border-slate-600{--tw-border-opacity: 1;border-color:rgb(71 85 105 / var(--tw-border-opacity, 1))}.border-slate-700{--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity, 1))}.border-slate-700\/50{border-color:#33415580}.border-transparent{border-color:transparent}.border-white\/20{border-color:#fff3}.bg-\[\#101615\]{--tw-bg-opacity: 1;background-color:rgb(16 22 21 / var(--tw-bg-opacity, 1))}.bg-amber-200\/50{background-color:#fde68a80}.bg-background{background-color:hsl(var(--background))}.bg-card{background-color:hsl(var(--card))}.bg-destructive{background-color:hsl(var(--destructive))}.bg-emerald-400{--tw-bg-opacity: 1;background-color:rgb(52 211 153 / var(--tw-bg-opacity, 1))}.bg-emerald-900\/30{background-color:#064e3b4d}.bg-emerald-950\/30{background-color:#022c224d}.bg-primary{background-color:hsl(var(--primary))}.bg-red-900\/30{background-color:#7f1d1d4d}.bg-secondary{background-color:hsl(var(--secondary))}.bg-slate-800{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity, 1))}.bg-slate-900{--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity, 1))}.bg-slate-900\/50{background-color:#0f172a80}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.pr-1{padding-right:.25rem}.pt-0{padding-top:0}.pt-1{padding-top:.25rem}.pt-2{padding-top:.5rem}.pt-4{padding-top:1rem}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[10px\]{font-size:10px}.text-\[8px\]{font-size:8px}.text-\[9px\]{font-size:9px}.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-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-snug{line-height:1.375}.tracking-tight{letter-spacing:-.025em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-amber-400{--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.text-amber-500{--tw-text-opacity: 1;color:rgb(245 158 11 / var(--tw-text-opacity, 1))}.text-card-foreground{color:hsl(var(--card-foreground))}.text-destructive-foreground{color:hsl(var(--destructive-foreground))}.text-emerald-400{--tw-text-opacity: 1;color:rgb(52 211 153 / var(--tw-text-opacity, 1))}.text-emerald-400\/80{color:#34d399cc}.text-foreground{color:hsl(var(--foreground))}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.text-slate-300{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity, 1))}.text-slate-400{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity, 1))}.text-slate-500{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity, 1))}.text-slate-600{--tw-text-opacity: 1;color:rgb(71 85 105 / var(--tw-text-opacity, 1))}.underline{text-decoration-line:underline}.decoration-dotted{text-decoration-style:dotted}.underline-offset-4{text-underline-offset:4px}.opacity-20{opacity:.2}.opacity-70{opacity:.7}.opacity-80{opacity:.8}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[4px_4px_0_rgba\(0\,0\,0\,0\.2\)\]{--tw-shadow: 4px 4px 0 rgba(0,0,0,.2);--tw-shadow-colored: 4px 4px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.ring{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.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)}.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}@keyframes enter{0%{opacity:var(--tw-enter-opacity, 1);transform:translate3d(var(--tw-enter-translate-x, 0),var(--tw-enter-translate-y, 0),0) scale3d(var(--tw-enter-scale, 1),var(--tw-enter-scale, 1),var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity, 1);transform:translate3d(var(--tw-exit-translate-x, 0),var(--tw-exit-translate-y, 0),0) scale3d(var(--tw-exit-scale, 1),var(--tw-exit-scale, 1),var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0))}}:root{--font-display: "Press Start 2P", monospace;color-scheme:light}*{box-sizing:border-box}body{margin:0;min-height:100vh}::-webkit-scrollbar{width:12px;height:12px}::-webkit-scrollbar-track{background:#e5f2fb;border-left:2px solid #6296e8}::-webkit-scrollbar-thumb{background:#6296e8;border:2px solid #ffffff;box-shadow:inset -2px -2px #3d5052}::-webkit-scrollbar-thumb:hover{background:#84e6fd}.gamish-card{background:#fff;border:4px solid #6296e8;box-shadow:inset 2px 2px #fff,inset -2px -2px #a5cbde,4px 4px #3d505233;border-radius:4px;position:relative}.gamish-card:active{box-shadow:inset 2px 2px #3d5052,inset -2px -2px #fff;transform:translate(2px,2px)}.gamish-btn{background:#6296e8;color:#fff;border:2px solid #3d5052;box-shadow:inset 2px 2px #a5cbde,inset -2px -2px #3d5052,2px 2px #0f172a;font-family:"Press Start 2P",monospace;text-transform:uppercase;font-size:10px;letter-spacing:.5px;cursor:pointer;padding:8px 16px;border-radius:0;-webkit-user-select:none;-moz-user-select:none;user-select:none;transition:none}.gamish-btn:active{background:#507bc8;box-shadow:inset 2px 2px #3d5052,inset -2px -2px #a5cbde;transform:translate(2px,2px)}.gamish-panel-title{font-family:var(--font-display);font-size:10px;color:#6296e8;margin-bottom:12px;letter-spacing:1px;display:flex;align-items:center;gap:8px;padding:4px 8px;background:#f0f9ff;border:2px solid #a5cbde;box-shadow:inset 1px 1px #fff;text-shadow:1px 1px 0 #a5cbde}.app{max-width:1440px;margin:0 auto;padding:24px}header{display:grid;grid-template-columns:1fr auto;gap:20px;margin-bottom:24px}.logo-card{display:flex;align-items:center;gap:16px;padding:12px 20px;background:#fff}.status-badge{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:0 20px;background:#6296e8;border:2px solid #3d5052;box-shadow:inset 2px 2px #84e6fd,inset -2px -2px #3d5052,2px 2px #0003;color:#fff;font-family:var(--font-display);font-size:10px;text-transform:uppercase;letter-spacing:1px;text-shadow:1px 1px 0 #3d5052}.status-badge.live{background:#4db152;box-shadow:inset 2px 2px #86efac,inset -2px -2px #14532d,2px 2px #0003}main{display:grid;grid-template-columns:minmax(0,1fr) 340px;gap:24px;align-items:start}.pixi-wrapper{background:#0f172a;border:4px solid #6296e8;box-shadow:inset 4px 4px #3d5052,4px 4px #0000004d;padding:8px;position:relative}.pixi-wrapper canvas{width:100%!important;height:auto!important;-o-object-fit:contain;object-fit:contain;max-height:80vh}.pixi-wrapper:before{content:"OFFICE_VIEW";position:absolute;top:-12px;left:20px;background:#6296e8;color:#fff;padding:4px 8px;font-family:var(--font-display);font-size:8px;border:2px solid #3d5052;box-shadow:2px 2px #0f172a;z-index:10}.boss-message-box{background:#e4be58;border:2px solid #3d5052;color:#3d5052;padding:12px 16px;box-shadow:inset 2px 2px #fde68a,inset -2px -2px #b45309,4px 4px #0003;margin-bottom:20px;font-family:Inter,sans-serif;font-weight:700}.sidebar-stack{display:flex;flex-direction:column;gap:20px}.data-panel{background:#fff;border:2px solid #3d5052;box-shadow:6px 6px #6296e866;padding:16px}.session-item{background:#fff;border:2px solid #a5cbde;padding:10px 12px;margin-bottom:6px;color:#64748b;font-family:"Press Start 2P",monospace;font-size:8px;cursor:pointer;display:flex;align-items:center;justify-content:space-between;line-height:1.5}.session-item:hover{background:#e5f2fb;border-color:#6296e8;transform:translate(2px)}.session-item.active{background:#6296e8;color:#fff;border-color:#3d5052;box-shadow:inset 2px 2px #fff3;text-shadow:1px 1px 0 #3d5052}.todo-item{border:2px solid #e1e3e9;background:#f8fafc;padding:8px 10px;margin-bottom:8px;color:#334155;font-size:10px;font-family:Inter,sans-serif;position:relative}.todo-item:before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;background:#a5cbde}.todo-item.active{border-color:#6296e8;background:#fff;box-shadow:2px 2px #6296e833}.todo-item.active:before{background:#6296e8}.todo-item.done{border-color:#4db152;opacity:.6}.todo-item.done:before{background:#4db152}.agent-stats{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:12px}.stat-box{background:#f1f5f9;border:2px solid #e2e8f0;padding:8px 10px}.stat-label{font-size:8px;color:#64748b;font-family:"Press Start 2P",monospace;display:block;margin-bottom:6px}.stat-value{color:#334155;font-size:10px;font-weight:700}@media (max-width: 900px){main{grid-template-columns:1fr;gap:16px}.app{padding:12px}header{margin-bottom:16px}.sidebar-stack{width:100%}}@media (max-width: 600px){:root{font-size:14px}.gamish-card{border-width:2px}}.hover\:bg-accent:hover{background-color:hsl(var(--accent))}.hover\:bg-destructive\/80:hover{background-color:hsl(var(--destructive) / .8)}.hover\:bg-destructive\/90:hover{background-color:hsl(var(--destructive) / .9)}.hover\:bg-primary\/80:hover{background-color:hsl(var(--primary) / .8)}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:text-accent:hover{color:hsl(var(--accent))}.hover\:text-accent-foreground:hover{color:hsl(var(--accent-foreground))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.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)}.focus\:ring-ring:focus{--tw-ring-color: hsl(var(--ring))}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-1:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color: hsl(var(--ring))}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:size-4 svg{width:1rem;height:1rem}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}
Binary file
Binary file
@@ -0,0 +1,14 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <link rel="icon" type="image/png" href="/favicon.png" />
7
+ <title>OpenCode Pixel Office</title>
8
+ <script type="module" crossorigin src="/assets/index-Cfnbdbzw.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-CocJhp5H.css">
10
+ </head>
11
+ <body>
12
+ <div id="root"></div>
13
+ </body>
14
+ </html>
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "opencode-pixel-office",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "files": [
6
+ "bin",
7
+ "client/dist",
8
+ "plugin",
9
+ "server",
10
+ "README.md"
11
+ ],
12
+ "bin": {
13
+ "opencode-pixel-office": "bin/opencode-pixel-office.js"
14
+ },
15
+ "scripts": {
16
+ "start": "tsx server/index.ts",
17
+ "dev:client": "vite --config client/vite.config.ts",
18
+ "build:client": "vite build --config client/vite.config.ts",
19
+ "preview:client": "vite preview --config client/vite.config.ts"
20
+ },
21
+ "dependencies": {
22
+ "@pixi/react": "^7.1.1",
23
+ "@radix-ui/react-slot": "^1.2.4",
24
+ "class-variance-authority": "^0.7.1",
25
+ "clsx": "^2.1.1",
26
+ "express": "^4.19.2",
27
+ "lucide-react": "^0.563.0",
28
+ "pixi.js": "^7.4.0",
29
+ "react": "^18.3.1",
30
+ "react-dom": "^18.3.1",
31
+ "react-qr-code": "^2.0.18",
32
+ "tailwind-merge": "^3.4.0",
33
+ "tailwindcss-animate": "^1.0.7",
34
+ "tsx": "^4.19.2",
35
+ "ws": "^8.16.0"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^20.12.7",
39
+ "@types/react": "^18.3.3",
40
+ "@types/react-dom": "^18.3.0",
41
+ "@vitejs/plugin-react": "^4.3.1",
42
+ "autoprefixer": "^10.4.24",
43
+ "postcss": "^8.5.6",
44
+ "tailwindcss": "^3.4.17",
45
+ "typescript": "^5.6.3",
46
+ "vite": "^5.4.8"
47
+ }
48
+ }
@@ -0,0 +1,174 @@
1
+ import path from "node:path";
2
+ import fs from "node:fs";
3
+
4
+ const DEFAULT_PORT = 5100;
5
+
6
+ // Helper to get configured port
7
+ const getConfiguredPort = (globalDistDir) => {
8
+ try {
9
+ const configPath = path.join(globalDistDir, "config.json");
10
+ if (fs.existsSync(configPath)) {
11
+ const start = Date.now();
12
+ // Read synchronously to ensure we have port for endpoint
13
+ // This is okay as it's a tiny local JSON
14
+ const raw = fs.readFileSync(configPath, "utf8");
15
+ const data = JSON.parse(raw);
16
+ if (data && typeof data.port === "number") {
17
+ return data.port;
18
+ }
19
+ }
20
+ } catch (e) {
21
+ // ignore
22
+ }
23
+ return DEFAULT_PORT;
24
+ };
25
+
26
+ // We need to resolve home dir early to get config
27
+ const homeDir = process.env.HOME || process.env.USERPROFILE || "/";
28
+ const globalDistDir = path.join(homeDir, ".opencode", "pixel-office");
29
+ const configuredPort = getConfiguredPort(globalDistDir);
30
+
31
+ const resolveEndpoint = () => {
32
+ const port = process.env.PIXEL_OFFICE_PORT || configuredPort;
33
+ const raw =
34
+ process.env.PIXEL_OFFICE_URL ||
35
+ `http://localhost:${port}/events`;
36
+ return raw.endsWith("/events") ? raw : `${raw.replace(/\/$/, "")}/events`;
37
+ };
38
+
39
+ const resolveServerUrl = (endpoint) => endpoint.replace(/\/events$/, "");
40
+
41
+ const resolveEndpointInfo = (endpoint, portOverride) => {
42
+ try {
43
+ const url = new URL(endpoint);
44
+ const port = url.port ? Number(url.port) : portOverride;
45
+ return {
46
+ url,
47
+ port,
48
+ isLocal: url.hostname === "localhost" || url.hostname === "127.0.0.1",
49
+ };
50
+ } catch (error) {
51
+ return { url: null, port: portOverride, isLocal: false };
52
+ }
53
+ };
54
+
55
+ const resolveOpenCommand = (url) => {
56
+ if (process.platform === "darwin") {
57
+ return ["open", url];
58
+ }
59
+ if (process.platform === "win32") {
60
+ return ["cmd", "/c", "start", "", url];
61
+ }
62
+ return ["xdg-open", url];
63
+ };
64
+
65
+ export const PixelOfficePlugin = async ({ directory, worktree, client }) => {
66
+ const endpoint = resolveEndpoint();
67
+ const serverUrl = resolveServerUrl(endpoint);
68
+ const rootDir = worktree || directory;
69
+ const endpointInfo = resolveEndpointInfo(endpoint, configuredPort);
70
+ const openCommand = resolveOpenCommand(serverUrl);
71
+
72
+ // Path Resolution
73
+ const localServerPath = path.join(rootDir, "server", "index.ts");
74
+ const globalServerPath = path.join(globalDistDir, "server", "index.ts");
75
+
76
+ let serverCwd = rootDir;
77
+ let serverScript = "server/index.ts";
78
+ let useGlobal = false;
79
+
80
+ if (fs.existsSync(localServerPath)) {
81
+ // Local dev mode: run from workspace
82
+ serverCwd = rootDir;
83
+ } else if (fs.existsSync(globalServerPath)) {
84
+ // Global standalone mode: run from ~/.opencode/pixel-office
85
+ serverCwd = globalDistDir;
86
+ useGlobal = true;
87
+ } else {
88
+ // Neither found
89
+ if (endpointInfo.isLocal) {
90
+ console.warn("[Pixel Office] Server not found locally or globally.");
91
+ }
92
+ }
93
+
94
+ let serverProcess = null;
95
+ let browserOpened = false;
96
+ let warnedOnce = false;
97
+
98
+ const startServerIfNeeded = async () => {
99
+ if (!endpointInfo.isLocal || serverProcess) {
100
+ return;
101
+ }
102
+ const env = {
103
+ ...process.env,
104
+ PORT: String(process.env.PIXEL_OFFICE_PORT || endpointInfo.port),
105
+ };
106
+
107
+ let cmd = ["tsx", serverScript];
108
+ if (useGlobal) {
109
+ const globalTsx = path.join(serverCwd, "node_modules", ".bin", "tsx");
110
+ if (fs.existsSync(globalTsx)) {
111
+ cmd = [globalTsx, serverScript];
112
+ }
113
+ }
114
+
115
+ try {
116
+ serverProcess = Bun.spawn({
117
+ cmd,
118
+ cwd: serverCwd,
119
+ env,
120
+ stdout: "ignore",
121
+ stderr: "ignore",
122
+ });
123
+ // console.log(`[Pixel Office] Started server in ${serverCwd} on port ${env.PORT}`);
124
+ } catch (error) {
125
+ await client.app.log({
126
+ service: "pixel-office",
127
+ level: "error",
128
+ message: "Failed to start Pixel Office server",
129
+ extra: { error: String(error), cwd: serverCwd },
130
+ });
131
+ }
132
+ };
133
+
134
+ const openBrowserIfNeeded = async () => {
135
+ if (!endpointInfo.isLocal || browserOpened) {
136
+ return;
137
+ }
138
+ browserOpened = true;
139
+ try {
140
+ Bun.spawn({ cmd: openCommand, stdout: "ignore", stderr: "ignore" });
141
+ } catch (error) {
142
+ await client.app.log({
143
+ service: "pixel-office",
144
+ level: "warn",
145
+ message: "Failed to open Pixel Office browser",
146
+ extra: { error: String(error), url: serverUrl },
147
+ });
148
+ }
149
+ };
150
+
151
+ await startServerIfNeeded();
152
+ await openBrowserIfNeeded();
153
+
154
+ return {
155
+ event: async ({ event }) => {
156
+ if (!event) {
157
+ return;
158
+ }
159
+ try {
160
+ await fetch(endpoint, {
161
+ method: "POST",
162
+ headers: {
163
+ "Content-Type": "application/json",
164
+ },
165
+ body: JSON.stringify(event),
166
+ });
167
+ } catch (error) {
168
+ if (!warnedOnce) {
169
+ warnedOnce = true;
170
+ }
171
+ }
172
+ },
173
+ };
174
+ };