@dadigua/web-terminal 0.1.4 → 0.1.5

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
+ .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;inset:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.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;inset:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{font-family:monospace;-webkit-user-select:text;user-select:text;white-space:pre}.xterm .xterm-accessibility-tree>div{transform-origin:left;width:fit-content}.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}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;background:#0000;transition:opacity .1s linear;z-index:11}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{position:absolute;display:none}.xterm .xterm-scrollable-element>.shadow.top{display:block;top:0;left:3px;height:3px;width:100%;box-shadow:var(--vscode-scrollbar-shadow, #000) 0 6px 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.left{display:block;top:3px;left:0;height:100%;width:3px;box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.top-left-corner{display:block;top:0;left:0;height:3px;width:3px}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}:root{font-family:Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,sans-serif;color:#d9e5e9;background:#0b1219;font-synthesis:none}*{box-sizing:border-box}body{margin:0}button,input,.draft-input{font:inherit}button{cursor:pointer;border:1px solid #2a3c47;background:#182630;color:#d9e5e9;border-radius:8px;padding:8px 11px;transition:background .15s,border-color .15s}button:hover:not(:disabled){background:#25404a;border-color:#4c7580}button:disabled{opacity:.45;cursor:default}input,.draft-input{min-width:0;border:1px solid #2b414d;background:#111f29;color:#e9f1f3;border-radius:8px;padding:10px 11px;outline:none}input:focus,.draft-input:focus{border-color:#55b5aa;box-shadow:0 0 0 3px #55b5aa22}.primary{background:#4fb6a8;color:#06201f;border-color:#4fb6a8;font-weight:700}.primary:hover:not(:disabled){background:#70d0c2;color:#06201f}.app{display:flex;flex-direction:column;height:var(--app-height,100dvh);min-height:0;position:fixed;top:var(--app-top,0px);left:0;right:0}.brand-mark{display:inline-grid;place-items:center;width:36px;height:36px;border-radius:9px;background:#174a4a;color:#7de8d4;font-weight:800;font-size:19px;font-family:monospace}.tabs-bar{position:relative;display:flex;flex:none;align-items:center;min-width:0;min-height:32px;background:#0d1821;border-bottom:1px solid #263640;padding:3px 5px;gap:3px;font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,sans-serif;font-size:12px;container-type:inline-size}.session-list{display:flex;align-items:stretch;gap:2px;overflow-x:auto;overflow-y:hidden;min-width:0;flex:1;scrollbar-width:none}.session-list::-webkit-scrollbar{display:none}.session{display:flex;align-items:center;flex:1 1 124px;min-width:64px;max-width:148px;height:26px;container:session-tab / inline-size;border-radius:4px;background:#13212b}.session.active{background:#263a45;box-shadow:inset 0 -1px #80cdbf}.session-select{display:flex;align-items:center;gap:4px;flex:1;min-width:0;height:26px;text-align:left;background:transparent;border:0;border-radius:4px;padding:3px 4px;overflow:hidden}.session-select strong{flex:1;min-width:0;font-size:12px;font-weight:400;line-height:16px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.session-select small{flex:0 1 auto;font-size:11px;color:#849da7;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:44px}.session .end,.tab-more{display:grid;place-items:center;flex:none;width:16px;height:22px;border:0;background:transparent;font-size:15px;line-height:1;color:#9ab0bc;padding:0;border-radius:3px;opacity:0}.tab-more{display:none}.session:hover .tab-more,.session:focus-within .tab-more{display:grid;opacity:1}.session:hover .end,.session:focus-within .end,.session.active .end{opacity:1}.dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:#6e8290;flex:none}.dot.live{background:#64d6ae;box-shadow:0 0 0 2px #64d6ae20}.dot.offline{background:transparent;border:1px solid #dc8c7f}.command-icon{flex:none;font-family:monospace;font-size:12px;color:#b5d8d2}.command-icon.claude{color:#db997c}.tab-actions{display:flex;flex:none;gap:1px}.tab-actions button{display:grid;place-items:center;min-width:26px;height:26px;border:0;background:transparent;padding:3px;font-size:18px;border-radius:4px}.tab-actions svg{width:15px;height:15px}.workspace{flex:1;min-width:0;min-height:0;display:flex;flex-direction:column}.session-group{display:flex;align-items:center;gap:2px;flex:0 1 auto;min-width:min-content;box-shadow:inset 0 -2px var(--group-color);padding:0 1px}.session-group.collapsed{flex:none;box-shadow:none}.session-group-header{display:flex;align-items:center;flex:none;max-width:136px;gap:1px}.session-group-label{display:flex;align-items:center;gap:4px;height:24px;min-width:0;max-width:122px;padding:2px 5px;border:1px solid transparent;border-radius:4px;background:var(--group-color);color:#101821;font-size:12px;font-weight:500;white-space:nowrap}.session-group-label:hover:not(:disabled){background:var(--group-color);border-color:#e4eef8}.session-group-label.active{border-color:#edf7ff;box-shadow:0 0 0 1px #edf7ff33}.group-name{overflow:hidden;text-overflow:ellipsis;min-width:0}.group-count{font-size:10px;opacity:.8}.group-chevron{font-size:13px;flex:none;line-height:14px}.group-output{width:8px;height:8px;flex:none;border-radius:50%;border:1.5px solid #10182138;border-top-color:#101821;border-right-color:#101821;animation:output-spin .7s linear infinite}.group-more{flex:none;width:14px;height:22px;padding:0;border:0;border-radius:3px;background:transparent;font-size:15px;color:var(--group-color);opacity:0}.session-group-header:hover .group-more,.session-group-header:focus-within .group-more{opacity:1}.tabs-bar button:focus-visible,.tab-menu button:focus-visible{outline:1px solid #9ed8ee;outline-offset:-1px}.tab-menu{position:fixed;z-index:120;width:218px;max-width:calc(100vw - 16px);max-height:calc(100dvh - 16px);overflow-y:auto;padding:4px;border:1px solid #39515f;border-radius:6px;background:#172630;box-shadow:0 6px 24px #0007;font:12px/18px ui-sans-serif,system-ui,-apple-system,Segoe UI,sans-serif;color:#d9e5e9}.tab-menu button{display:flex;align-items:center;gap:7px;width:100%;min-height:28px;text-align:left;padding:4px 7px;border:0;border-radius:3px;background:transparent;font-size:12px;overflow-wrap:anywhere}.tab-menu button:hover:not(:disabled){background:#29414e}.tab-menu-caption{padding:6px 7px 2px;color:#91a8b5;font-size:11px}.tab-menu hr{border:0;border-top:1px solid #30444f;margin:4px}.menu-color{flex:none;width:8px;height:8px;border-radius:50%}.menu-check{margin-left:auto}.session-group-dialog{width:min(92vw,320px);padding:18px}.session-group-dialog h2{font-size:15px}.session-group-dialog label{display:block;font-size:12px;margin:12px 0 5px}.session-group-dialog input{width:100%;font-size:12px;padding:7px 9px}.group-colors{display:flex;gap:5px;flex-wrap:wrap;border:0;padding:0;margin:14px 0}.group-colors legend{font-size:12px;margin-bottom:8px}.group-colors button{display:grid;place-items:center;width:23px;height:23px;min-width:23px;padding:0;border:2px solid transparent;border-radius:50%;color:#101821;font-size:12px}.group-colors button[aria-pressed=true]{border-color:#e8f3ff}.session-group-dialog .session-close-actions button{font-size:12px;padding:6px 10px}@container session-tab (max-width:115px){.session-select small{display:none}}@container (max-width:360px){.session{max-width:130px}}@media(hover:none)and (pointer:coarse){.tabs-bar{min-height:38px}.session,.session-select{height:32px}.session{min-width:94px}.session .end,.tab-more,.group-more{display:grid;width:22px;height:30px;opacity:1}.session-group-label{height:30px}.tab-actions button{height:32px;min-width:30px}}.content{flex:1;min-height:0;display:flex}.terminal-pane{flex:1;min-width:0;display:flex;flex-direction:column;background:#101821}.terminal-wrap{flex:1;min-height:0;padding:15px 12px 4px;overflow:auto;overscroll-behavior:contain}.terminal-host{width:100%;height:100%;min-height:0}.xterm{height:100%}.draft-row{display:flex;min-width:0}.draft-row .draft-input{flex:1;font-size:12px}.mobile-keys{display:none}.upload-state{display:flex;align-items:center;gap:10px;justify-content:space-between;background:#18313a;padding:9px 14px;color:#b5e8df;font-size:12px;word-break:break-all}.upload-state.error,.error{color:#ffb3aa}.upload-state button{margin-left:auto;font-size:11px;padding:4px 7px;white-space:nowrap}.hover-card{position:fixed;z-index:10;width:220px;padding:7px;background:#1a2c35;border:1px solid #45616b;border-radius:9px;box-shadow:0 12px 35px #0009;pointer-events:none}.hover-card img{display:block;width:100%;max-height:165px;object-fit:contain}.hover-card span{display:block;font-size:11px;margin-top:6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hidden{display:none}.auth-shell{min-height:100dvh;display:grid;place-items:center;padding:20px;background:radial-gradient(circle at 50% 28%,#163039,#0b1219 55%)}.auth-card{width:min(100%,390px);padding:32px;background:#12212b;border:1px solid #2b414b;border-radius:17px;box-shadow:0 20px 70px #0005;display:grid;gap:13px}.auth-card h1{font-size:23px;margin:8px 0 0}.auth-card p{font-size:13px;color:#96adb7;line-height:1.5;margin:0 0 14px}.auth-card label{font-size:12px;color:#a7bec6}.auth-card .primary{margin-top:6px}.auth-card .error{font-size:12px}@media(max-width:760px){.content{position:relative}.terminal-wrap{padding:8px 5px 0}}.empty-session{position:absolute;z-index:2;inset:0 0 75px;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;background:#101821;color:#d5e7e9}.empty-session strong{font-size:18px}.empty-session p{font-size:13px;color:#89a3ad}.empty-session button{margin-top:10px}.terminal-pane{position:relative}.workspace{min-height:0}.upload-thumbnail{width:38px;height:30px;object-fit:cover;border-radius:4px;flex:none}.upload-state>span{flex:1}.upload-state button{margin-left:0}@media(hover:none)and (pointer:coarse){.mobile-keys{display:flex;gap:4px;padding:6px;flex-wrap:wrap;border-top:1px solid #243640}.mobile-keys button{flex:1;min-width:34px;min-height:42px;font-size:12px;padding:6px 4px;touch-action:manipulation}}.session-close-dialog{width:min(92vw,380px);box-sizing:border-box;border:1px solid #38535f;border-radius:12px;padding:22px;background:#12212b;color:#d9e5e9;box-shadow:0 20px 70px #0008}.session-close-dialog::backdrop{background:#0008}.session-close-dialog h2{font-size:17px;margin:0 0 12px;overflow-wrap:anywhere}.session-close-dialog p{font-size:13px;line-height:1.6;color:#a7bec6}.session-close-dialog .error{color:#ffb3aa}.session-close-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:20px}.session-ended-dialog{width:min(92vw,440px)}.session-ended-path{overflow-wrap:anywhere;font-family:ui-monospace,monospace}.session-ended-dialog .session-close-actions{flex-wrap:wrap}.terminal-progress{display:inline-flex;flex:none;width:14px;height:14px;color:#7bdfcd}.terminal-progress svg{transform:rotate(-90deg)}.progress-track{opacity:.2}.progress-state-2{color:#ed9388}.progress-state-4{color:#e3b967}.progress-state-3 svg{animation:output-spin .7s linear infinite}@media(prefers-reduced-motion:reduce){.progress-state-3 svg{animation:none}}.message-layer{position:fixed;z-index:100;top:max(16px,env(safe-area-inset-top));left:0;right:0;display:flex;justify-content:center;padding:0 16px;pointer-events:none}.message-toast{display:flex;align-items:center;gap:10px;max-width:min(520px,100%);padding:11px 14px;border:1px solid #3a515e;border-radius:9px;background:#20323e;color:#e7f0f3;box-shadow:0 6px 24px #0006;font-size:13px;line-height:1.5;pointer-events:auto;animation:message-appear .16s ease-out}.message-icon{flex:none;display:grid;place-items:center;width:18px;height:18px;border-radius:50%;background:#58c1b2;color:#09231f;font-weight:700;font-family:serif}.message-text{overflow-wrap:anywhere;min-width:0}.message-close{flex:none;padding:0 3px;border:0;background:transparent;color:#9fb5c0;font-size:19px;line-height:22px}@keyframes message-appear{0%{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}@media(prefers-reduced-motion:reduce){.message-toast{animation:none}}.directory-picker{width:min(560px,calc(100vw - 24px));max-height:calc(100dvh - 24px);border:1px solid #38535f;border-radius:12px;padding:18px;background:#12212b;color:#d9e5e9;box-shadow:0 20px 70px #0008;overflow:auto}.directory-picker::backdrop{background:#0007}.directory-picker header,.directory-picker footer{display:flex;align-items:center;justify-content:space-between;gap:8px}.directory-picker header button{background:transparent;border:0;font-size:20px}.directory-picker footer{justify-content:flex-end;margin-top:14px}.directory-path{display:flex;gap:6px;margin:14px 0 8px}.directory-path input{flex:1;width:0;font-size:12px}.directory-path button{padding:7px 9px;flex:none}.directory-filter{width:100%;font-size:12px}.directory-entries{height:min(260px,35dvh);overflow:auto;margin-top:8px}.directory-entries button{display:flex;align-items:center;gap:10px;width:100%;text-align:left;border:0;background:transparent;border-radius:5px;font-size:13px;overflow-wrap:anywhere}.directory-entries button span:last-child{margin-left:auto}.directory-entries p{font-size:12px;color:#8fa7af;padding:12px}.workspace-shortcuts small{display:block;color:#8fa7af;margin-bottom:6px}.workspace-shortcuts>div{display:flex;flex-wrap:wrap;gap:6px;max-height:100px;overflow:auto}.workspace-shortcuts button{font-size:12px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.directory-picker .error{font-size:12px;overflow-wrap:anywhere}@media(hover:none)and (pointer:coarse){.draft-row .draft-input{font-size:16px}.mobile-keys{flex-wrap:nowrap;overflow-x:auto;flex:none}.mobile-keys button{min-width:38px}.app .terminal-pane{min-height:0}}.draft-input{min-height:40px;max-height:100px;line-height:20px;white-space:pre-wrap;overflow-wrap:anywhere;overflow-y:auto;cursor:text}.draft-input:empty:before{content:attr(data-placeholder);color:#78909c;pointer-events:none}.session-pane[hidden]{display:none}.composer-dock{position:relative;flex:none;height:calc(112px + env(safe-area-inset-bottom,0px));container-type:inline-size;z-index:6}.composer-panel{position:absolute;left:12px;right:12px;bottom:max(10px,env(safe-area-inset-bottom));display:flex;flex-direction:column;gap:8px;padding:8px;border:1px solid #304953;border-radius:13px;background:#12232c;box-shadow:0 -6px 22px #0003}.composer-panel:focus-within{border-color:#4b978f;box-shadow:0 -6px 22px #0003,0 0 0 2px #4fb6a812}.composer-panel .draft-input{width:100%;min-height:38px;max-height:min(236px,max(38px,calc(var(--app-height,100dvh) - 180px)));padding:8px;border:0;border-radius:6px;background:transparent;font-size:14px;line-height:22px;box-shadow:none;scrollbar-width:thin;overscroll-behavior:contain}.composer-actions,.composer-tools{display:flex;align-items:center;gap:4px}.composer-actions{gap:8px;min-height:32px}.composer-tools{flex:none}.composer-tools button{display:inline-flex;align-items:center;justify-content:center;height:30px;padding:4px 7px;border:0;border-radius:6px;background:transparent;color:#96b0b9;font-size:11px}.composer-tools button:hover:not(:disabled){background:#223e48;color:#def3ee}.composer-divider{height:14px;width:1px;background:#30444d;margin:0 3px}.composer-hint{flex:1;text-align:right;color:#78939e;font-size:10px;white-space:nowrap}.composer-send{display:inline-flex;align-items:center;justify-content:center;gap:7px;margin-left:auto;min-width:70px;height:32px;padding:6px 11px;border:1px solid #4fb6a8;border-radius:8px;background:#4fb6a8;color:#062c28;font-size:12px;font-weight:600}.composer-send:hover:not(:disabled){border-color:#76d5c5;background:#76d5c5}.composer-send:disabled{opacity:1;border-color:#2c434c;background:#1a3039;color:#6c8791}.composer-attachments{display:flex;align-items:center;gap:8px;padding:6px;border:1px solid #304953;border-radius:11px;background:#142a31;min-width:0}.attachment-count{display:inline-flex;align-items:center;gap:3px;flex:none;font-size:12px;color:#b5d8d2;white-space:nowrap}.attachment-list{display:flex;gap:6px;min-width:0;flex:1;overflow-x:auto;scrollbar-width:thin}.attachment-card{flex:none;width:112px;padding:4px;border:1px solid #39545e;border-radius:8px;background:#10212a;overflow:hidden}.attachment-card .upload-thumbnail,.attachment-text{display:block;width:100%;height:76px;margin:0;border:1px solid #2b414d;border-radius:5px;background:#0b1821;object-fit:cover}.attachment-text{padding:5px;font:9px/12px ui-monospace,monospace;white-space:pre-wrap;overflow:hidden;overflow-wrap:anywhere;color:#b5d8d2}.attachment-caption{display:flex;align-items:center;gap:3px;height:23px;font-size:11px}.attachment-caption span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.attachment-caption button{border:0;background:transparent;padding:0 3px;font-size:17px;color:#96b0b9}.attachment-status{display:flex;align-items:center;justify-content:space-between;font-size:9px;line-height:15px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#86a59f}.attachment-status button{border:0;background:transparent;font-size:10px;padding:0 2px}.attachment-card.error{border-color:#bf766b}.attachment-card.error .attachment-status{color:#ffb3aa}.attachment-clear{flex:none;border:0;background:#263e42;font-size:11px;padding:5px 7px;white-space:nowrap}.composer-attachments{max-height:160px}@container (max-width:360px){.composer-attachments{gap:4px}.attachment-count{font-size:10px}.attachment-clear{font-size:10px;padding:5px 4px}}.composer-panel .mobile-keys{padding:0;border:0}@container (max-width:480px){.composer-hint{display:none}}@media(hover:none)and (pointer:coarse){.composer-dock{height:calc(124px + env(safe-area-inset-bottom,0px))}.composer-panel{left:4px;right:4px;bottom:max(6px,env(safe-area-inset-bottom));gap:2px;padding:4px;border-radius:10px}.composer-panel .draft-input{min-height:32px;padding:4px 6px;font-size:16px;line-height:24px}.composer-actions{gap:4px}.composer-tools{gap:2px}.composer-tools button{height:36px;min-width:36px}.composer-divider{margin:0 1px}.composer-send{height:36px;min-width:64px;padding:6px 8px}.composer-panel .mobile-keys{gap:2px}.composer-panel .mobile-keys button{min-height:36px;border-color:transparent;background:transparent;border-radius:6px}.composer-panel .mobile-keys button:hover:not(:disabled){background:#223e48}}.client-settings label{display:block;margin:14px 0 8px;font-size:13px}.client-settings input{width:100%}.font-preview{padding:12px;border:1px solid #304953;border-radius:8px;overflow-wrap:anywhere}.terminal-selection-handle{position:absolute;z-index:15;width:40px;height:44px;padding:0;border:0;background:transparent;border-radius:0;touch-action:none;cursor:grab}.terminal-selection-handle:before{content:"";position:absolute;left:19px;top:0;width:2px;height:22px;background:#7bdfcd}.terminal-selection-handle:after{content:"";position:absolute;left:12px;top:18px;width:16px;height:16px;border-radius:50%;background:#7bdfcd;border:2px solid #101821}.terminal-selection-handle:hover:not(:disabled){background:transparent}.terminal-touch-actions{position:absolute;z-index:16;display:flex;gap:4px;padding:4px;border:1px solid #42616c;border-radius:9px;background:#182b35;box-shadow:0 4px 18px #0006;touch-action:none}.terminal-touch-actions button{min-width:48px;min-height:40px;padding:6px 10px;font-size:13px}.terminal-touch-actions[hidden],.terminal-selection-handle[hidden]{display:none}.client-settings{width:min(92vw,520px);max-height:calc(var(--app-height,100dvh) - 32px);overflow:auto}.settings-section{border-top:1px solid #304953;margin-top:18px;padding-top:16px}.settings-section h3{font-size:14px;margin:0 0 10px}.client-settings select{width:100%;padding:10px 11px;border:1px solid #38535f;border-radius:8px;background:#111f29;color:#e9f1f3;font:inherit}.client-settings .settings-section p{margin:8px 0 12px}.tab-actions button[aria-label=设置]{display:inline-flex;align-items:center;justify-content:center}.composer-tools .copy-mode-toggle[aria-pressed=true]{background:#28594f;color:#a6f3df;box-shadow:inset 0 0 0 1px #5abfa9}.dot.live.output-active{background:transparent;border:1.5px solid #64d6ae35;border-top-color:#8df8d4;border-right-color:#8df8d4;box-shadow:0 0 5px #64d6ae40;animation:output-spin .7s linear infinite}@keyframes output-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.dot.live.output-active,.group-output{animation:none}.dot.live.output-active{border-color:#8df8d4}.group-output{border-color:#101821}}.file-preview-dialog{width:min(960px,calc(100vw - 32px));max-height:calc(var(--app-height,100dvh) - 32px);padding:18px;border:1px solid #38535f;border-radius:13px;background:#12212b;color:#d9e5e9;box-shadow:0 20px 70px #0008;overflow:auto}.file-preview-dialog::backdrop{background:#0009}.file-preview-dialog header,.file-preview-dialog footer{display:flex;align-items:center;gap:10px}.file-preview-dialog header h2{min-width:0;flex:1;font-size:17px;overflow-wrap:anywhere;margin:0}.file-preview-dialog header button{border:0;background:transparent;font-size:22px;padding:2px 8px}.file-preview-dialog .file-path{font-size:11px;color:#8ea7b0;overflow-wrap:anywhere;line-height:1.5}.file-preview-content{max-height:calc(var(--app-height,100dvh) - 210px);min-height:80px;overflow:auto;border:1px solid #2b414d;border-radius:8px;background:#0b1821}.file-preview-content pre{margin:0;padding:14px;font:12px/1.6 ui-monospace,monospace;white-space:pre;tab-size:2}.file-preview-content img{display:block;max-width:100%;max-height:calc(var(--app-height,100dvh) - 230px);object-fit:contain;margin:auto}.file-preview-content>p{margin:16px;font-size:13px;overflow-wrap:anywhere}.file-preview-dialog footer{justify-content:flex-end;margin-top:14px;font-size:12px}.file-preview-dialog footer span{margin-right:auto;color:#8ea7b0}.file-preview-dialog footer button{font-size:12px}.session[draggable=true],.session-group-header[draggable=true]{cursor:grab}.session.dragging,.session-group.dragging{opacity:.45}.session.drop-before{box-shadow:inset 2px 0 #a3e4d5}.session.drop-after{box-shadow:inset -2px 0 #a3e4d5}.session-group-header.drop-group{outline:2px solid var(--group-color);outline-offset:1px;border-radius:4px}.session-list.drop-end:after{content:"";flex:none;width:2px;background:#a3e4d5}
package/dist/index.html CHANGED
@@ -1,4 +1,4 @@
1
1
  <!doctype html>
