Files
ubuntu-bare-metal/coding-agent/SERVER-UI-CLI.md
T
tomasz-syn-grzegorza 73e4fc005e Add stack Update, ComfyUI model manager, and slim ComfyUI stack.
Server UI gains Update on stack cards, ComfyUI Models tab with workflow
scan and downloads, and centralized comfyui_config. Model catalog and
download scripts move from stacks/comfyui to server-ui so ComfyUI stays a
minimal Docker wrapper for easier image updates.
2026-07-05 18:45:17 +00:00

4.7 KiB

Server UI — CLI (terminal PTY)

Data: 2026-07-05
Status: wdrożone (bugfix FitAddon: 2026-07-05; pamięć sesji: 2026-07-05)

Zakładka CLI w panelu Server UI (:8091) — interaktywny shell bash w przeglądarce (PTY + xterm.js).

UI

  • Zakładka CLI (pierwsza, przed Pliki)
  • Hash URL: http://<host>:8091/#cli
  • Wymaga API Key w toolbarze (WebSocket nie obsługuje nagłówka X-API-Key)

Architektura

sequenceDiagram
    participant Browser
    participant xterm as xterm_js
    participant WS as WS_api_cli_ws
    participant PTY as cli_pty_py
    participant Shell as bash

    Browser->>xterm: klawiatura
    xterm->>WS: dane terminala
    WS->>PTY: zapis master_fd
    PTY->>Shell: stdin
    Shell->>PTY: stdout/stderr
    PTY->>WS: odczyt master_fd
    WS->>xterm: output

WebSocket

Parametr Wartość
Ścieżka /api/cli/ws
Auth ?api_key=<API_KEY> (query string)
Reattach ?session_id=<uuid> (opcjonalnie, z sessionStorage)
Protokół I/O surowe bajty terminala (text/binary frames)
Resize JSON: {"type":"resize","cols":120,"rows":40}
Zamknij sesję JSON: {"type":"close"} (klient → serwer)

Handshake sesji (serwer → klient)

Payload Znaczenie
{"type":"session","id":"<uuid>"} Nowa sesja — ID zapisane w sessionStorage (server-ui-cli-session-id)
{"type":"replay","complete":true} Koniec replay bufora po reattach

Przykład (wscat)

API_KEY=$(sudo grep ^API_KEY= /opt/control-plane/.env | cut -d= -f2)

# wymaga: npm i -g wscat
wscat -c "ws://127.0.0.1:8091/api/cli/ws?api_key=${API_KEY}"

Bez klucza na bind LAN → połączenie zamknięte z kodem 1008.

Konfiguracja

W /opt/control-plane/.env (opcjonalnie):

Zmienna Domyślnie Opis
CLI_ENABLED 1 0 = WebSocket odrzucany
CLI_SHELL /bin/bash Shell PTY (np. /bin/bash -l)
CLI_DEFAULT_CWD $HOME usługi Katalog startowy
CLI_MAX_SESSIONS 5 Limit równoległych sesji PTY (bash)
CLI_SESSION_TTL 300 Sekundy utrzymania odłączonej sesji przed kill

Pamięć sesji

  • Przełączanie zakładek — WebSocket i bash pozostają aktywne (bez disconnectCli)
  • F5 / reloadsession_id z sessionStorage → reattach do tego samego bash (bufor ~256 KB replay)
  • Połącz ponownie — wysyła {"type":"close"}, czyści sessionStorage, nowy bash
  • Zamknięcie karty — serwer utrzymuje PTY przez CLI_SESSION_TTL, potem zwalnia slot
sequenceDiagram
    participant Browser
    participant SS as sessionStorage
    participant WS as WebSocket
    participant Mgr as CliSessionManager
    participant Bash as bash

    Browser->>WS: connect api_key
    WS->>Mgr: create_session
    Mgr->>Bash: spawn PTY
    Mgr-->>Browser: session id
    Browser->>SS: zapisz session_id
    Note over Browser,Bash: przełączenie zakładki — WS żyje
    Browser->>Browser: F5 reload
    Browser->>SS: odczyt session_id
    Browser->>WS: connect session_id
    WS->>Mgr: attach_session
    Mgr-->>Browser: replay + live output

Uprawnienia POSIX

Server UI działa jako tomasz-syn-grzegorza (server-ui.service):

  • docker ps, edycja repo, /data/apps/ — OK
  • sudo — interaktywnie (hasło użytkownika w terminalu)
  • root-only pliki — odmowa jak w SSH

Kod

Plik Rola
stacks/server-ui/cli_pty.py CliSessionManager — PTY, detach/attach, bufor outputu
stacks/server-ui/app.py WebSocket /api/cli/ws, mount /static
stacks/server-ui/static/index.html Zakładka CLI
stacks/server-ui/static/vendor/xterm/ xterm.js + FitAddon (vendored; UMD: new FitAddon.FitAddon())

Bezpieczeństwo

  • Pełny shell przez LAN = wysokie ryzyko — wymagany API_KEY przy SERVER_UI_HOST=0.0.0.0
  • CLI_ENABLED=0 jako kill switch
  • CLI_MAX_SESSIONS ogranicza liczbę równoległych bashów (PTY, nie połączeń WS)
  • Brak whitelisty komend (właściciel serwera)
  • Jawne zamknięcie: przycisk Połącz ponownie lub {"type":"close"}
  • Odłączenie WS (reload) → detach + TTL; reattach w tej samej karcie przeglądarki

Deploy

sudo rsync -a --exclude '.venv' --exclude '__pycache__' \
  stacks/server-ui/ /opt/server-ui/
sudo systemctl restart server-ui

Tutorial użytkownika: manual-tutorial/10-server-ui-cli.md

Znane problemy / bugfix

Pusty terminal przy działającym API Key: SERVER-UI-CLI-BUGFIX.md