kanon-cli 0.1.0 → 0.1.1

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}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:#374151;border-radius:3px}::-webkit-scrollbar-thumb:hover{background:#4b5563}.pointer-events-none{pointer-events:none}.\!visible{visibility:visible!important}.visible{visibility:visible}.absolute{position:absolute}.relative{position:relative}.inset-0{top:0;right:0;bottom:0;left:0}.-right-1{right:-.25rem}.-right-2{right:-.5rem}.-top-1{top:-.25rem}.left-0\.5{left:.125rem}.left-3{left:.75rem}.left-\[18px\]{left:18px}.right-2{right:.5rem}.right-3{right:.75rem}.top-0\.5{top:.125rem}.top-1\/2{top:50%}.top-8{top:2rem}.top-full{top:100%}.z-50{z-index:50}.col-span-2{grid-column:span 2 / span 2}.mx-2{margin-left:.5rem;margin-right:.5rem}.mb-0\.5{margin-bottom:.125rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-16{height:4rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-full{height:100%}.max-h-40{max-height:10rem}.max-h-48{max-height:12rem}.max-h-60{max-height:15rem}.max-h-64{max-height:16rem}.max-h-\[60vh\]{max-height:60vh}.max-h-\[70vh\]{max-height:70vh}.w-10{width:2.5rem}.w-12{width:3rem}.w-16{width:4rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-20{width:5rem}.w-3{width:.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-56{width:14rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-full{width:100%}.min-w-0{min-width:0px}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-90{--tw-rotate: 90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-110{--tw-scale-x: 1.1;--tw-scale-y: 1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.cursor-text{cursor:text}.select-text{-webkit-user-select:text;-moz-user-select:text;user-select:text}.resize-y{resize:vertical}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-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))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-r-2{border-right-width:2px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-gray-600{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity, 1))}.border-gray-700{--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity, 1))}.border-gray-700\/30{border-color:#3741514d}.border-gray-700\/50{border-color:#37415180}.border-gray-800{--tw-border-opacity: 1;border-color:rgb(31 41 55 / var(--tw-border-opacity, 1))}.border-gray-800\/50{border-color:#1f293780}.border-green-500\/30{border-color:#22c55e4d}.border-kanon-500{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.border-kanon-500\/30{border-color:#3b82f64d}.border-red-500\/30{border-color:#ef44444d}.border-red-800\/40{border-color:#991b1b66}.border-transparent{border-color:transparent}.border-yellow-500\/30{border-color:#eab3084d}.bg-black\/50{background-color:#00000080}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-cyan-500\/10{background-color:#06b6d41a}.bg-gray-500{--tw-bg-opacity: 1;background-color:rgb(107 114 128 / 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-800{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.bg-gray-800\/20{background-color:#1f293733}.bg-gray-800\/30{background-color:#1f29374d}.bg-gray-800\/50{background-color:#1f293780}.bg-gray-900{--tw-bg-opacity: 1;background-color:rgb(17 24 39 / var(--tw-bg-opacity, 1))}.bg-gray-950{--tw-bg-opacity: 1;background-color:rgb(3 7 18 / var(--tw-bg-opacity, 1))}.bg-gray-950\/50{background-color:#03071280}.bg-green-500{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity, 1))}.bg-green-500\/10{background-color:#22c55e1a}.bg-green-500\/20{background-color:#22c55e33}.bg-green-600\/20{background-color:#16a34a33}.bg-kanon-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-kanon-500\/10{background-color:#3b82f61a}.bg-kanon-500\/20{background-color:#3b82f633}.bg-kanon-500\/5{background-color:#3b82f60d}.bg-kanon-600{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.bg-orange-500{--tw-bg-opacity: 1;background-color:rgb(249 115 22 / var(--tw-bg-opacity, 1))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-red-500\/10{background-color:#ef44441a}.bg-red-500\/20{background-color:#ef444433}.bg-red-600\/20{background-color:#dc262633}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-yellow-500{--tw-bg-opacity: 1;background-color:rgb(234 179 8 / var(--tw-bg-opacity, 1))}.bg-yellow-500\/10{background-color:#eab3081a}.bg-yellow-500\/15{background-color:#eab30826}.bg-yellow-500\/20{background-color:#eab30833}.bg-yellow-600\/20{background-color:#ca8a0433}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.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-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}.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-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-3{padding-bottom:.75rem}.pl-3{padding-left:.75rem}.pr-16{padding-right:4rem}.pt-2{padding-top:.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.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-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}.capitalize{text-transform:capitalize}.italic{font-style:italic}.leading-tight{line-height:1.25}.tracking-wider{letter-spacing:.05em}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.text-cyan-400{--tw-text-opacity: 1;color:rgb(34 211 238 / var(--tw-text-opacity, 1))}.text-gray-100{--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}.text-gray-200{--tw-text-opacity: 1;color:rgb(229 231 235 / 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-green-400{--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.text-green-400\/60{color:#4ade8099}.text-green-400\/70{color:#4ade80b3}.text-kanon-300{--tw-text-opacity: 1;color:rgb(147 197 253 / var(--tw-text-opacity, 1))}.text-kanon-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.text-kanon-400\/60{color:#60a5fa99}.text-purple-400{--tw-text-opacity: 1;color:rgb(192 132 252 / var(--tw-text-opacity, 1))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-transparent{color:transparent}.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))}.placeholder-gray-600::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(75 85 99 / var(--tw-placeholder-opacity, 1))}.placeholder-gray-600::placeholder{--tw-placeholder-opacity: 1;color:rgb(75 85 99 / var(--tw-placeholder-opacity, 1))}.caret-gray-200{caret-color:#e5e7eb}.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)}.ring-2{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-white{--tw-ring-opacity: 1;--tw-ring-color: rgb(255 255 255 / var(--tw-ring-opacity, 1))}.ring-offset-2{--tw-ring-offset-width: 2px}.ring-offset-gray-900{--tw-ring-offset-color: #111827}.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}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.last\:border-0:last-child{border-width:0px}.hover\:scale-110:hover{--tw-scale-x: 1.1;--tw-scale-y: 1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:border-gray-600\/50:hover{border-color:#4b556380}.hover\:border-kanon-500\/50:hover{border-color:#3b82f680}.hover\:bg-gray-700\/50:hover{background-color:#37415180}.hover\:bg-gray-800:hover{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-800\/30:hover{background-color:#1f29374d}.hover\:bg-gray-800\/50:hover{background-color:#1f293780}.hover\:bg-gray-800\/80:hover{background-color:#1f2937cc}.hover\:bg-green-600\/30:hover{background-color:#16a34a4d}.hover\:bg-kanon-500:hover{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.hover\:bg-kanon-500\/20:hover{background-color:#3b82f633}.hover\:bg-kanon-500\/5:hover{background-color:#3b82f60d}.hover\:bg-red-500\/10:hover{background-color:#ef44441a}.hover\:bg-red-500\/20:hover{background-color:#ef444433}.hover\:bg-red-600\/30:hover{background-color:#dc26264d}.hover\:bg-yellow-600\/30:hover{background-color:#ca8a044d}.hover\:text-gray-200:hover{--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity, 1))}.hover\:text-gray-300:hover{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.hover\:text-gray-400:hover{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.hover\:text-green-300:hover{--tw-text-opacity: 1;color:rgb(134 239 172 / var(--tw-text-opacity, 1))}.hover\:text-kanon-300:hover{--tw-text-opacity: 1;color:rgb(147 197 253 / var(--tw-text-opacity, 1))}.hover\:text-kanon-400:hover{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.hover\:text-red-300:hover{--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity, 1))}.hover\:text-red-400:hover{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.focus\:border-kanon-500:focus{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.focus\:border-kanon-500\/50:focus{border-color:#3b82f680}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1: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(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\:ring-kanon-500\/30:focus{--tw-ring-color: rgb(59 130 246 / .3)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:opacity-100{opacity:1}@media(min-width:768px){.md\:block{display:block}}
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Kanon Dashboard</title>
7
- <script type="module" crossorigin src="/assets/index-Dcbpx-Xz.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-DhFfv70f.css">
7
+ <script type="module" crossorigin src="/assets/index-7UwkIyFn.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-DBQ473Y5.css">
9
9
  </head>
