aegis-bridge 2.12.0 → 2.12.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.
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Copyright (c) 2014 The xterm.js authors. All rights reserved.
3
+ * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
4
+ * https://github.com/chjj/term.js
5
+ * @license MIT
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in
15
+ * all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ * THE SOFTWARE.
24
+ *
25
+ * Originally forked from (with the author's permission):
26
+ * Fabrice Bellard's javascript vt100 for jslinux:
27
+ * http://bellard.org/jslinux/
28
+ * Copyright (c) 2011 Fabrice Bellard
29
+ * The original design remains. The terminal itself
30
+ * has been extended to include xterm CSI codes, among
31
+ * other features.
32
+ */.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--font-mono:"JetBrains Mono", "Fira Code", "Cascadia Code", "Consolas", monospace;--color-red-200:oklch(88.5% .062 18.334);--color-red-300:oklch(80.8% .114 19.571);--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-900:oklch(39.6% .141 25.723);--color-red-950:oklch(25.8% .092 26.042);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-500:oklch(76.9% .188 70.08);--color-yellow-200:oklch(94.5% .129 101.54);--color-yellow-300:oklch(90.5% .182 98.111);--color-yellow-400:oklch(85.2% .199 91.936);--color-yellow-500:oklch(79.5% .184 86.047);--color-yellow-900:oklch(42.1% .095 57.708);--color-yellow-950:oklch(28.6% .066 53.813);--color-green-200:oklch(92.5% .084 155.995);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-green-900:oklch(39.3% .095 152.535);--color-green-950:oklch(26.6% .065 152.934);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-300:oklch(84.5% .143 164.978);--color-emerald-400:oklch(76.5% .177 163.223);--color-emerald-500:oklch(69.6% .17 162.48);--color-cyan-200:oklch(91.7% .08 205.041);--color-cyan-500:oklch(71.5% .143 215.221);--color-cyan-950:oklch(30.2% .056 229.695);--color-blue-500:oklch(62.3% .214 259.815);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-black:#000;--spacing:.25rem;--container-xs:20rem;--container-sm:24rem;--container-md:28rem;--container-2xl:42rem;--container-6xl:72rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-wider:.05em;--leading-relaxed:1.625;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--animate-ping:ping 1s cubic-bezier(0, 0, .2, 1) infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-sm:8px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-void:#0a0a0f;--color-void-light:#12121a;--color-void-lighter:#1a1a2e;--color-accent:#3b82f6;--color-accent-dim:#3b82f640;--color-warning:#f59e0b;--color-error:#ef4444;--color-info:#6366f1}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}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;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.right-0{right:calc(var(--spacing) * 0)}.right-4{right:calc(var(--spacing) * 4)}.bottom-0{bottom:calc(var(--spacing) * 0)}.bottom-4{bottom:calc(var(--spacing) * 4)}.left-0{left:calc(var(--spacing) * 0)}.isolate{isolation:isolate}.z-10{z-index:10}.z-50{z-index:50}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.mx-4{margin-inline:calc(var(--spacing) * 4)}.mx-auto{margin-inline:auto}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.ml-1{margin-left:calc(var(--spacing) * 1)}.ml-4{margin-left:calc(var(--spacing) * 4)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.h-0\.5{height:calc(var(--spacing) * .5)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-3{height:calc(var(--spacing) * 3)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-6{height:calc(var(--spacing) * 6)}.h-8{height:calc(var(--spacing) * 8)}.h-10{height:calc(var(--spacing) * 10)}.h-36{height:calc(var(--spacing) * 36)}.h-48{height:calc(var(--spacing) * 48)}.h-\[calc\(100vh-380px\)\]{height:calc(100vh - 380px)}.h-\[calc\(100vh-420px\)\]{height:calc(100vh - 420px)}.h-full{height:100%}.h-screen{height:100vh}.max-h-32{max-height:calc(var(--spacing) * 32)}.max-h-64{max-height:calc(var(--spacing) * 64)}.max-h-\[90vh\]{max-height:90vh}.max-h-\[300px\]{max-height:300px}.max-h-\[360px\]{max-height:360px}.max-h-\[420px\]{max-height:420px}.min-h-\[40px\]{min-height:40px}.min-h-\[44px\]{min-height:44px}.min-h-\[50vh\]{min-height:50vh}.min-h-\[88px\]{min-height:88px}.min-h-\[240px\]{min-height:240px}.min-h-\[250px\]{min-height:250px}.min-h-\[300px\]{min-height:300px}.min-h-screen{min-height:100vh}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-3{width:calc(var(--spacing) * 3)}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-6{width:calc(var(--spacing) * 6)}.w-8{width:calc(var(--spacing) * 8)}.w-10{width:calc(var(--spacing) * 10)}.w-16{width:calc(var(--spacing) * 16)}.w-56{width:calc(var(--spacing) * 56)}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-\[80\%\]{max-width:80%}.max-w-\[85\%\]{max-width:85%}.max-w-\[160px\]{max-width:160px}.max-w-\[200px\]{max-width:200px}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-\[44px\]{min-width:44px}.min-w-\[220px\]{min-width:220px}.flex-1{flex:1}.shrink-0{flex-shrink:0}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-ping{animation:var(--animate-ping)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-pointer{cursor:pointer}.resize{resize:both}.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))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-\[1fr_120px_1fr_44px\]{grid-template-columns:1fr 120px 1fr 44px}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-6{column-gap:calc(var(--spacing) * 6)}.gap-y-2{row-gap:calc(var(--spacing) * 2)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-\[\#1a1a2e\]\/50>:not(:last-child)){border-color:#1a1a2e80}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-br-sm{border-bottom-right-radius:var(--radius-sm)}.rounded-bl-sm{border-bottom-left-radius:var(--radius-sm)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-\[\#00e5ff\]{border-color:#00e5ff}.border-\[\#00e5ff\]\/30{border-color:#00e5ff4d}.border-\[\#00e5ff\]\/40{border-color:#00e5ff66}.border-\[\#1a1a2e\]{border-color:#1a1a2e}.border-\[\#1a1a2e\]\/50{border-color:#1a1a2e80}.border-\[\#3b82f6\]\/30{border-color:#3b82f64d}.border-\[\#3b82f6\]\/40{border-color:#3b82f666}.border-\[\#7f1d1d\]{border-color:#7f1d1d}.border-\[\#10b981\]\/30{border-color:#10b9814d}.border-\[\#ef4444\]\/20{border-color:#ef444433}.border-\[\#ef4444\]\/30{border-color:#ef44444d}.border-\[\#ef4444\]\/40{border-color:#ef444466}.border-\[\#ef444420\]{border-color:#ef444420}.border-\[\#f59e0b\]\/40{border-color:#f59e0b66}.border-\[\#ff3366\]\/20{border-color:#f363}.border-\[\#ff336620\]{border-color:#ff336620}.border-\[\#ffaa00\]\/30{border-color:#ffaa004d}.border-amber-500\/20{border-color:#f99c0033}@supports (color:color-mix(in lab,red,red)){.border-amber-500\/20{border-color:color-mix(in oklab,var(--color-amber-500) 20%,transparent)}}.border-amber-500\/30{border-color:#f99c004d}@supports (color:color-mix(in lab,red,red)){.border-amber-500\/30{border-color:color-mix(in oklab,var(--color-amber-500) 30%,transparent)}}.border-cyan-500\/50{border-color:#00b7d780}@supports (color:color-mix(in lab,red,red)){.border-cyan-500\/50{border-color:color-mix(in oklab,var(--color-cyan-500) 50%,transparent)}}.border-emerald-400\/20{border-color:#00d29433}@supports (color:color-mix(in lab,red,red)){.border-emerald-400\/20{border-color:color-mix(in oklab,var(--color-emerald-400) 20%,transparent)}}.border-emerald-400\/30{border-color:#00d2944d}@supports (color:color-mix(in lab,red,red)){.border-emerald-400\/30{border-color:color-mix(in oklab,var(--color-emerald-400) 30%,transparent)}}.border-emerald-500\/20{border-color:#00bb7f33}@supports (color:color-mix(in lab,red,red)){.border-emerald-500\/20{border-color:color-mix(in oklab,var(--color-emerald-500) 20%,transparent)}}.border-gray-500\/30{border-color:#6a72824d}@supports (color:color-mix(in lab,red,red)){.border-gray-500\/30{border-color:color-mix(in oklab,var(--color-gray-500) 30%,transparent)}}.border-green-500\/50{border-color:#00c75880}@supports (color:color-mix(in lab,red,red)){.border-green-500\/50{border-color:color-mix(in oklab,var(--color-green-500) 50%,transparent)}}.border-red-400\/30{border-color:#ff65684d}@supports (color:color-mix(in lab,red,red)){.border-red-400\/30{border-color:color-mix(in oklab,var(--color-red-400) 30%,transparent)}}.border-red-500\/20{border-color:#fb2c3633}@supports (color:color-mix(in lab,red,red)){.border-red-500\/20{border-color:color-mix(in oklab,var(--color-red-500) 20%,transparent)}}.border-red-500\/50{border-color:#fb2c3680}@supports (color:color-mix(in lab,red,red)){.border-red-500\/50{border-color:color-mix(in oklab,var(--color-red-500) 50%,transparent)}}.border-void-lighter{border-color:var(--color-void-lighter)}.border-void-lighter\/50{border-color:#1a1a2e80}@supports (color:color-mix(in lab,red,red)){.border-void-lighter\/50{border-color:color-mix(in oklab,var(--color-void-lighter) 50%,transparent)}}.border-yellow-500\/50{border-color:#edb20080}@supports (color:color-mix(in lab,red,red)){.border-yellow-500\/50{border-color:color-mix(in oklab,var(--color-yellow-500) 50%,transparent)}}.bg-\[\#0a0a0f\]{background-color:#0a0a0f}.bg-\[\#0d0d12\]{background-color:#0d0d12}.bg-\[\#00e5ff\]{background-color:#00e5ff}.bg-\[\#00e5ff\]\/10{background-color:#00e5ff1a}.bg-\[\#00e5ff\]\/70{background-color:#00e5ffb3}.bg-\[\#1a1a00\]\/60{background-color:#1a1a0099}.bg-\[\#1a1a2e\]{background-color:#1a1a2e}.bg-\[\#1a1a3e\]{background-color:#1a1a3e}.bg-\[\#002a33\]{background-color:#002a33}.bg-\[\#2a120f\]{background-color:#2a120f}.bg-\[\#2b2200\]{background-color:#2b2200}.bg-\[\#3a2e00\]{background-color:#3a2e00}.bg-\[\#3b82f6\]\/10{background-color:#3b82f61a}.bg-\[\#003322\]{background-color:#032}.bg-\[\#003322\]\/50{background-color:#00332280}.bg-\[\#111118\]{background-color:#111118}.bg-\[\#331111\]{background-color:#311}.bg-\[\#ef4444\]\/10{background-color:#ef44441a}.bg-\[\#ef444410\]{background-color:#ef444410}.bg-\[\#ff3366\]\/10{background-color:#ff33661a}.bg-\[\#ff336610\]{background-color:#ff336610}.bg-amber-500\/5{background-color:#f99c000d}@supports (color:color-mix(in lab,red,red)){.bg-amber-500\/5{background-color:color-mix(in oklab,var(--color-amber-500) 5%,transparent)}}.bg-black{background-color:var(--color-black)}.bg-black\/60{background-color:#0009}@supports (color:color-mix(in lab,red,red)){.bg-black\/60{background-color:color-mix(in oklab,var(--color-black) 60%,transparent)}}.bg-current{background-color:currentColor}.bg-cyan-950\/80{background-color:#053345cc}@supports (color:color-mix(in lab,red,red)){.bg-cyan-950\/80{background-color:color-mix(in oklab,var(--color-cyan-950) 80%,transparent)}}.bg-emerald-400\/10{background-color:#00d2941a}@supports (color:color-mix(in lab,red,red)){.bg-emerald-400\/10{background-color:color-mix(in oklab,var(--color-emerald-400) 10%,transparent)}}.bg-emerald-500\/5{background-color:#00bb7f0d}@supports (color:color-mix(in lab,red,red)){.bg-emerald-500\/5{background-color:color-mix(in oklab,var(--color-emerald-500) 5%,transparent)}}.bg-gray-500\/10{background-color:#6a72821a}@supports (color:color-mix(in lab,red,red)){.bg-gray-500\/10{background-color:color-mix(in oklab,var(--color-gray-500) 10%,transparent)}}.bg-green-900\/30{background-color:#0d542b4d}@supports (color:color-mix(in lab,red,red)){.bg-green-900\/30{background-color:color-mix(in oklab,var(--color-green-900) 30%,transparent)}}.bg-green-950\/80{background-color:#032e15cc}@supports (color:color-mix(in lab,red,red)){.bg-green-950\/80{background-color:color-mix(in oklab,var(--color-green-950) 80%,transparent)}}.bg-red-400\/10{background-color:#ff65681a}@supports (color:color-mix(in lab,red,red)){.bg-red-400\/10{background-color:color-mix(in oklab,var(--color-red-400) 10%,transparent)}}.bg-red-500\/5{background-color:#fb2c360d}@supports (color:color-mix(in lab,red,red)){.bg-red-500\/5{background-color:color-mix(in oklab,var(--color-red-500) 5%,transparent)}}.bg-red-500\/10{background-color:#fb2c361a}@supports (color:color-mix(in lab,red,red)){.bg-red-500\/10{background-color:color-mix(in oklab,var(--color-red-500) 10%,transparent)}}.bg-red-900\/30{background-color:#82181a4d}@supports (color:color-mix(in lab,red,red)){.bg-red-900\/30{background-color:color-mix(in oklab,var(--color-red-900) 30%,transparent)}}.bg-red-950\/80{background-color:#460809cc}@supports (color:color-mix(in lab,red,red)){.bg-red-950\/80{background-color:color-mix(in oklab,var(--color-red-950) 80%,transparent)}}.bg-transparent{background-color:#0000}.bg-void{background-color:var(--color-void)}.bg-void-light{background-color:var(--color-void-light)}.bg-void-lighter{background-color:var(--color-void-lighter)}.bg-yellow-900\/30{background-color:#733e0a4d}@supports (color:color-mix(in lab,red,red)){.bg-yellow-900\/30{background-color:color-mix(in oklab,var(--color-yellow-900) 30%,transparent)}}.bg-yellow-950\/80{background-color:#432004cc}@supports (color:color-mix(in lab,red,red)){.bg-yellow-950\/80{background-color:color-mix(in oklab,var(--color-yellow-950) 80%,transparent)}}.object-contain{object-fit:contain}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-2{padding:calc(var(--spacing) * 2)}.p-2\.5{padding:calc(var(--spacing) * 2.5)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.p-12{padding:calc(var(--spacing) * 12)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-8{padding-block:calc(var(--spacing) * 8)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pb-0{padding-bottom:calc(var(--spacing) * 0)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[\#00e5ff\]{color:#00e5ff}.text-\[\#00ff88\]{color:#0f8}.text-\[\#3b82f6\]{color:#3b82f6}.text-\[\#9af5ff\]{color:#9af5ff}.text-\[\#10b981\]{color:#10b981}.text-\[\#333\]{color:#333}.text-\[\#444\]{color:#444}.text-\[\#555\]{color:#555}.text-\[\#666\]{color:#666}.text-\[\#888\]{color:#888}.text-\[\#bbb\]{color:#bbb}.text-\[\#c0c0d0\]{color:#c0c0d0}.text-\[\#e0e0e0\]{color:#e0e0e0}.text-\[\#ef4444\]{color:#ef4444}.text-\[\#f59e0b\]{color:#f59e0b}.text-\[\#fca5a5\]{color:#fca5a5}.text-\[\#fecaca\]{color:#fecaca}.text-\[\#ff3366\]{color:#f36}.text-\[\#ffaa00\]{color:#fa0}.text-amber-200{color:var(--color-amber-200)}.text-amber-200\/80{color:#fee685cc}@supports (color:color-mix(in lab,red,red)){.text-amber-200\/80{color:color-mix(in oklab,var(--color-amber-200) 80%,transparent)}}.text-amber-400{color:var(--color-amber-400)}.text-amber-500{color:var(--color-amber-500)}.text-blue-500{color:var(--color-blue-500)}.text-cyan-200{color:var(--color-cyan-200)}.text-emerald-200\/80{color:#a4f4cfcc}@supports (color:color-mix(in lab,red,red)){.text-emerald-200\/80{color:color-mix(in oklab,var(--color-emerald-200) 80%,transparent)}}.text-emerald-300{color:var(--color-emerald-300)}.text-emerald-400{color:var(--color-emerald-400)}.text-gray-100{color:var(--color-gray-100)}.text-gray-200{color:var(--color-gray-200)}.text-gray-300{color:var(--color-gray-300)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-700{color:var(--color-gray-700)}.text-green-200{color:var(--color-green-200)}.text-green-400{color:var(--color-green-400)}.text-red-200{color:var(--color-red-200)}.text-red-300{color:var(--color-red-300)}.text-red-400{color:var(--color-red-400)}.text-void{color:var(--color-void)}.text-yellow-200{color:var(--color-yellow-200)}.text-yellow-300{color:var(--color-yellow-300)}.text-yellow-400{color:var(--color-yellow-400)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.placeholder-gray-600::placeholder{color:var(--color-gray-600)}.opacity-40{opacity:.4}.opacity-60{opacity:.6}.opacity-75{opacity:.75}.opacity-80{opacity:.8}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),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(var(--blur-sm));-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-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.outline-none{--tw-outline-style:none;outline-style:none}.placeholder\:text-gray-500::placeholder{color:var(--color-gray-500)}@media(hover:hover){.hover\:border-l-2:hover{border-left-style:var(--tw-border-style);border-left-width:2px}.hover\:border-\[\#00e5ff\]\/30:hover{border-color:#00e5ff4d}.hover\:border-\[\#2a2a3e\]:hover{border-color:#2a2a3e}.hover\:border-\[\#3b82f6\]\/30:hover{border-color:#3b82f64d}.hover\:border-\[\#333\]:hover{border-color:#333}.hover\:border-gray-500:hover{border-color:var(--color-gray-500)}.hover\:bg-\[\#00e5ff\]\/20:hover{background-color:#00e5ff33}.hover\:bg-\[\#1a1a2e\]\/30:hover{background-color:#1a1a2e4d}.hover\:bg-\[\#2a2a3e\]:hover{background-color:#2a2a3e}.hover\:bg-\[\#3a2e00\]:hover{background-color:#3a2e00}.hover\:bg-\[\#3b82f6\]\/20:hover{background-color:#3b82f633}.hover\:bg-\[\#4a3900\]:hover{background-color:#4a3900}.hover\:bg-\[\#003744\]:hover{background-color:#003744}.hover\:bg-\[\#004433\]:hover{background-color:#043}.hover\:bg-\[\#442222\]:hover{background-color:#422}.hover\:bg-amber-500\/10:hover{background-color:#f99c001a}@supports (color:color-mix(in lab,red,red)){.hover\:bg-amber-500\/10:hover{background-color:color-mix(in oklab,var(--color-amber-500) 10%,transparent)}}.hover\:bg-green-900\/50:hover{background-color:#0d542b80}@supports (color:color-mix(in lab,red,red)){.hover\:bg-green-900\/50:hover{background-color:color-mix(in oklab,var(--color-green-900) 50%,transparent)}}.hover\:bg-red-500\/10:hover{background-color:#fb2c361a}@supports (color:color-mix(in lab,red,red)){.hover\:bg-red-500\/10:hover{background-color:color-mix(in oklab,var(--color-red-500) 10%,transparent)}}.hover\:bg-red-900\/50:hover{background-color:#82181a80}@supports (color:color-mix(in lab,red,red)){.hover\:bg-red-900\/50:hover{background-color:color-mix(in oklab,var(--color-red-900) 50%,transparent)}}.hover\:bg-void-lighter:hover{background-color:var(--color-void-lighter)}.hover\:bg-yellow-900\/50:hover{background-color:#733e0a80}@supports (color:color-mix(in lab,red,red)){.hover\:bg-yellow-900\/50:hover{background-color:color-mix(in oklab,var(--color-yellow-900) 50%,transparent)}}.hover\:text-\[\#00e5ff\]:hover{color:#00e5ff}.hover\:text-\[\#777\]:hover{color:#777}.hover\:text-\[\#888\]:hover{color:#888}.hover\:text-\[\#e0e0e0\]:hover{color:#e0e0e0}.hover\:text-\[\#ef4444\]:hover{color:#ef4444}.hover\:text-emerald-200:hover{color:var(--color-emerald-200)}.hover\:text-gray-100:hover{color:var(--color-gray-100)}.hover\:text-gray-200:hover{color:var(--color-gray-200)}.hover\:text-gray-300:hover{color:var(--color-gray-300)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}}.focus\:border-\[\#00e5ff\]:focus{border-color:#00e5ff}.focus\:border-\[\#3b82f6\]:focus{border-color:#3b82f6}.focus\:border-\[\#ffaa00\]:focus{border-color:#fa0}.focus\:ring-1:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.active\:bg-\[\#1a1a2e\]\/50:active{background-color:#1a1a2e80}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}@media(min-width:40rem){.sm\:flex{display:flex}.sm\:inline{display:inline}.sm\:inline-block{display:inline-block}.sm\:h-\[calc\(100vh-420px\)\]{height:calc(100vh - 420px)}.sm\:h-\[calc\(100vh-460px\)\]{height:calc(100vh - 460px)}.sm\:min-h-\[300px\]{min-height:300px}.sm\:min-h-\[400px\]{min-height:400px}.sm\:max-w-xs{max-width:var(--container-xs)}.sm\:flex-row{flex-direction:row}.sm\:items-center{align-items:center}.sm\:justify-between{justify-content:space-between}.sm\:gap-2{gap:calc(var(--spacing) * 2)}.sm\:gap-3{gap:calc(var(--spacing) * 3)}.sm\:gap-4{gap:calc(var(--spacing) * 4)}:where(.sm\:space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}.sm\:p-4{padding:calc(var(--spacing) * 4)}.sm\:p-5{padding:calc(var(--spacing) * 5)}.sm\:px-4{padding-inline:calc(var(--spacing) * 4)}.sm\:px-5{padding-inline:calc(var(--spacing) * 5)}.sm\:py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.sm\:py-4{padding-block:calc(var(--spacing) * 4)}.sm\:text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}}@media(min-width:48rem){.md\:block{display:block}.md\:hidden{display:none}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-center{align-items:center}.md\:justify-between{justify-content:space-between}}@media(min-width:64rem){.lg\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.lg\:flex-row{flex-direction:row}.lg\:items-center{align-items:center}.lg\:items-start{align-items:flex-start}.lg\:justify-between{justify-content:space-between}}@media(min-width:80rem){.xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.xl\:grid-cols-\[minmax\(0\,360px\)_minmax\(0\,1fr\)\]{grid-template-columns:minmax(0,360px) minmax(0,1fr)}.xl\:flex-row{flex-direction:row}.xl\:items-start{align-items:flex-start}.xl\:justify-between{justify-content:space-between}}}body{font-family:var(--font-sans);background-color:var(--color-void);color:#e0e0e8}*{scrollbar-width:thin;scrollbar-color:var(--color-void-lighter) transparent}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:var(--color-void-lighter);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--color-accent-dim)}.status-dot{border-radius:50%;flex-shrink:0;width:8px;height:8px;display:inline-block}.status-dot--idle{background-color:var(--color-accent)}.status-dot--working{background-color:var(--color-warning);animation:1.5s ease-in-out infinite pulse}.status-dot--permission_prompt,.status-dot--bash_approval{background-color:var(--color-error);animation:1s ease-in-out infinite pulse}.status-dot--plan_mode,.status-dot--ask_question{background-color:var(--color-info)}.status-dot--settings{background-color:var(--color-warning)}.status-dot--unknown{background-color:#666}@keyframes pulse{50%{opacity:.5}}.font-code{font-family:var(--font-mono)}@keyframes slide-in{0%{opacity:0;transform:translate(100%)}to{opacity:1;transform:translate(0)}}.animate-slide-in{animation:.2s ease-out slide-in}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes ping{75%,to{opacity:0;transform:scale(2)}}
@@ -5,8 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Aegis Dashboard</title>
7
7
  <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🛡️</text></svg>" />
8
- <script type="module" crossorigin src="/dashboard/assets/index-DFdRqV0R.js"></script>
9
- <link rel="stylesheet" crossorigin href="/dashboard/assets/index--qcihe0P.css">
8
+ <script type="module" crossorigin src="/dashboard/assets/index-DhUXvnKe.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/dashboard/assets/index-hJxI_Ze7.css">
10
10
  </head>
11
11
  <body class="bg-[#0a0a0f] text-gray-200 antialiased">
12
12
  <div id="root"></div>
@@ -0,0 +1,197 @@
1
+ /**
2
+ * api-contracts.ts — Shared API contract types for backend and dashboard.
3
+ *
4
+ * Keep this file runtime-free (types only) so both packages can import it
5
+ * without bundling backend implementation code into the frontend.
6
+ */
7
+ export type UIState = 'idle' | 'working' | 'compacting' | 'context_warning' | 'waiting_for_input' | 'permission_prompt' | 'plan_mode' | 'ask_question' | 'bash_approval' | 'settings' | 'error' | 'unknown';
8
+ export type SessionStatusFilter = 'all' | UIState;
9
+ export interface SessionInfo {
10
+ id: string;
11
+ windowId: string;
12
+ windowName: string;
13
+ workDir: string;
14
+ claudeSessionId?: string;
15
+ jsonlPath?: string;
16
+ byteOffset: number;
17
+ monitorOffset: number;
18
+ status: UIState;
19
+ createdAt: number;
20
+ lastActivity: number;
21
+ stallThresholdMs: number;
22
+ permissionMode: string;
23
+ autoApprove?: boolean;
24
+ settingsPatched?: boolean;
25
+ promptDelivery?: {
26
+ delivered: boolean;
27
+ attempts: number;
28
+ };
29
+ actionHints?: Record<string, {
30
+ method: string;
31
+ url: string;
32
+ description: string;
33
+ }>;
34
+ }
35
+ export interface SessionHealth {
36
+ alive: boolean;
37
+ windowExists: boolean;
38
+ claudeRunning: boolean;
39
+ paneCommand: string | null;
40
+ status: UIState;
41
+ hasTranscript: boolean;
42
+ lastActivity: number;
43
+ lastActivityAgo: number;
44
+ sessionAge: number;
45
+ details: string;
46
+ actionHints?: Record<string, {
47
+ method: string;
48
+ url: string;
49
+ description: string;
50
+ }>;
51
+ }
52
+ export interface HealthResponse {
53
+ status: string;
54
+ version: string;
55
+ uptime: number;
56
+ sessions: {
57
+ active: number;
58
+ total: number;
59
+ };
60
+ timestamp: string;
61
+ }
62
+ export interface ParsedEntry {
63
+ role: 'user' | 'assistant' | 'system';
64
+ contentType: 'text' | 'thinking' | 'tool_use' | 'tool_result' | 'tool_error' | 'permission_request' | 'progress';
65
+ text: string;
66
+ toolName?: string;
67
+ toolUseId?: string;
68
+ timestamp?: string;
69
+ }
70
+ export interface MessagesResponse {
71
+ messages: ParsedEntry[];
72
+ status: UIState;
73
+ statusText: string | null;
74
+ interactiveContent: string | null;
75
+ }
76
+ export interface SessionMetrics {
77
+ durationSec: number;
78
+ messages: number;
79
+ toolCalls: number;
80
+ approvals: number;
81
+ autoApprovals: number;
82
+ statusChanges: string[];
83
+ }
84
+ export interface LatencySummaryStat {
85
+ min: number | null;
86
+ max: number | null;
87
+ avg: number | null;
88
+ count: number;
89
+ }
90
+ export interface SessionLatency {
91
+ sessionId: string;
92
+ realtime: {
93
+ hook_latency_ms: number | null;
94
+ state_change_detection_ms: number | null;
95
+ permission_response_ms: number | null;
96
+ } | null;
97
+ aggregated: {
98
+ hook_latency_ms: LatencySummaryStat;
99
+ state_change_detection_ms: LatencySummaryStat;
100
+ permission_response_ms: LatencySummaryStat;
101
+ channel_delivery_ms: LatencySummaryStat;
102
+ } | null;
103
+ }
104
+ export interface GlobalMetrics {
105
+ uptime: number;
106
+ sessions: {
107
+ total_created: number;
108
+ currently_active: number;
109
+ completed: number;
110
+ failed: number;
111
+ avg_duration_sec: number;
112
+ avg_messages_per_session: number;
113
+ };
114
+ auto_approvals: number;
115
+ webhooks_sent: number;
116
+ webhooks_failed: number;
117
+ screenshots_taken: number;
118
+ pipelines_created: number;
119
+ batches_created: number;
120
+ prompt_delivery: {
121
+ sent: number;
122
+ delivered: number;
123
+ failed: number;
124
+ success_rate: number | null;
125
+ };
126
+ latency: {
127
+ hook_latency_ms: LatencySummaryStat;
128
+ state_change_detection_ms: LatencySummaryStat;
129
+ permission_response_ms: LatencySummaryStat;
130
+ channel_delivery_ms: LatencySummaryStat;
131
+ };
132
+ }
133
+ export type SSEEventType = 'status' | 'message' | 'approval' | 'ended' | 'heartbeat' | 'stall' | 'dead' | 'system' | 'hook' | 'subagent_start' | 'subagent_stop' | 'verification';
134
+ export interface SessionSSEEvent {
135
+ event: SSEEventType;
136
+ sessionId: string;
137
+ timestamp: string;
138
+ emittedAt?: number;
139
+ data: Record<string, unknown>;
140
+ }
141
+ export type GlobalSSEEventType = 'session_status_change' | 'session_message' | 'session_approval' | 'session_ended' | 'session_created' | 'session_stall' | 'session_dead' | 'session_subagent_start' | 'session_subagent_stop' | 'session_verification';
142
+ export interface GlobalSSEEvent {
143
+ event: GlobalSSEEventType;
144
+ sessionId: string;
145
+ timestamp: string;
146
+ data: Record<string, unknown>;
147
+ }
148
+ export interface CreateSessionRequest {
149
+ workDir: string;
150
+ name?: string;
151
+ prompt?: string;
152
+ resumeSessionId?: string;
153
+ claudeCommand?: string;
154
+ env?: Record<string, string>;
155
+ stallThresholdMs?: number;
156
+ permissionMode?: string;
157
+ autoApprove?: boolean;
158
+ parentId?: string;
159
+ memoryKeys?: string[];
160
+ }
161
+ export interface PaneResponse {
162
+ pane: string;
163
+ }
164
+ export interface SessionSummary {
165
+ sessionId: string;
166
+ windowName: string;
167
+ status: UIState;
168
+ totalMessages: number;
169
+ messages: Array<{
170
+ role: string;
171
+ contentType: string;
172
+ text: string;
173
+ }>;
174
+ createdAt: number;
175
+ lastActivity: number;
176
+ permissionMode: string;
177
+ }
178
+ export interface OkResponse {
179
+ ok: boolean;
180
+ }
181
+ export interface SendResponse extends OkResponse {
182
+ delivered: boolean;
183
+ attempts: number;
184
+ }
185
+ export interface ApiError {
186
+ error: string;
187
+ }
188
+ export interface SessionsListResponse {
189
+ sessions: SessionInfo[];
190
+ pagination: {
191
+ page: number;
192
+ limit: number;
193
+ total: number;
194
+ totalPages: number;
195
+ };
196
+ }
197
+ export type SessionStatusCounts = Record<SessionStatusFilter, number>;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * api-contracts.ts — Shared API contract types for backend and dashboard.
3
+ *
4
+ * Keep this file runtime-free (types only) so both packages can import it
5
+ * without bundling backend implementation code into the frontend.
6
+ */
7
+ export {};
@@ -0,0 +1,14 @@
1
+ import type { SessionInfo as InternalSessionInfo, SessionManager } from './session.js';
2
+ import type { MetricsCollector, SessionLatencySummary } from './metrics.js';
3
+ import type { SessionSSEEvent as InternalSessionSSEEvent, GlobalSSEEvent as InternalGlobalSSEEvent } from './events.js';
4
+ import type { SessionInfo, MessagesResponse, SessionSummary, SessionMetrics, SessionLatency, GlobalMetrics, SessionSSEEvent, GlobalSSEEvent } from './api-contracts.js';
5
+ type Assert<T extends true> = T;
6
+ export type SessionInfoContractCompat = Assert<InternalSessionInfo extends SessionInfo ? true : false>;
7
+ export type SessionReadMessagesContractCompat = Assert<Awaited<ReturnType<SessionManager['readMessages']>> extends MessagesResponse ? true : false>;
8
+ export type SessionSummaryContractCompat = Assert<Awaited<ReturnType<SessionManager['getSummary']>> extends SessionSummary ? true : false>;
9
+ export type SessionMetricsContractCompat = Assert<NonNullable<ReturnType<MetricsCollector['getSessionMetrics']>> extends SessionMetrics ? true : false>;
10
+ export type SessionLatencySummaryContractCompat = Assert<SessionLatencySummary extends NonNullable<SessionLatency['aggregated']> ? true : false>;
11
+ export type GlobalMetricsContractCompat = Assert<ReturnType<MetricsCollector['getGlobalMetrics']> extends GlobalMetrics ? true : false>;
12
+ export type SessionSSEContractCompat = Assert<InternalSessionSSEEvent extends SessionSSEEvent ? true : false>;
13
+ export type GlobalSSEContractCompat = Assert<InternalGlobalSSEEvent extends GlobalSSEEvent ? true : false>;
14
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -13,10 +13,13 @@ export interface TelegramChannelConfig {
13
13
  botToken: string;
14
14
  groupChatId: string;
15
15
  allowedUserIds: number[];
16
+ topicTtlMs?: number;
16
17
  }
17
18
  export declare class TelegramChannel implements Channel {
18
19
  private config;
19
20
  readonly name = "telegram";
21
+ static readonly DEFAULT_TOPIC_TTL_MS: number;
22
+ private static readonly TOPIC_CLEANUP_RETRY_MS;
20
23
  private topics;
21
24
  private progress;
22
25
  private pollOffset;
@@ -24,6 +27,9 @@ export declare class TelegramChannel implements Channel {
24
27
  private rateLimitUntil;
25
28
  private pollBackoffMs;
26
29
  private onInbound;
30
+ private topicCleanupTimers;
31
+ private topicCleanupSweepTimer;
32
+ private readonly topicTtlMs;
27
33
  private messageQueue;
28
34
  private lastSent;
29
35
  private flushTimers;
@@ -66,7 +72,12 @@ export declare class TelegramChannel implements Channel {
66
72
  private decrementInFlight;
67
73
  private queueMessage;
68
74
  private flushQueue;
69
- private cleanup;
75
+ private cleanupSessionRuntimeState;
76
+ private startTopicCleanupSweep;
77
+ private clearTopicCleanupTimer;
78
+ private scheduleTopicCleanup;
79
+ private runTopicCleanup;
80
+ private isIgnorableTopicDeleteError;
70
81
  private handleSwarmCommand;
71
82
  private pollLoop;
72
83
  /** Issue #348: Redact bot token from error messages before logging. */
@@ -482,6 +482,8 @@ function formatProgressCard(progress) {
482
482
  export class TelegramChannel {
483
483
  config;
484
484
  name = 'telegram';
485
+ static DEFAULT_TOPIC_TTL_MS = 24 * 60 * 60 * 1000;
486
+ static TOPIC_CLEANUP_RETRY_MS = 60_000;
485
487
  topics = new Map();
486
488
  progress = new Map();
487
489
  pollOffset = 0;
@@ -489,6 +491,9 @@ export class TelegramChannel {
489
491
  rateLimitUntil = 0;
490
492
  pollBackoffMs = 1_000; // Exponential backoff for poll errors
491
493
  onInbound = null;
494
+ topicCleanupTimers = new Map();
495
+ topicCleanupSweepTimer = null;
496
+ topicTtlMs;
492
497
  // Rate limiting & batching
493
498
  messageQueue = new Map();
494
499
  lastSent = new Map();
@@ -512,6 +517,10 @@ export class TelegramChannel {
512
517
  }
513
518
  constructor(config) {
514
519
  this.config = config;
520
+ const configuredTtlMs = config.topicTtlMs ?? TelegramChannel.DEFAULT_TOPIC_TTL_MS;
521
+ this.topicTtlMs = Number.isFinite(configuredTtlMs)
522
+ ? Math.max(0, configuredTtlMs)
523
+ : TelegramChannel.DEFAULT_TOPIC_TTL_MS;
515
524
  }
516
525
  /** Call Telegram Bot API with retry on 429. Instance method so it can access rateLimitUntil. */
517
526
  async tgApi(method, body, retries = 3) {
@@ -550,6 +559,7 @@ export class TelegramChannel {
550
559
  async init(onInbound) {
551
560
  this.onInbound = onInbound;
552
561
  this.polling = true;
562
+ this.startTopicCleanupSweep();
553
563
  this.pollLoopPromise = this.pollLoop(); // store promise for graceful shutdown
554
564
  console.log(`Telegram channel: polling started, group ${this.config.groupChatId}`);
555
565
  }
@@ -565,8 +575,15 @@ export class TelegramChannel {
565
575
  clearTimeout(timer);
566
576
  for (const timer of this.readTimer.values())
567
577
  clearTimeout(timer);
578
+ for (const timer of this.topicCleanupTimers.values())
579
+ clearTimeout(timer);
580
+ if (this.topicCleanupSweepTimer) {
581
+ clearInterval(this.topicCleanupSweepTimer);
582
+ this.topicCleanupSweepTimer = null;
583
+ }
568
584
  this.flushTimers.clear();
569
585
  this.readTimer.clear();
586
+ this.topicCleanupTimers.clear();
570
587
  }
571
588
  async onSessionCreated(payload) {
572
589
  const topicName = `🤖 ${payload.session.name}`;
@@ -575,10 +592,14 @@ export class TelegramChannel {
575
592
  name: topicName,
576
593
  }));
577
594
  const topicId = result.message_thread_id;
595
+ this.clearTopicCleanupTimer(payload.session.id);
578
596
  this.topics.set(payload.session.id, {
579
597
  sessionId: payload.session.id,
580
598
  topicId,
581
599
  windowName: payload.session.name,
600
+ endedAt: null,
601
+ cleanupScheduledAt: null,
602
+ deleting: false,
582
603
  });
583
604
  this.progress.set(payload.session.id, {
584
605
  totalMessages: 0,
@@ -638,7 +659,8 @@ export class TelegramChannel {
638
659
  const styled = quickUpdate('✅', `${payload.session.name} — Session ended`);
639
660
  await this.sendStyled(payload.session.id, styled);
640
661
  }
641
- this.cleanup(payload.session.id);
662
+ this.scheduleTopicCleanup(payload.session.id);
663
+ this.cleanupSessionRuntimeState(payload.session.id);
642
664
  }
643
665
  async onMessage(payload) {
644
666
  // Issue #46: If topic doesn't exist yet, buffer the message
@@ -1126,8 +1148,7 @@ export class TelegramChannel {
1126
1148
  await this.sendToTopic(sessionId, groups[i]);
1127
1149
  }
1128
1150
  }
1129
- cleanup(sessionId) {
1130
- this.topics.delete(sessionId);
1151
+ cleanupSessionRuntimeState(sessionId) {
1131
1152
  this.progress.delete(sessionId);
1132
1153
  this.lastSent.delete(sessionId);
1133
1154
  this.pendingTool.delete(sessionId);
@@ -1146,6 +1167,105 @@ export class TelegramChannel {
1146
1167
  this.readTimer.delete(sessionId);
1147
1168
  }
1148
1169
  }
1170
+ startTopicCleanupSweep() {
1171
+ if (this.topicCleanupSweepTimer)
1172
+ return;
1173
+ const sweepMs = Math.min(60_000, Math.max(5_000, this.topicTtlMs || 5_000));
1174
+ this.topicCleanupSweepTimer = setInterval(() => {
1175
+ for (const [sessionId, topic] of this.topics) {
1176
+ if (topic.endedAt === null)
1177
+ continue;
1178
+ if (topic.deleting)
1179
+ continue;
1180
+ if (Date.now() >= topic.endedAt + this.topicTtlMs) {
1181
+ void this.runTopicCleanup(sessionId);
1182
+ }
1183
+ }
1184
+ }, sweepMs);
1185
+ if (typeof this.topicCleanupSweepTimer.unref === 'function') {
1186
+ this.topicCleanupSweepTimer.unref();
1187
+ }
1188
+ }
1189
+ clearTopicCleanupTimer(sessionId) {
1190
+ const timer = this.topicCleanupTimers.get(sessionId);
1191
+ if (timer) {
1192
+ clearTimeout(timer);
1193
+ this.topicCleanupTimers.delete(sessionId);
1194
+ }
1195
+ }
1196
+ scheduleTopicCleanup(sessionId) {
1197
+ const topic = this.topics.get(sessionId);
1198
+ if (!topic)
1199
+ return;
1200
+ if (topic.endedAt === null) {
1201
+ topic.endedAt = Date.now();
1202
+ }
1203
+ if (topic.cleanupScheduledAt !== null) {
1204
+ return;
1205
+ }
1206
+ const cleanupAt = topic.endedAt + this.topicTtlMs;
1207
+ topic.cleanupScheduledAt = cleanupAt;
1208
+ const delayMs = Math.max(0, cleanupAt - Date.now());
1209
+ if (delayMs === 0) {
1210
+ void this.runTopicCleanup(sessionId);
1211
+ return;
1212
+ }
1213
+ this.clearTopicCleanupTimer(sessionId);
1214
+ const timer = setTimeout(() => {
1215
+ void this.runTopicCleanup(sessionId);
1216
+ }, delayMs);
1217
+ this.topicCleanupTimers.set(sessionId, timer);
1218
+ if (typeof timer.unref === 'function') {
1219
+ timer.unref();
1220
+ }
1221
+ }
1222
+ async runTopicCleanup(sessionId) {
1223
+ const topic = this.topics.get(sessionId);
1224
+ if (!topic || topic.endedAt === null || topic.deleting)
1225
+ return;
1226
+ if (Date.now() < topic.endedAt + this.topicTtlMs) {
1227
+ return;
1228
+ }
1229
+ topic.deleting = true;
1230
+ this.clearTopicCleanupTimer(sessionId);
1231
+ const body = {
1232
+ chat_id: this.config.groupChatId,
1233
+ message_thread_id: topic.topicId,
1234
+ };
1235
+ try {
1236
+ try {
1237
+ await this.tgApi('closeForumTopic', body);
1238
+ }
1239
+ catch (e) {
1240
+ if (!this.isIgnorableTopicDeleteError(e)) {
1241
+ throw e;
1242
+ }
1243
+ }
1244
+ await this.tgApi('deleteForumTopic', body);
1245
+ this.topics.delete(sessionId);
1246
+ }
1247
+ catch (e) {
1248
+ if (this.isIgnorableTopicDeleteError(e)) {
1249
+ this.topics.delete(sessionId);
1250
+ }
1251
+ else {
1252
+ console.error(`Telegram: failed to cleanup topic for session ${sessionId}:`, this.redactError(e));
1253
+ topic.deleting = false;
1254
+ topic.cleanupScheduledAt = null;
1255
+ const timer = setTimeout(() => {
1256
+ void this.runTopicCleanup(sessionId);
1257
+ }, TelegramChannel.TOPIC_CLEANUP_RETRY_MS);
1258
+ this.topicCleanupTimers.set(sessionId, timer);
1259
+ if (typeof timer.unref === 'function') {
1260
+ timer.unref();
1261
+ }
1262
+ }
1263
+ }
1264
+ }
1265
+ isIgnorableTopicDeleteError(err) {
1266
+ const message = err instanceof Error ? err.message : String(err);
1267
+ return /not found|message thread|topic.*(?:closed|deleted)|forum topic/i.test(message);
1268
+ }
1149
1269
  // ── /swarm command ──────────────────────────────────────────────────
1150
1270
  async handleSwarmCommand(sessionId) {
1151
1271
  if (!this.swarmMonitor) {
package/dist/config.d.ts CHANGED
@@ -35,6 +35,8 @@ export interface Config {
35
35
  tgGroupId: string;
36
36
  /** Allowed Telegram user IDs for inbound commands (empty = allow all) */
37
37
  tgAllowedUsers: number[];
38
+ /** TTL for Telegram forum topics after session end, in milliseconds. */
39
+ tgTopicTtlMs: number;
38
40
  /** Webhook URLs (comma-separated or array) */
39
41
  webhooks: string[];
40
42
  /** Default env vars injected into every CC session (e.g. model overrides, API keys).
package/dist/config.js CHANGED
@@ -39,6 +39,7 @@ const defaults = {
39
39
  tgBotToken: '',
40
40
  tgGroupId: '',
41
41
  tgAllowedUsers: [],
42
+ tgTopicTtlMs: 24 * 60 * 60 * 1000,
42
43
  webhooks: [],
43
44
  defaultSessionEnv: {},
44
45
  defaultPermissionMode: 'bypassPermissions',
@@ -126,6 +127,7 @@ function applyEnvOverrides(config) {
126
127
  { aegis: 'AEGIS_TG_TOKEN', manus: 'MANUS_TG_TOKEN', key: 'tgBotToken' },
127
128
  { aegis: 'AEGIS_TG_GROUP', manus: 'MANUS_TG_GROUP', key: 'tgGroupId' },
128
129
  { aegis: 'AEGIS_TG_ALLOWED_USERS', manus: 'MANUS_TG_ALLOWED_USERS', key: 'tgAllowedUsers' },
130
+ { aegis: 'AEGIS_TG_TOPIC_TTL_MS', manus: 'MANUS_TG_TOPIC_TTL_MS', key: 'tgTopicTtlMs' },
129
131
  { aegis: 'AEGIS_WEBHOOKS', manus: 'MANUS_WEBHOOKS', key: 'webhooks' },
130
132
  { aegis: 'AEGIS_SSE_MAX_CONNECTIONS', manus: 'MANUS_SSE_MAX_CONNECTIONS', key: 'sseMaxConnections' },
131
133
  { aegis: 'AEGIS_SSE_MAX_PER_IP', manus: 'MANUS_SSE_MAX_PER_IP', key: 'sseMaxPerIp' },
@@ -140,6 +142,7 @@ function applyEnvOverrides(config) {
140
142
  case 'maxSessionAgeMs':
141
143
  case 'reaperIntervalMs':
142
144
  case 'continuationPointerTtlMs':
145
+ case 'tgTopicTtlMs':
143
146
  case 'sseMaxConnections':
144
147
  case 'sseMaxPerIp':
145
148
  config[key] = parseIntSafe(value, config[key]);
package/dist/events.d.ts CHANGED
@@ -35,6 +35,10 @@ export interface GlobalSSEEvent {
35
35
  /** Issue #301: Incrementing event ID for Last-Event-ID replay. */
36
36
  id?: number;
37
37
  }
38
+ interface SessionEventBusOptions {
39
+ /** Maximum number of per-session replay buffers retained in memory. */
40
+ maxSessionBuffers?: number;
41
+ }
38
42
  /**
39
43
  * Per-session event bus. Subscribers (SSE connections) register here.
40
44
  * The monitor calls emit() when events happen.
@@ -51,8 +55,14 @@ export declare class SessionEventBus {
51
55
  private static readonly BUFFER_SIZE;
52
56
  /** Per-session ring buffer for event replay. */
53
57
  private eventBuffers;
58
+ /** Last activity time per session buffer for LRU eviction. */
59
+ private sessionBufferLastTouched;
54
60
  /** Global ring buffer for event replay across all sessions (Issue #301). */
55
61
  private globalEventBuffer;
62
+ private readonly maxSessionBuffers;
63
+ constructor(options?: SessionEventBusOptions);
64
+ private touchSessionBuffer;
65
+ private pruneSessionBufferMap;
56
66
  /** Get or create the emitter for a session. */
57
67
  private getEmitter;
58
68
  /** Subscribe to events for a session. Returns unsubscribe function. */
@@ -120,3 +130,4 @@ export declare class SessionEventBus {
120
130
  /** Clean up all emitters. */
121
131
  destroy(): void;
122
132
  }
133
+ export {};