2
- <html lang="zh-CN"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><meta name="theme-color" content="#101419"/><link rel="icon" href="/favicon.svg"/><title>Web Terminal</title> <script type="module" crossorigin src="/assets/index-Bv4iPZiS.js"></script>
3
- <link rel="stylesheet" crossorigin href="/assets/index-DAKKO3a9.css">
2
+ <html lang="zh-CN"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><meta name="theme-color" content="#101419"/><link rel="icon" href="/favicon.svg"/><title>Web Terminal</title> <script type="module" crossorigin src="/assets/index-Cdq-0BxC.js"></script>
3
+ <link rel="stylesheet" crossorigin href="/assets/index-DIMl7N0D.css">
4
4
  </head><body><div id="root"></div></body></html>
@@ -2,7 +2,7 @@ import {
2
2
  serviceName,
3
3
  serviceProtocol,
4
4
  serviceVersion
5
- } from "./chunk-TD3NJESY.js";
5
+ } from "./chunk-2APXDIFJ.js";
6
6
 
7
7
  // src/server/app.ts
8
8
  import express from "express";
@@ -289,10 +289,29 @@ var TerminalScreen = class {
289
289
  cursorVisible = true;
290
290
  mouseEncoding = 0;
291
291
  margins = [1, 30];
292
- constructor(onTitle, onResponse) {
292
+ progress;
293
+ constructor(onTitle, onResponse, onProgress = () => {
294
+ }) {
293
295
  this.terminal.loadAddon(this.serializer);
294
296
  this.terminal.onTitleChange((title) => onTitle(title.replace(/[\x00-\x1f\x7f]/g, "").slice(0, 512)));
295
297
  this.terminal.onData(onResponse);
298
+ const setProgress = (progress) => {
299
+ this.progress = progress;
300
+ onProgress(progress);
301
+ };
302
+ this.terminal.parser.registerOscHandler(9, (data) => {
303
+ if (!data.startsWith("4;")) return false;
304
+ const match = /^4;([0-4])(?:;(\d+))?$/.exec(data);
305
+ if (!match) return true;
306
+ const state = Number(match[1]);
307
+ if (state === 0) setProgress(void 0);
308
+ else {
309
+ const previous = this.progress?.value ?? 0;
310
+ const value = state === 3 ? previous : match[2] !== void 0 ? Math.min(100, Number(match[2])) : state === 1 ? 0 : previous;
311
+ setProgress({ state, value });
312
+ }
313
+ return true;
314
+ });
296
315
  for (const [code, color] of [[10, "d8d8/e3e3/e8e8"], [11, "1010/1818/2121"]]) {
297
316
  this.terminal.parser.registerOscHandler(code, (data) => {
298
317
  if (data !== "?") return false;
@@ -314,6 +333,7 @@ var TerminalScreen = class {
314
333
  this.cursorVisible = true;
315
334
  this.mouseEncoding = 0;
316
335
  this.margins = [1, this.terminal.rows];
336
+ setProgress(void 0);
317
337
  return false;
318
338
  });
319
339
  }
@@ -377,7 +397,7 @@ var Sessions = class {
377
397
  for (const record of records) {
378
398
  if (!/^[a-f0-9-]{36}$/.test(record.id)) continue;
379
399
  const { id, name, cwd, createdAt } = record;
380
- const info = { id, name, cwd, createdAt, running: false };
400
+ const info = { id, name, cwd, createdAt, running: false, outputActive: false };
381
401
  this.entries.set(info.id, this.makeSession(info));
382
402
  }
383
403
  }
@@ -386,12 +406,23 @@ var Sessions = class {
386
406
  files;
387
407
  entries = /* @__PURE__ */ new Map();
388
408
  shuttingDown = false;
409
+ watchers = /* @__PURE__ */ new Set();
410
+ refreshTimer;
411
+ refreshing = false;
389
412
  makeSession(info) {
390
413
  const session = { info, clients: /* @__PURE__ */ new Map(), pendingBytes: 0, screen: new TerminalScreen(
391
414
  (title) => {
392
- info.title = title;
415
+ if (info.title !== title) {
416
+ info.title = title;
417
+ this.publish();
418
+ }
393
419
  },
394
- (data) => session.process?.write(data)
420
+ (data) => session.process?.write(data),
421
+ (progress) => {
422
+ if (info.progress?.state === progress?.state && info.progress?.value === progress?.value) return;
423
+ info.progress = progress;
424
+ this.publish();
425
+ }
395
426
  ) };
396
427
  return session;
397
428
  }
@@ -420,13 +451,59 @@ var Sessions = class {
420
451
  async list() {
421
452
  return Promise.all([...this.entries.keys()].map((id) => this.current(id)));
422
453
  }
454
+ publish(ws) {
455
+ const message = { type: "sessions", sessions: [...this.entries.values()].map((session) => ({ ...session.info })) };
456
+ if (ws) send(ws, message);
457
+ else for (const watcher of this.watchers) send(watcher, message);
458
+ }
459
+ watch(ws) {
460
+ this.watchers.add(ws);
461
+ this.publish(ws);
462
+ ws.once("close", () => {
463
+ this.watchers.delete(ws);
464
+ if (!this.watchers.size) {
465
+ clearInterval(this.refreshTimer);
466
+ this.refreshTimer = void 0;
467
+ }
468
+ });
469
+ if (!this.refreshTimer) this.refreshTimer = setInterval(() => void this.refresh(), 5e3);
470
+ void this.refresh();
471
+ }
472
+ async refresh() {
473
+ if (this.refreshing || this.shuttingDown) return;
474
+ this.refreshing = true;
475
+ try {
476
+ await this.list();
477
+ if (!this.shuttingDown) this.publish();
478
+ } catch (error) {
479
+ console.error("\u4F1A\u8BDD\u72B6\u6001\u66F4\u65B0\u5931\u8D25", error);
480
+ } finally {
481
+ this.refreshing = false;
482
+ }
483
+ }
484
+ stopActivity(session) {
485
+ clearTimeout(session.activityTimer);
486
+ session.activityTimer = void 0;
487
+ session.info.outputActive = false;
488
+ }
489
+ outputActivity(session) {
490
+ clearTimeout(session.activityTimer);
491
+ if (!session.info.outputActive) {
492
+ session.info.outputActive = true;
493
+ this.publish();
494
+ }
495
+ session.activityTimer = setTimeout(() => {
496
+ this.stopActivity(session);
497
+ this.publish();
498
+ }, 800);
499
+ }
423
500
  async create(name, cwd) {
424
501
  if (this.entries.size >= 32) throw new HttpError(409, "\u6700\u591A\u4FDD\u7559 32 \u4E2A\u4F1A\u8BDD\uFF0C\u8BF7\u7ED3\u675F\u4E0D\u9700\u8981\u7684\u4F1A\u8BDD");
425
502
  if (name !== void 0 && (typeof name !== "string" || name.length > 80)) throw new HttpError(400, "\u4F1A\u8BDD\u540D\u79F0\u6700\u591A 80 \u5B57\u7B26");
426
503
  if (cwd !== void 0 && typeof cwd !== "string") throw new HttpError(400, "\u5DE5\u4F5C\u76EE\u5F55\u65E0\u6548");
427
504
  const dir = await this.files.directory(cwd || this.config.defaultCwd);
428
505
  const id = randomUUID();
429
- const info = { id, name: name?.trim() || `\u7EC8\u7AEF ${this.entries.size + 1}`, cwd: dir, createdAt: (/* @__PURE__ */ new Date()).toISOString(), running: true };
506
+ const info = { id, name: name?.trim() || `\u7EC8\u7AEF ${this.entries.size + 1}`, cwd: dir, createdAt: (/* @__PURE__ */ new Date()).toISOString(), running: true, outputActive: false };
430
507
  const session = this.makeSession(info);
431
508
  try {
432
509
  this.entries.set(id, session);
@@ -437,6 +514,7 @@ var Sessions = class {
437
514
  throw error;
438
515
  }
439
516
  this.save();
517
+ this.publish();
440
518
  return info;
441
519
  }
442
520
  spawnTerminal(command, args, cwd, cols, rows) {
@@ -456,6 +534,8 @@ var Sessions = class {
456
534
  const terminalProcess = this.spawnTerminal(this.config.shell, shellArgs, session.info.cwd, 100, 30);
457
535
  session.process = terminalProcess;
458
536
  terminalProcess.onData((data) => {
537
+ if (this.shuttingDown || this.entries.get(session.info.id) !== session) return;
538
+ if (data) this.outputActivity(session);
459
539
  session.pendingBytes += data.length;
460
540
  if (session.pendingBytes > 256 * 1024) terminalProcess.pause();
461
541
  void session.screen.write(data, () => {
@@ -469,7 +549,10 @@ var Sessions = class {
469
549
  if (this.shuttingDown) return;
470
550
  void session.screen.run(() => {
471
551
  session.info.running = false;
552
+ session.info.progress = void 0;
553
+ this.stopActivity(session);
472
554
  this.save();
555
+ this.publish();
473
556
  for (const ws of session.clients.keys()) {
474
557
  send(ws, { type: "exit", exitCode });
475
558
  ws.close(4404, "\u4F1A\u8BDD\u5DF2\u7ED3\u675F");
@@ -549,17 +632,24 @@ var Sessions = class {
549
632
  }
550
633
  async remove(id) {
551
634
  const session = this.get(id);
635
+ this.stopActivity(session);
552
636
  session.process?.kill();
553
637
  for (const ws of session.clients.keys()) ws.close(1e3, "\u4F1A\u8BDD\u5DF2\u7ED3\u675F");
554
638
  this.entries.delete(id);
555
639
  this.save();
640
+ this.publish();
556
641
  await session.screen.dispose();
557
642
  await this.files.removeUploads(id);
558
643
  }
559
644
  async shutdown() {
560
645
  this.shuttingDown = true;
561
646
  this.save();
647
+ clearInterval(this.refreshTimer);
648
+ this.refreshTimer = void 0;
649
+ for (const ws of this.watchers) ws.close(1012, "\u670D\u52A1\u91CD\u542F\u4E2D");
650
+ this.watchers.clear();
562
651
  for (const session of this.entries.values()) {
652
+ this.stopActivity(session);
563
653
  for (const ws of session.clients.keys()) ws.close(1012, "\u670D\u52A1\u91CD\u542F\u4E2D");
564
654
  session.process?.kill();
565
655
  }
@@ -695,6 +785,7 @@ async function createApp(config, options = {}) {
695
785
  });
696
786
  wss.on("connection", (ws) => {
697
787
  let sessionId;
788
+ let watching = false;
698
789
  const timer = setTimeout(() => ws.close(4401, "\u9700\u8981 token"), 5e3);
699
790
  ws.once("close", () => clearTimeout(timer));
700
791
  ws.on("error", () => {
@@ -703,6 +794,7 @@ async function createApp(config, options = {}) {
703
794
  try {
704
795
  if (binary) throw new Error("\u6D88\u606F\u683C\u5F0F\u65E0\u6548");
705
796
  const message = JSON.parse(raw.toString());
797
+ if (watching) throw new Error("\u4F1A\u8BDD\u72B6\u6001\u8BA2\u9605\u53EA\u652F\u6301\u8BFB\u53D6");
706
798
  if (!sessionId) {
707
799
  if (message.type !== "auth" || !validToken(message.token, config.token)) {
708
800
  ws.close(4401, "token \u65E0\u6548");
@@ -713,6 +805,12 @@ async function createApp(config, options = {}) {
713
805
  ws.close(4406, "\u8BF7\u5237\u65B0\u9875\u9762");
714
806
  return;
715
807
  }
808
+ if (message.scope === "sessions") {
809
+ watching = true;
810
+ clearTimeout(timer);
811
+ sessions.watch(ws);
812
+ return;
813
+ }
716
814
  if (typeof message.sessionId !== "string") throw new Error("\u4F1A\u8BDD\u65E0\u6548");
717
815
  const session = sessions.get(message.sessionId);
718
816
  sessionId = session.info.id;
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "@dadigua/web-terminal",
4
- version: "0.1.4",
4
+ version: "0.1.5",
5
5
  type: "module",
6
6
  scripts: {
7
7
  dev: "tsx src/server/index.ts --dev",
@@ -2,7 +2,7 @@ import {
2
2
  serviceName,
3
3
  serviceProtocol,
4
4
  serviceVersion
5
- } from "./chunk-TD3NJESY.js";
5
+ } from "./chunk-2APXDIFJ.js";
6
6
 
7
7
  // src/cli.ts
8
8
  import { fileURLToPath } from "node:url";
@@ -307,7 +307,7 @@ async function main() {
307
307
  return;
308
308
  }
309
309
  if (action === "install-vscode") {
310
- const { installVSCodeExtension } = await import("./vscodeInstaller-WIM5VHDI.js");
310
+ const { installVSCodeExtension } = await import("./vscodeInstaller-AIKL2DRR.js");
311
311
  await installVSCodeExtension({ vsixPath: values.vsix, onInstalled: (result) => console.log(`${result.target} \u5DF2\u5B89\u88C5 ${result.extension}`) });
312
312
  console.log("\u8BF7\u5728\u5DF2\u6253\u5F00\u7684 VS Code \u7A97\u53E3\u8FD0\u884C Developer: Reload Window \u4EE5\u52A0\u8F7D\u63D2\u4EF6\u3002");
313
313
  return;
@@ -333,7 +333,7 @@ async function main() {
333
333
  config.host = new URL(url).hostname === "localhost" ? "127.0.0.1" : new URL(url).hostname.replace(/^\[|\]$/g, "");
334
334
  config.port = Number(new URL(url).port || 80);
335
335
  const instanceId = randomUUID2();
336
- const { createApp } = await import("./app-3OE4ER7S.js");
336
+ const { createApp } = await import("./app-FFT46HD7.js");
337
337
  const runtime = await createApp(config, { managed: true, instanceId, staticDir: fileURLToPath(new URL("../dist/", import.meta.url)) });
338
338
  const stamp = await processStamp(process.pid);
339
339
  if (!stamp) throw new Error("\u65E0\u6CD5\u53D6\u5F97\u8FDB\u7A0B\u542F\u52A8\u6807\u8BC6\uFF0C\u62D2\u7EDD\u542F\u52A8\u4E0D\u53EF\u5B89\u5168\u7BA1\u7406\u7684\u540E\u53F0");
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  serviceVersion
3
- } from "./chunk-TD3NJESY.js";
3
+ } from "./chunk-2APXDIFJ.js";
4
4
 
5
5
  // src/vscodeInstaller.ts
6
6
  import { execFile } from "node:child_process";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dadigua/web-terminal",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "tsx src/server/index.ts --dev",
Binary file