10
10
  <body class="h-full text-gray-100">
11
11
  <div id="root" class="h-full"></div>
@@ -12,13 +12,48 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
12
 
13
13
  export function createDashboardServer(port = 3737) {
14
14
  const app = express();
15
- app.use(express.json());
15
+ app.use(express.json({ limit: '5mb' }));
16
16
 
17
17
  // API routes
18
18
  app.use('/api/kanon', createProxyRoutes());
19
19
  app.use('/api/settings', createSettingsRoutes());
20
20
  app.use('/api/agent', createAgentRoutes());
21
21
 
22
+ // GET /api/version — current version + check for updates
23
+ app.get('/api/version', async (req, res) => {
24
+ try {
25
+ const pkgPath = path.resolve(__dirname, '../../../package.json');
26
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
27
+ const current = pkg.version;
28
+
29
+ let latest = current;
30
+ try {
31
+ const resp = await fetch('https://registry.npmjs.org/kanon-cli/latest', {
32
+ headers: { 'Accept': 'application/json' },
33
+ signal: AbortSignal.timeout(3000),
34
+ });
35
+ if (resp.ok) {
36
+ const data = await resp.json();
37
+ latest = data.version || current;
38
+ }
39
+ } catch {}
40
+
41
+ res.json({ current, latest, updateAvailable: latest !== current });
42
+ } catch (err) {
43
+ res.status(500).json({ error: err.message });
44
+ }
45
+ });
46
+
47
+ // POST /api/update — run npm update -g kanon-cli
48
+ app.post('/api/update', async (req, res) => {
49
+ try {
50
+ execSync('npm install -g kanon-cli@latest', { stdio: 'pipe', timeout: 30000 });
51
+ res.json({ ok: true });
52
+ } catch (err) {
53
+ res.status(500).json({ error: err.stderr?.toString() || err.message });
54
+ }
55
+ });
56
+
22
57
  // POST /api/restart — restart server, optionally rebuild dashboard first
23
58
  app.post('/api/restart', async (req, res) => {
24
59
  const rebuild = req.query.rebuild === '1';
@@ -172,17 +172,36 @@ export function createSettingsRoutes() {
172
172
  }
173
173
  });
174
174
 
175
- // GET /api/settings/credentials — returns global config (masked password)
176
- router.get('/credentials', (req, res) => {
175
+ // GET /api/settings/credentials — returns global config + agent profile from server
176
+ router.get('/credentials', async (req, res) => {
177
177
  const config = loadGlobalConfig();
178
- res.json({
178
+ const base = {
179
179
  server_url: config.server_url || '',
180
180
  email: config.email || '',
181
- password: config.password ? '********' : '',
181
+ password: config.password || '',
182
182
  token: config.token || '',
183
183
  user_name: config.user_name || '',
184
184
  user_id: config.user_id || '',
185
- });
185
+ };
186
+
187
+ // Fetch agent profile from server if we have a token
188
+ if (config.token) {
189
+ try {
190
+ const serverUrl = getServerUrl();
191
+ const profileRes = await fetch(`${serverUrl}/api/auth/me`, {
192
+ headers: { 'Authorization': `Bearer ${config.token}` },
193
+ });
194
+ if (profileRes.ok) {
195
+ const profile = await profileRes.json();
196
+ const user = profile.user || profile;
197
+ base.user_name = user.name || base.user_name;
198
+ base.color = user.color || '#6366f1';
199
+ base.avatar = user.avatar || '';
200
+ }
201
+ } catch {}
202
+ }
203
+
204
+ res.json(base);
186
205
  });
187
206
 
188
207
  // PUT /api/settings/credentials — update global config
@@ -193,9 +212,7 @@ export function createSettingsRoutes() {
193
212
 
194
213
  if (req.body.server_url) update.server_url = req.body.server_url;
195
214
  if (req.body.email) update.email = req.body.email;
196
- if (req.body.password && req.body.password !== '********') {
197
- update.password = req.body.password;
198
- }
215
+ if (req.body.password) update.password = req.body.password;
199
216
 
200
217
  saveGlobalConfig(update);
201
218
  res.json({ ok: true });
@@ -204,6 +221,117 @@ export function createSettingsRoutes() {
204
221
  }
205
222
  });
206
223
 
224
+ // PUT /api/settings/agent-profile — update agent name and color on Kanon server
225
+ router.put('/agent-profile', async (req, res) => {
226
+ try {
227
+ const config = loadGlobalConfig();
228
+ if (!config.token) return res.status(401).json({ error: 'Not logged in' });
229
+ const serverUrl = getServerUrl();
230
+
231
+ const { name, color } = req.body;
232
+ const profileRes = await fetch(`${serverUrl}/api/auth/me`, {
233
+ method: 'PUT',
234
+ headers: {
235
+ 'Content-Type': 'application/json',
236
+ 'Authorization': `Bearer ${config.token}`,
237
+ },
238
+ body: JSON.stringify({ name, color }),
239
+ });
240
+
241
+ if (!profileRes.ok) {
242
+ const data = await profileRes.json().catch(() => ({}));
243
+ return res.status(profileRes.status).json({ error: data.error || 'Failed to update profile' });
244
+ }
245
+
246
+ // Update local config name
247
+ if (name) saveGlobalConfig({ ...config, user_name: name });
248
+
249
+ res.json({ ok: true });
250
+ } catch (err) {
251
+ res.status(500).json({ error: err.message });
252
+ }
253
+ });
254
+
255
+ // POST /api/settings/agent-avatar — upload agent avatar to Kanon server
256
+ router.post('/agent-avatar', async (req, res) => {
257
+ try {
258
+ const config = loadGlobalConfig();
259
+ if (!config.token) return res.status(401).json({ error: 'Not logged in' });
260
+ const serverUrl = getServerUrl();
261
+
262
+ const { image } = req.body;
263
+ if (!image) return res.status(400).json({ error: 'No image data' });
264
+
265
+ const avatarRes = await fetch(`${serverUrl}/api/auth/me/avatar`, {
266
+ method: 'POST',
267
+ headers: {
268
+ 'Content-Type': 'application/json',
269
+ 'Authorization': `Bearer ${config.token}`,
270
+ },
271
+ body: JSON.stringify({ image }),
272
+ });
273
+
274
+ if (!avatarRes.ok) {
275
+ const data = await avatarRes.json().catch(() => ({}));
276
+ return res.status(avatarRes.status).json({ error: data.error || 'Failed to upload avatar' });
277
+ }
278
+
279
+ const data = await avatarRes.json();
280
+ res.json({ ok: true, avatar: data.user?.avatar || data.avatar });
281
+ } catch (err) {
282
+ res.status(500).json({ error: err.message });
283
+ }
284
+ });
285
+
286
+ // DELETE /api/settings/agent-avatar — remove agent avatar
287
+ router.delete('/agent-avatar', async (req, res) => {
288
+ try {
289
+ const config = loadGlobalConfig();
290
+ if (!config.token) return res.status(401).json({ error: 'Not logged in' });
291
+ const serverUrl = getServerUrl();
292
+
293
+ const delRes = await fetch(`${serverUrl}/api/auth/me/avatar`, {
294
+ method: 'DELETE',
295
+ headers: { 'Authorization': `Bearer ${config.token}` },
296
+ });
297
+
298
+ if (!delRes.ok) {
299
+ const data = await delRes.json().catch(() => ({}));
300
+ return res.status(delRes.status).json({ error: data.error || 'Failed to remove avatar' });
301
+ }
302
+
303
+ res.json({ ok: true });
304
+ } catch (err) {
305
+ res.status(500).json({ error: err.message });
306
+ }
307
+ });
308
+
309
+ // DELETE /api/settings/agent-account — delete agent account from Kanon server + clear local config
310
+ router.delete('/agent-account', async (req, res) => {
311
+ try {
312
+ const config = loadGlobalConfig();
313
+ if (!config.token) return res.status(401).json({ error: 'Not logged in' });
314
+ const serverUrl = getServerUrl();
315
+
316
+ const delRes = await fetch(`${serverUrl}/api/auth/me`, {
317
+ method: 'DELETE',
318
+ headers: { 'Authorization': `Bearer ${config.token}` },
319
+ });
320
+
321
+ if (!delRes.ok) {
322
+ const data = await delRes.json().catch(() => ({}));
323
+ return res.status(delRes.status).json({ error: data.error || 'Failed to delete account' });
324
+ }
325
+
326
+ // Clear local credentials
327
+ saveGlobalConfig({ server_url: config.server_url });
328
+
329
+ res.json({ ok: true });
330
+ } catch (err) {
331
+ res.status(500).json({ error: err.message });
332
+ }
333
+ });
334
+
207
335
  // POST /api/settings/test-connection — test login with stored credentials
208
336
  router.post('/test-connection', async (req, res) => {
209
337
  try {
@@ -232,5 +360,113 @@ export function createSettingsRoutes() {
232
360
  }
233
361
  });
234
362
 
363
+ // POST /api/settings/provision-agent — log in as user, create agent, save credentials
364
+ router.post('/provision-agent', async (req, res) => {
365
+ try {
366
+ const { email, password, agent_name, team_ids } = req.body;
367
+ const serverUrl = getServerUrl();
368
+
369
+ if (!email || !password || !agent_name) {
370
+ return res.status(400).json({ error: 'Email, password, and agent name are required' });
371
+ }
372
+
373
+ // 1. Log in with user's personal credentials
374
+ const loginRes = await fetch(`${serverUrl}/api/auth/login`, {
375
+ method: 'POST',
376
+ headers: { 'Content-Type': 'application/json' },
377
+ body: JSON.stringify({ email, password }),
378
+ });
379
+
380
+ if (!loginRes.ok) {
381
+ const data = await loginRes.json().catch(() => ({}));
382
+ return res.status(401).json({ error: data.error || 'Login failed. Check your email and password.' });
383
+ }
384
+
385
+ const loginData = await loginRes.json();
386
+ const userToken = loginData.token;
387
+
388
+ // 2. Provision agent via Kanon API
389
+ const provisionRes = await fetch(`${serverUrl}/api/agents/provision`, {
390
+ method: 'POST',
391
+ headers: {
392
+ 'Content-Type': 'application/json',
393
+ 'Authorization': `Bearer ${userToken}`,
394
+ },
395
+ body: JSON.stringify({ name: agent_name, team_ids: team_ids || [] }),
396
+ });
397
+
398
+ if (!provisionRes.ok) {
399
+ const data = await provisionRes.json().catch(() => ({}));
400
+ return res.status(provisionRes.status).json({ error: data.error || 'Failed to provision agent' });
401
+ }
402
+
403
+ const provisionData = await provisionRes.json();
404
+ const agent = provisionData.agent;
405
+
406
+ // 3. Save agent credentials to global config
407
+ const current = loadGlobalConfig();
408
+ saveGlobalConfig({
409
+ ...current,
410
+ server_url: serverUrl,
411
+ email: agent.email,
412
+ password: agent.password || current.password,
413
+ token: agent.token,
414
+ user_id: agent.id,
415
+ user_name: agent.name,
416
+ });
417
+
418
+ res.json({
419
+ ok: true,
420
+ created: provisionData.created,
421
+ agent: {
422
+ id: agent.id,
423
+ email: agent.email,
424
+ name: agent.name,
425
+ teams: agent.teams || [],
426
+ },
427
+ skippedTeams: provisionData.skippedTeams || [],
428
+ });
429
+ } catch (err) {
430
+ res.status(500).json({ error: err.message });
431
+ }
432
+ });
433
+
434
+ // POST /api/settings/provision-teams — get user's teams for provisioning UI
435
+ router.post('/provision-teams', async (req, res) => {
436
+ try {
437
+ const { email, password } = req.body;
438
+ const serverUrl = getServerUrl();
439
+
440
+ // Log in to get token
441
+ const loginRes = await fetch(`${serverUrl}/api/auth/login`, {
442
+ method: 'POST',
443
+ headers: { 'Content-Type': 'application/json' },
444
+ body: JSON.stringify({ email, password }),
445
+ });
446
+
447
+ if (!loginRes.ok) {
448
+ const data = await loginRes.json().catch(() => ({}));
449
+ return res.status(401).json({ error: data.error || 'Login failed' });
450
+ }
451
+
452
+ const loginData = await loginRes.json();
453
+
454
+ // Fetch teams
455
+ const teamsRes = await fetch(`${serverUrl}/api/agents/teams`, {
456
+ headers: { 'Authorization': `Bearer ${loginData.token}` },
457
+ });
458
+
459
+ if (!teamsRes.ok) {
460
+ const data = await teamsRes.json().catch(() => ({}));
461
+ return res.status(teamsRes.status).json({ error: data.error || `Failed to fetch teams. Please try again later.` });
462
+ }
463
+
464
+ const teamsData = await teamsRes.json();
465
+ res.json(teamsData);
466
+ } catch (err) {
467
+ res.status(500).json({ error: err.message });
468
+ }
469
+ });
470
+
235
471
  return router;
236
472
  }