From 6882349bf48ed383c19bfd1a065a3a2611240320 Mon Sep 17 00:00:00 2001 From: Kalina Date: Mon, 2 Nov 2026 18:29:25 +0100 Subject: [PATCH 1/2] feat(shell): Kalina-CI-Prompt und Installer fuer weitere Maschinen (#2) prompt.zsh: zweizeiliger zsh-Prompt aus den CI-Token (Tinte, Knochenweiss, Markenrot nur als Grafik, Text-Rot fuer Fehlercodes, Salbei nur an Git). install.sh: idempotent, sichert jede Datei, erkennt foot/qterminal/xfce4-terminal/xterm und prueft mit zsh -n, foot --check-config und xrdb. --- CHANGELOG.md | 21 +++ shell/README.md | 66 +++++++ shell/install.sh | 447 +++++++++++++++++++++++++++++++++++++++++++++++ shell/prompt.zsh | 176 +++++++++++++++++++ 4 files changed, 710 insertions(+) create mode 100644 shell/README.md create mode 100755 shell/install.sh create mode 100644 shell/prompt.zsh diff --git a/CHANGELOG.md b/CHANGELOG.md index b2c2edb..d2c6035 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,27 @@ Format: Datum — was — warum. Die CI beginnt versioniert am 2026-10-23; davor sie verstreut (Marke in `brand/`, Dokument-CSS im Open-WebUI-Skill) und wurde nicht versioniert. +## 1.3.0 — 2026-11-02 + +- **Die CI reicht bis in die Shell.** `shell/prompt.zsh` rendert einen zweizeiligen Prompt + (`┌─ kalina ~/kalina-ci · main ✚1 ✎2 · 4.2s` / `└─ ❯`) aus denselben Werten wie + `themes/kalina-ci-dark.json`: Tinte `#0B0F14`, Knochenweiß `#F5F5EF`, Markenrot `#C1121F` + nur als Grafik, Text-Rot `#E0454F` (4,70:1), Salbei `#7FA88C` nur an Git. Ausgerollt auf + kalina, ROG, imac und Kalini 1 (Gast-VM); die Pixelprobe zeigt auf jedem Host `#0B0F14`. +- **`shell/install.sh` richtet weitere Maschinen ohne meinen Zugriff ein.** Idempotent, sichert + jede Datei nach `.vor-kalina-ci-`, erkennt foot, qterminal, xfce4-terminal und xterm + und prüft anschließend mit `zsh -n`, `foot --check-config` und `xrdb`-Query. +- **Vier Erkenntnisse, die das Ausrollen gekostet hat:** p10k lässt sich nicht umfärben, nur + ablösen (der dreizeilige Instant-Prompt hinterlässt beim Auskommentieren ein `fi`, danach + startet keine Shell mehr); `${PWD/#$HOME/~}` ersetzt in zsh 5.9 nichts; `COLORTERM` wird per + SSH nicht übertragen, remote bleibt es beim 256-Farben-Ersatz; wer die Login-Shell auf zsh + umstellt, braucht `no_nomatch` in `~/.zshenv`, sonst brechen `ssh host '…'`-Aufrufe an leeren + Globs ab, wo bash weitermachte. +- **Terminal-Paletten sind nicht ratbar, sie sind messbar.** qterminal liest sein Schema nur + aus `XDG_DATA_DIRS` (nicht aus `~/.local/share/qterminal`), xfce4-terminal ignoriert + `terminalrc`, solange `xfconf` `/color-use-theme=true` hält, und foot 1.28 will + `[colors-dark]` mit `cursor= ` statt `[colors]` mit `cursor-text`. + ## 1.2.0 — 2026-10-23 - **Jede Seite wird durchgestempelt, keine eigene Impressumsseite** (Mathias: „Alle diff --git a/shell/README.md b/shell/README.md new file mode 100644 index 0000000..71f77e6 --- /dev/null +++ b/shell/README.md @@ -0,0 +1,66 @@ +# Kalina CI in der Shell + +Prompt und Terminal-Palette in derselben Farbwelt wie das VS-Code-Theme +(`themes/kalina-ci-dark.json`). Der Prompt ist ein eigenstaendiges zsh-Modul, +kein oh-my-zsh und kein powerlevel10k noetig. + +``` +┌─ kalina ~/kalina-ci · main ✚1 ✎2 · 4.2s +└─ ❯ +``` + +| Farbe | Wert | Rolle | +|---|---|---| +| Tinte | `#0B0F14` | Flaeche | +| Knochenweiss | `#F5F5EF` | Text, Pfad | +| Markenrot | `#C1121F` | **nur Grafik** (Pfeil, Cursor) — 3,09:1 auf Tinte | +| Text-Rot | `#E0454F` | Fehlercode, Akzent — 4,70:1 auf Tinte | +| Salbei | `#7FA88C` | **nur** Git „hinzugefuegt" | +| Steel | `#3A4250` | Linien | +| Muted | `#8A94A2` | Hostname | + +## Installation auf einer neuen Maschine + +```sh +git clone http://192.168.188.161:3000/mm/kalina-ci.git +cd kalina-ci/shell +./install.sh --dry-run # zeigen, was passieren wuerde +./install.sh # ausfuehren +``` + +Das Skript ist idempotent, sichert jede Datei nach `.vor-kalina-ci-` +und laesst sich in Teilen fahren: + +| Schalter | Wirkung | +|---|---| +| `--dry-run` | nichts schreiben, nur anzeigen | +| `--shell-only` | nur zsh + Prompt | +| `--terminal-only` | nur Terminal-Palette | +| `--no-chsh` | Login-Shell nicht umstellen | + +Erkannt und eingerichtet werden: **foot** (`~/.config/foot/foot.ini`, +`[colors-dark]`), **qterminal** (`~/.local/share/qterminal-ci/…/KalinaCI.colorscheme` +plus `~/.config/qterminal.org/qterminal.ini` und ein `environment.d`-Eintrag, +weil qtermwidget6 nur `XDG_DATA_DIRS` durchsucht), **xfce4-terminal** +(`~/.config/xfce4/terminal/terminalrc` **und** `xfconf-query`, sonst gewinnt +das GTK-Theme) sowie **xterm** (`~/.Xresources`, aktiv nach `xrdb -merge`). + +## Schalter im Prompt + +| Variable | Wirkung | +|---|---| +| `KALINA_CI_PROMPT=0` | Prompt abschalten (Modul wird nicht geladen) | +| `KALINA_CI_NO_NEWLINE=1` | keine Leerzeile vor dem Prompt | +| `KALINA_CI_TRUECOLOR=0\|1` | Farbmodus erzwingen (sonst Automatik) | + +## Fallen, die beim Ausrollen aufgefallen sind + +- **Truecolor kommt per SSH nicht an.** `COLORTERM` wird nicht uebertragen, remote + greift der 256-Farben-Ersatz (231/145/60/161 statt exakt). Das ist gewollt. +- **Der erste Prompt darf kein `✗1` zeigen.** `precmd` liest `$?` aus dem Ende der + `.zshrc`; das Modul setzt den ersten echten Prompt deshalb auf 0. +- **p10k wird abgeloest, nicht umgef aerbt.** Wer `~/.p10k.zsh` behaelt, muss + `ZSH_THEME=""` setzen und die Instant-Prompt-Zeilen samt `fi` auskommentieren — + sonst startet jede Shell mit `parse error near 'fi'`. +- **Login-Shell-Wechsel:** nicht-interaktive zsh-Aufrufe (`ssh host '…'`) brechen bei + leerem Glob ab, bash nicht. Das Modul setzt deshalb `no_nomatch` in `~/.zshenv`. diff --git a/shell/install.sh b/shell/install.sh new file mode 100755 index 0000000..fb1818c --- /dev/null +++ b/shell/install.sh @@ -0,0 +1,447 @@ +#!/usr/bin/env bash +# Kalina CI — Shell-Prompt und Terminal-Palette installieren. +# +# Einmal auf einer neuen Maschine ausfuehren, danach ist die Shell im Kalina-CI +# (Tinte #0B0F14, Knochenweiss #F5F5EF, Markenrot #C1121F als Grafik-Akzent). +# +# ./install.sh # alles, was erkannt wird +# ./install.sh --dry-run # nur zeigen, was passieren wuerde +# ./install.sh --shell-only # nur zsh + Prompt +# ./install.sh --terminal-only # nur Terminal-Palette +# ./install.sh --no-chsh # Login-Shell nicht anfassen +# +# Grundsaetze: jede Datei wird vorher gesichert (.vor-kalina-ci-), +# jeder Block ist an einem Marker erkennbar und wird nicht doppelt geschrieben, +# jede veraenderte Datei wird anschliessend mit dem passenden Pruefer getestet. + +set -uo pipefail + +MARK_ON="# >>> kalina-ci >>>" +MARK_OFF="# <<< kalina-ci <<<" +TS="$(date +%Y%m%d-%H%M%S)" +CONF_DIR="$HOME/.config/kalina-ci" +PROMPT="$CONF_DIR/prompt.zsh" +SRC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +DRY=0; DO_SHELL=1; DO_TERM=1; DO_CHSH=1 +for arg in "$@"; do + case "$arg" in + --dry-run) DRY=1 ;; + --shell-only) DO_TERM=0 ;; + --terminal-only) DO_SHELL=0 ;; + --no-chsh) DO_CHSH=0 ;; + -h|--help) sed -n '2,18p' "$0"; exit 0 ;; + *) echo "unbekannte Option: $arg" >&2; exit 2 ;; + esac +done + +say() { printf '%s\n' "$*"; } +step() { printf '\n\033[38;2;224;69;79m▸\033[0m %s\n' "$*"; } +ok() { printf ' \033[38;2;127;168;140m✓\033[0m %s\n' "$*"; } +warn() { printf ' \033[38;2;199;164;107m!\033[0m %s\n' "$*"; } +run() { if [ "$DRY" = 1 ]; then printf ' [dry] %s\n' "$*"; else "$@"; fi } + +backup() { + [ -e "$1" ] || return 0 + local dst="$1.vor-kalina-ci-$TS" + run cp -a "$1" "$dst" + ok "Sicherung: $dst" +} + +# ----------------------------------------------------------------- Hilfsmittel +SUDO="" +if [ "$(id -u)" = 0 ]; then SUDO="" +elif command -v sudo >/dev/null && sudo -n true 2>/dev/null; then SUDO="sudo -n" +fi + +install_zsh() { + command -v zsh >/dev/null && { ok "zsh vorhanden: $(zsh --version)"; return 0; } + local pm="" + for c in apt-get dnf pacman zypper apk; do command -v "$c" >/dev/null && pm="$c" && break; done + [ -n "$pm" ] || { warn "kein bekannter Paketmanager — zsh bitte von Hand installieren"; return 1; } + if [ -z "$SUDO" ] && [ "$(id -u)" != 0 ]; then + warn "zsh fehlt und sudo verlangt ein Passwort. Bitte selbst ausfuehren:" + case "$pm" in + apt-get) say " sudo apt-get install -y zsh" ;; + dnf) say " sudo dnf install -y zsh" ;; + pacman) say " sudo pacman -S --needed zsh" ;; + zypper) say " sudo zypper install -y zsh" ;; + apk) say " sudo apk add zsh" ;; + esac + return 1 + fi + case "$pm" in + apt-get) run $SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y zsh ;; + dnf) run $SUDO dnf install -y zsh ;; + pacman) run $SUDO pacman -S --needed --noconfirm zsh ;; + zypper) run $SUDO zypper --non-interactive install zsh ;; + apk) run $SUDO apk add zsh ;; + esac + command -v zsh >/dev/null && ok "zsh installiert: $(zsh --version)" || warn "zsh weiterhin nicht auffindbar" +} + +# Block mit Markern an eine Datei anhaengen (nicht doppelt) +append_block() { + local file="$1" + if [ -f "$file" ] && grep -qF "$MARK_ON" "$file"; then + ok "$(basename "$file"): Kalina-CI-Block ist schon drin" + return 0 + fi + backup "$file" + if [ "$DRY" = 1 ]; then + printf ' [dry] Block an %s anhaengen\n' "$file" + else + { printf '\n%s\n' "$MARK_ON"; cat; printf '%s\n' "$MARK_OFF"; } >> "$file" + fi + ok "$(basename "$file"): Block angehaengt" +} + +# ------------------------------------------------------------------ Shell +do_shell() { + step "Shell (zsh + Kalina-CI-Prompt)" + install_zsh || true + + run mkdir -p "$CONF_DIR" + if [ -f "$PROMPT" ] && [ -f "$SRC_DIR/prompt.zsh" ]; then + backup "$PROMPT" + run cp -f "$SRC_DIR/prompt.zsh" "$PROMPT" + ok "prompt.zsh aus $SRC_DIR uebernommen" + elif [ -f "$SRC_DIR/prompt.zsh" ]; then + run cp -f "$SRC_DIR/prompt.zsh" "$PROMPT" + ok "prompt.zsh installiert" + elif [ -f "$PROMPT" ]; then + ok "prompt.zsh liegt bereits in $CONF_DIR" + else + warn "prompt.zsh weder neben dem Skript noch in $CONF_DIR — Shell-Teil uebersprungen" + return 1 + fi + + local zshrc="$HOME/.zshrc" + if [ ! -f "$zshrc" ]; then + backup "$zshrc" + if [ "$DRY" = 0 ]; then + cat > "$zshrc" <<'RC' +# Grundgeruest (angelegt von install.sh aus mm/kalina-ci) +HISTFILE=~/.zsh_history +HISTSIZE=20000 +SAVEHIST=20000 +setopt append_history share_history hist_ignore_dups hist_ignore_space extended_history +setopt autocd interactive_comments +unsetopt beep +autoload -Uz compinit && compinit -u -d "$HOME/.zcompdump" +zstyle ':completion:*' menu select +bindkey -e +RC + fi + ok "~/.zshrc angelegt" + fi + + printf '\n[[ -r ~/.config/kalina-ci/prompt.zsh ]] && source ~/.config/kalina-ci/prompt.zsh\n' \ + | append_block "$zshrc" + + # Nicht-interaktive Aufrufe (ssh host '...') erwarten bash-Verhalten + local zshenv="$HOME/.zshenv" + if ! grep -qs "kalina-ci" "$zshenv"; then + backup "$zshenv" + if [ "$DRY" = 0 ]; then + { + printf '%s\n' "$MARK_ON" + printf '# Leerer Glob soll nicht abbrechen (bash-Verhalten fuer Automatik/Remote).\n' + printf 'if ! [[ -o interactive ]]; then setopt no_nomatch 2>/dev/null; fi\n' + printf '%s\n' "$MARK_OFF" + } >> "$zshenv" + fi + ok "~/.zshenv: no_nomatch fuer nicht-interaktive Shells" + else + ok "~/.zshenv: schon eingerichtet" + fi + + if [ "$DRY" = 0 ]; then + zsh -n "$zshrc" && ok "zsh -n ~/.zshrc" || warn "~/.zshrc hat einen Syntaxfehler" + zsh -n "$PROMPT" && ok "zsh -n prompt.zsh" || warn "prompt.zsh hat einen Syntaxfehler" + fi + + # Login-Shell + local cur; cur="$(getent passwd "$(id -un)" | cut -d: -f7)" + if [ "$cur" = "$(command -v zsh 2>/dev/null)" ]; then + ok "Login-Shell ist bereits zsh" + elif [ "$DO_CHSH" = 0 ]; then + warn "Login-Shell bleibt $cur (--no-chsh); Start mit 'exec zsh' oder 'chsh -s $(command -v zsh)'" + else + run $SUDO chsh -s "$(command -v zsh)" "$(id -un)" && ok "Login-Shell auf zsh gestellt (greift beim naechsten Login)" + fi +} + +# --------------------------------------------------------------- Terminal +do_terminal() { + step "Terminal-Palette" + + local chosen="" + if command -v foot >/dev/null; then + chosen=foot; foot_setup + elif command -v qterminal >/dev/null; then + chosen=qterminal; qterminal_setup + elif command -v xfce4-terminal >/dev/null; then + chosen=xfce4-terminal; xfce_setup + fi + + # xterm-Ressourcen zusaetzlich, wenn xterm daneben installiert ist. + if command -v xterm >/dev/null && [ "$chosen" != xterm ]; then + chosen="${chosen:-xterm}"; xterm_setup + fi + + [ -n "$chosen" ] || warn "kein bekanntes Terminal gefunden (foot, qterminal, xfce4-terminal, xterm)" +} + +foot_setup() { + local cfg="$HOME/.config/foot" + run mkdir -p "$cfg" + if [ -f "$cfg/foot.ini" ] && grep -qF "Kalina CI" "$cfg/foot.ini"; then + ok "foot: CI-Palette ist schon drin" + else + backup "$cfg/foot.ini" + if [ "$DRY" = 0 ]; then + cat >> "$cfg/foot.ini" <<'FOOT' + +# --- Kalina CI ------------------------------------------------------------- +# Absichtlich NACH einem eventuellen include: in foot gewinnt die spaetere +# Angabe, damit die CI-Palette jedes Theme-Update ueberlebt. +[colors-dark] +background=0b0f14 +foreground=f5f5ef +regular0=1a212a +regular1=e0454f +regular2=7fa88c +regular3=c7a46b +regular4=7e93ad +regular5=be8fa0 +regular6=8fb3b3 +regular7=f5f5ef +bright0=5c6675 +bright1=ff6b75 +bright2=9cc2a8 +bright3=e0c08a +bright4=a3b6cb +bright5=d3a8b8 +bright6=aecbcb +bright7=ffffff +selection-foreground=0b0f14 +selection-background=f5f5ef +cursor=0b0f14 c1121f +# --- Ende Kalina CI -------------------------------------------------------- +FOOT + fi + ok "foot: [colors-dark] angehaengt" + fi + if command -v foot >/dev/null && [ "$DRY" = 0 ]; then + foot --check-config 2>&1 | grep -v "UTF-8 locale" | grep . && warn "foot meldet Konfigurationsfehler (siehe oben)" \ + || ok "foot --check-config: keine Fehler" + fi +} + +qterminal_setup() { + local share="$HOME/.local/share/qterminal-ci/qtermwidget6/color-schemes" + local ini="$HOME/.config/qterminal.org/qterminal.ini" + run mkdir -p "$share" "$(dirname "$ini")" + if [ "$DRY" = 0 ]; then + cat > "$share/KalinaCI.colorscheme" <<'SCHEME' +[Color0] +Color=26,33,42 +[Color0Intense] +Color=92,102,117 +[Color0Faint] +Color=20,26,34 +[Color1] +Color=224,69,79 +[Color1Intense] +Color=255,107,117 +[Color1Faint] +Color=146,50,57 +[Color2] +Color=127,168,140 +[Color2Intense] +Color=156,194,168 +[Color2Faint] +Color=84,110,91 +[Color3] +Color=199,164,107 +[Color3Intense] +Color=224,192,138 +[Color3Faint] +Color=128,107,74 +[Color4] +Color=126,147,173 +[Color4Intense] +Color=163,182,203 +[Color4Faint] +Color=85,97,113 +[Color5] +Color=190,143,160 +[Color5Intense] +Color=211,168,184 +[Color5Faint] +Color=122,95,105 +[Color6] +Color=143,179,179 +[Color6Intense] +Color=174,203,203 +[Color6Faint] +Color=94,116,116 +[Color7] +Color=245,245,239 +[Color7Intense] +Color=255,255,255 +[Color7Faint] +Color=155,155,152 +[Background] +Color=11,15,20 +[BackgroundIntense] +Color=26,33,42 +[BackgroundFaint] +Color=11,15,20 +[Foreground] +Color=245,245,239 +[ForegroundIntense] +Color=255,255,255 +[ForegroundFaint] +Color=138,148,162 +[General] +Description=Kalina CI +Opacity=1 +SCHEME + ok "qterminal: Farbschema geschrieben" + fi + + backup "$ini" + if [ "$DRY" = 0 ]; then + mkdir -p "$(dirname "$ini")"; touch "$ini" + if ! grep -q '^\[General\]' "$ini"; then printf '[General]\n' | cat - "$ini" > "$ini.neu" && mv "$ini.neu" "$ini"; fi + set_ini() { # set_ini + if grep -qE "^$1=" "$ini"; then + sed -i "s|^$1=.*|$1=$2|" "$ini" + else + sed -i "/^\[General\]/a $1=$2" "$ini" + fi + } + set_ini colorScheme KalinaCI + set_ini fontFamily "DejaVu Sans Mono" + set_ini fontSize 11 + set_ini TerminalTransparency 0 + fi + ok "qterminal: colorScheme/font/TerminalTransparency gesetzt" + + # qtermwidget6 durchsucht XDG_DATA_DIRS — eigenen Pfad dort einhaengen + local envd="$HOME/.config/environment.d" + run mkdir -p "$envd" + if [ "$DRY" = 0 ]; then + cat > "$envd/60-kalina-ci-terminal.conf" <<'ENVD' +# Kalina CI: Farbschema fuer QTerminal/QTermWidget (ohne sudo) +XDG_DATA_DIRS=${HOME}/.local/share/qterminal-ci:${XDG_DATA_DIRS:-/usr/local/share:/usr/share} +ENVD + fi + ok "environment.d/60-kalina-ci-terminal.conf (greift nach dem naechsten Login)" +} + +xfce_setup() { + local dir="$HOME/.config/xfce4/terminal" rc + rc="$dir/terminalrc" + run mkdir -p "$dir" + backup "$rc" + if [ "$DRY" = 0 ]; then + cat > "$rc" <<'XFCE' +[Configuration] +FontName=DejaVu Sans Mono 11 +MiscAlwaysShowTabs=FALSE +MiscBell=FALSE +MiscCursorBlinks=FALSE +MiscCursorShape=TERMINAL_CURSOR_SHAPE_BLOCK +MiscShowUnsafePasteDialog=FALSE +ColorForeground=#f5f5ef +ColorBackground=#0b0f14 +ColorCursor=#c1121f +ColorCursorUseDefault=FALSE +ColorPalette=#1a212a;#e0454f;#7fa88c;#c7a46b;#7e93ad;#be8fa0;#8fb3b3;#f5f5ef;#5c6675;#ff6b75;#9cc2a8;#e0c08a;#a3b6cb;#d3a8b8;#aecbcb;#ffffff +ColorUseTheme=false +BoldIsBright=TRUE +BackgroundMode=TERMINAL_BACKGROUND_SOLID +XFCE + fi + ok "xfce4-terminal: terminalrc geschrieben" + + if command -v xfconf-query >/dev/null; then + local have=0 + command -v xfconf-query >/dev/null && xfconf-query -c xfce4-terminal -l >/dev/null 2>&1 && have=1 + if [ "$have" = 1 ]; then + xfset() { # xfset + if xfconf-query -c xfce4-terminal -p "$1" >/dev/null 2>&1; then + run xfconf-query -c xfce4-terminal -p "$1" -t "$2" -s "$3" >/dev/null + else + run xfconf-query -c xfce4-terminal -p "$1" -n -t "$2" -s "$3" >/dev/null + fi + } + xfset /color-background string "#0b0f14" + xfset /color-foreground string "#f5f5ef" + xfset /color-cursor string "#c1121f" + xfset /color-cursor-use-default bool false + xfset /color-use-theme bool false + xfset /font-name string "DejaVu Sans Mono 11" + xfset /color-palette string "#1a212a;#e0454f;#7fa88c;#c7a46b;#7e93ad;#be8fa0;#8fb3b3;#f5f5ef;#5c6675;#ff6b75;#9cc2a8;#e0c08a;#a3b6cb;#d3a8b8;#aecbcb;#ffffff" + ok "xfce4-terminal: laufende Sitzung (xfconf) gesetzt — wichtig, sonst gewinnt das GTK-Theme" + else + warn "xfconf-query ohne Verbindung zur Sitzung (per SSH normal); terminalrc greift beim naechsten Login" + fi + fi +} + +xterm_setup() { + local xr="$HOME/.Xresources" + if [ -f "$xr" ] && grep -qF "Kalina CI" "$xr"; then + ok "~/.Xresources: xterm-Block ist schon drin" + return 0 + fi + backup "$xr" + if [ "$DRY" = 0 ]; then + cat >> "$xr" <<'XRES' + +! --- Kalina CI (xterm) ----------------------------------------------------- +xterm*background: #0B0F14 +xterm*foreground: #F5F5EF +xterm*cursorColor: #C1121F +xterm*pointerColor: #C1121F +xterm*colorBD: #F5F5EF +xterm*colorUL: #C1121F +xterm*faceName: DejaVu Sans Mono +xterm*faceSize: 11 +xterm*color0: #1A212A +xterm*color1: #E0454F +xterm*color2: #7FA88C +xterm*color3: #C7A46B +xterm*color4: #7E93AD +xterm*color5: #BE8FA0 +xterm*color6: #8FB3B3 +xterm*color7: #F5F5EF +xterm*color8: #5C6675 +xterm*color9: #FF6B75 +xterm*color10: #9CC2A8 +xterm*color11: #E0C08A +xterm*color12: #A3B6CB +xterm*color13: #D3A8B8 +xterm*color14: #AECBCB +xterm*color15: #FFFFFF +! --- Ende Kalina CI ------------------------------------------------------- +XRES + fi + ok "~/.Xresources: xterm-Farben ergaenzt (aktiv nach 'xrdb -merge ~/.Xresources')" +} + +# ------------------------------------------------------------------- Ablauf +say "Kalina CI — Installation auf $(hostname), Ziel $HOME" +[ "$DRY" = 1 ] && say "(Probelauf: es wird nichts geschrieben)" + +[ "$DO_SHELL" = 1 ] && do_shell +[ "$DO_TERM" = 1 ] && do_terminal + +step "Fertig" +say " Prompt pruefen: zsh -i (oder neue Terminal-Sitzung)" +say " Abschalten: KALINA_CI_PROMPT=0 zsh -i" +say " Palette pruefen: Terminal neu starten; nach environment.d-Aenderung einmal neu anmelden" diff --git a/shell/prompt.zsh b/shell/prompt.zsh new file mode 100644 index 0000000..7e9f1c3 --- /dev/null +++ b/shell/prompt.zsh @@ -0,0 +1,176 @@ +# Kalina CI – zsh-Prompt +# --------------------------------------------------------------------------- +# Zweizeiliger Prompt in der Farbwelt von "Kalina CI Dark" (VS Code). +# Farbwerte: /home/mm/kalina-ci/tokens.json + Theme-Datei +# /home/mm/vscode/kalina-ci-theme/themes/kalina-ci-dark.json +# (terminal.ansi* = dieselben Rollen wie dort) +# +# ┌─ kalina ~/Projekte/kalina-ci main ✚1 ✎2 ·(venv) · 4.2s +# └─ ❯ +# +# Abschalten: KALINA_CI_PROMPT=0 (vor dem source setzen) +# Truecolor: automatisch bei COLORTERM=truecolor/24bit; erzwingen mit +# KALINA_CI_TRUECOLOR=1, abschalten mit =0 +# Kein Zeilenumbruch vor dem Prompt: KALINA_CI_NO_NEWLINE=1 + +[[ ${KALINA_CI_PROMPT:-1} == 0 ]] && return 0 + +zmodload zsh/datetime 2>/dev/null +autoload -Uz add-zsh-hook 2>/dev/null || true + +typeset -g _KCI_TRUECOLOR=0 +typeset -g _KCI_START=0 _KCI_DUR=0 _KCI_CODE=0 _KCI_FIRST=1 +typeset -g _KCI_GIT='' + +case ${COLORTERM:-} in + truecolor|24bit) _KCI_TRUECOLOR=1 ;; +esac +[[ ${TERM:-} == *-direct ]] && _KCI_TRUECOLOR=1 +[[ -n ${KALINA_CI_TRUECOLOR:-} ]] && _KCI_TRUECOLOR=${KALINA_CI_TRUECOLOR} + +# Hex -> Vordergrund-Sequenz, in %{ %} gewickelt (zsh rechnet sie sonst als Breite) +_kci_fg() { + local s=${1#\#} + local -i r=$(( 16#${s:0:2} )) g=$(( 16#${s:2:2} )) b=$(( 16#${s:4:2} )) + if (( _KCI_TRUECOLOR )); then + print -rn -- $'%{\e[38;2;'"${r};${g};${b}"$'m%}' + else + local -i ri=$(( (r * 5 + 127) / 255 )) gi=$(( (g * 5 + 127) / 255 )) bi=$(( (b * 5 + 127) / 255 )) + print -rn -- $'%{\e[38;5;'"$(( 16 + 36 * ri + 6 * gi + bi ))"$'m%}' + fi +} + +# --- Palette (Rollen wie im Theme) ----------------------------------------- +typeset -g _KCI_BONE=$(_kci_fg '#F5F5EF') # Text +typeset -g _KCI_ROT=$(_kci_fg '#C1121F') # Akzent/Grafik: Pfeil, i-Punkt +typeset -g _KCI_ROT_TXT=$(_kci_fg '#E0454F') # Text-Akzent (4,7:1 auf Tinte) +typeset -g _KCI_STEEL=$(_kci_fg '#3A4250') # Linien +typeset -g _KCI_STEEL_L=$(_kci_fg '#5C6675') # Sekundär-Meta +typeset -g _KCI_MUTED=$(_kci_fg '#8A94A2') # Host, Kommentar +typeset -g _KCI_BLUE=$(_kci_fg '#A3B6CB') # Branch +typeset -g _KCI_GREEN=$(_kci_fg '#7FA88C') # nur Git "hinzugefügt" +typeset -g _KCI_YELLOW=$(_kci_fg '#C7A46B') # nur Git "geändert" / venv +typeset -g _KCI_BRIGHTROT=$(_kci_fg '#FF6B75') # root +typeset -g _KCI_RESET=$'%{\e[0m%}' +typeset -g _KCI_BOLD=$'%{\e[1m%}' + +# --- Git-Zustand einsammeln (ein Aufruf, keine Locks) ---------------------- +_kci_git_info() { + reply=() + local out + out=$(command git --no-optional-locks -C "${PWD}" status --porcelain=v1 -b 2>/dev/null) || return 1 + [[ -z $out ]] && return 1 + local line=${out%%$'\n'*} + local br=${line#\#\# } + br=${br%%...*} + br=${br%% *} + local -i ahead=0 behind=0 + [[ $line == *'[ahead '* ]] && ahead=${${line#*\[ahead }%%[,\]]*} + [[ $line == *'behind '* ]] && behind=${${line#*behind }%%[,\]]*} + local -i staged=0 mod=0 untracked=0 + local l + for l in ${(f)out}; do + [[ $l == \#\#* ]] && continue + case $l in + '??'*) (( untracked++ )) ;; + [MTARCD]*) (( staged++ )); [[ ${l:1:1} != ' ' ]] && (( mod++ )) ;; + ' '*) (( mod++ )) ;; + esac + done + (( ${#br} > 26 )) && br="${br:0:24}…" + reply=("$br" $staged $mod $untracked $ahead $behind) +} + +_kci_preexec() { _KCI_START=$EPOCHREALTIME } + +_kci_precmd() { + _KCI_CODE=$? + # allererster Prompt: $? stammt aus .zshrc, nicht aus einer Nutzereingabe + if (( _KCI_FIRST )); then _KCI_CODE=0; _KCI_FIRST=0; fi + if (( _KCI_START > 0 )); then + local -F 3 d=$(( EPOCHREALTIME - _KCI_START )) + _KCI_DUR=${d} + _KCI_START=0 + else + _KCI_DUR=0 + fi + [[ ${_KCI_DUR%.*} -lt 2 ]] && _KCI_DUR=0 + + local host=${(%):-%m} + local -i root=0 + (( EUID == 0 )) && root=1 + + # Pfad: ~ für $HOME, tiefe Pfade auf die letzten drei Ebenen kürzen + local p + if [[ $PWD == $HOME ]]; then + p='~' + elif [[ $PWD == $HOME/* ]]; then + p="~${PWD#$HOME}" + else + p=$PWD + fi + if [[ $p != '~' && $p != '/' ]]; then + local -a parts=(${(s:/:)p}) + (( ${#parts} > 4 )) && p="…/${(j:/:)parts[-3,-1]}" + fi + + # Git + local gitseg='' + if _kci_git_info; then + local br=$reply[1] + gitseg=" ${_KCI_STEEL}·${_KCI_RESET} ${_KCI_BLUE}${br}${_KCI_RESET}" + (( reply[2] )) && gitseg+=" ${_KCI_GREEN}✚${reply[2]}${_KCI_RESET}" + (( reply[3] )) && gitseg+=" ${_KCI_YELLOW}✎${reply[3]}${_KCI_RESET}" + (( reply[4] )) && gitseg+=" ${_KCI_STEEL_L}?${reply[4]}${_KCI_RESET}" + (( reply[5] )) && gitseg+=" ${_KCI_GREEN}↑${reply[5]}${_KCI_RESET}" + (( reply[6] )) && gitseg+=" ${_KCI_YELLOW}↓${reply[6]}${_KCI_RESET}" + fi + + # Umgebung + local envseg='' + [[ -n ${VIRTUAL_ENV:-} ]] && envseg+=" ${_KCI_STEEL}·${_KCI_RESET} ${_KCI_YELLOW}${VIRTUAL_ENV:t}${_KCI_RESET}" + [[ -n ${CONDA_DEFAULT_ENV:-} && -z ${VIRTUAL_ENV:-} ]] && envseg+=" ${_KCI_STEEL}·${_KCI_RESET} ${_KCI_YELLOW}${CONDA_DEFAULT_ENV}${_KCI_RESET}" + [[ -n ${KALINA_SSH_HOST:-} ]] && envseg+=" ${_KCI_STEEL}·${_KCI_RESET} ${_KCI_MUTED}ssh:${KALINA_SSH_HOST}${_KCI_RESET}" + + local durseg='' + (( _KCI_DUR )) && durseg=" ${_KCI_STEEL}·${_KCI_RESET} ${_KCI_STEEL_L}$(printf '%.1fs' ${_KCI_DUR})${_KCI_RESET}" + + local prefix='' + [[ ${KALINA_CI_NO_NEWLINE:-0} == 1 ]] || prefix=$'\n' + + local hostsym=${_KCI_MUTED} + local marksym='❯' + local marksym_c=${_KCI_ROT} + if (( root )); then + hostsym=${_KCI_BRIGHTROT} + marksym='#' + marksym_c=${_KCI_BRIGHTROT} + fi + + local codeseg='' + (( _KCI_CODE )) && codeseg="${_KCI_ROT_TXT}✗${_KCI_CODE}${_KCI_RESET} " + + PROMPT="${prefix}${_KCI_STEEL}┌─${_KCI_RESET} ${hostsym}${host}${_KCI_RESET} ${_KCI_BONE}${p}${_KCI_RESET}${gitseg}${envseg}${durseg}"$'\n' + PROMPT+="${_KCI_STEEL}└─${_KCI_RESET} ${codeseg}${marksym_c}${marksym}${_KCI_RESET} " + + RPROMPT='' + local -i j=${#jobstates} + (( j )) && RPROMPT="${_KCI_STEEL_L}⚙${j}${_KCI_RESET}" +} + +if (( ${+functions[add-zsh-hook]} )); then + add-zsh-hook precmd _kci_precmd + add-zsh-hook preexec _kci_preexec +else + precmd_functions+=(_kci_precmd) + preexec_functions+=(_kci_preexec) +fi + +# Initialer Prompt sofort beim Start (precmd feuert erst vor dem ersten Prompt) +if [[ -o interactive ]]; then + true + _kci_precmd + # doch noch kein Nutzerbefehl gelaufen: erster echter Prompt zeigt keinen Fehlercode + _KCI_FIRST=1 + _KCI_CODE=0 +fi -- 2.43.0 From 9e594e2f768d95f94cb151c02b1f71c2a1146784 Mon Sep 17 00:00:00 2001 From: Kalina Date: Mon, 2 Nov 2026 18:34:15 +0100 Subject: [PATCH 2/2] docs: Startseite auf 1.3.0 nachgezogen (Shell, Paletten, Rohadresse) README beschreibt jetzt shell/ und den Ein-Zeilen-Aufruf ohne Token; Farbregel (Rot nur als Grafik, #E0454F fuer Text) steht dort, wo sie gelesen wird. SKILL.md auf 1.3.0 mit Abschnitt Shell/Terminal. CHANGELOG ohne Maschinen- und Hostnamen (Inhaltsregel). install.sh holt prompt.zsh bei Pipe-Aufruf ueber KALINA_CI_RAW. docs/aenderungen.md: Shell-Rollout per Skript nachziehen. --- CHANGELOG.md | 8 +++++--- README.md | 34 +++++++++++++++++++++++++++++++--- SKILL.md | 22 ++++++++++++++++++++-- docs/aenderungen.md | 2 ++ shell/README.md | 4 +++- shell/install.sh | 22 +++++++++++++++------- 6 files changed, 76 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2c6035..22e053f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,11 +9,13 @@ versioniert. - **Die CI reicht bis in die Shell.** `shell/prompt.zsh` rendert einen zweizeiligen Prompt (`┌─ kalina ~/kalina-ci · main ✚1 ✎2 · 4.2s` / `└─ ❯`) aus denselben Werten wie `themes/kalina-ci-dark.json`: Tinte `#0B0F14`, Knochenweiß `#F5F5EF`, Markenrot `#C1121F` - nur als Grafik, Text-Rot `#E0454F` (4,70:1), Salbei `#7FA88C` nur an Git. Ausgerollt auf - kalina, ROG, imac und Kalini 1 (Gast-VM); die Pixelprobe zeigt auf jedem Host `#0B0F14`. + nur als Grafik, Text-Rot `#E0454F` (4,70:1), Salbei `#7FA88C` nur an Git. Ausgerollt auf vier + Maschinen (Arbeitsplatz, Laptop, iMac, Gast-VM); die Pixelprobe zeigt auf jeder `#0B0F14`. - **`shell/install.sh` richtet weitere Maschinen ohne meinen Zugriff ein.** Idempotent, sichert jede Datei nach `.vor-kalina-ci-`, erkennt foot, qterminal, xfce4-terminal und xterm - und prüft anschließend mit `zsh -n`, `foot --check-config` und `xrdb`-Query. + und prüft anschließend mit `zsh -n`, `foot --check-config` und `xrdb`-Query. Aufruf per + `curl … | bash` funktioniert: fehlt `prompt.zsh` neben dem Skript, holt es das Modul über die + Raw-Adresse des Repos (`KALINA_CI_RAW` überschreibt sie). - **Vier Erkenntnisse, die das Ausrollen gekostet hat:** p10k lässt sich nicht umfärben, nur ablösen (der dreizeilige Instant-Prompt hinterlässt beim Auskommentieren ein `fi`, danach startet keine Shell mehr); `${PWD/#$HOME/~}` ersetzt in zsh 5.9 nichts; `COLORTERM` wird per diff --git a/README.md b/README.md index ccf8698..ef3bf81 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,18 @@ # KALINA CI Corporate Identity der KALINA als versioniertes Artefakt: eine Satzvorlage (CSS), -drei Dokumentvorlagen, die Marke als SVG, ein Stempel-Skript für fremde PDFs und eine -CLI, die alle drei Wege bedient. **Ein Dokument, das nach KALINA aussehen soll, nimmt -diese Dateien — keine nachgebauten Farben, kein selbst gezeichnetes Logo.** +drei Dokumentvorlagen, die Marke als SVG, ein Stempel-Skript für fremde PDFs, eine CLI, +die alle drei Wege bedient — und seit 1.3.0 dieselbe Farbwelt für Shell und Terminal. +**Ein Dokument, das nach KALINA aussehen soll, nimmt diese Dateien — keine nachgebauten +Farben, kein selbst gezeichnetes Logo.** ``` css/kalina-ci.css Satzvorlage: @page A4, Kopfleiste, Tabellen, Plakette, Fußlinie templates/ report.html · page.html · bild-mit-prompt.html assets/ kalina-mark.svg · kalina-wordmark.svg · kalina-logo-combined.svg · favicon/ scripts/stamp_existing_pdf.py fremdes PDF mit Deckblatt/Marke/Fußzeile versehen +shell/install.sh Shell-Prompt und Terminal-Palette auf einer Maschine einrichten +shell/prompt.zsh zsh-Prompt als eigenständiges Modul (kein oh-my-zsh, kein p10k) tools/kalina-pdf CLI: build · stamp · check · tokens tokens.json Farben, Schriften, Geometrie, Zonen (maschinenlesbar) SKILL.md Einstiegspunkt für Agenten (Frontmatter + Regeln + Fallen) @@ -35,6 +38,31 @@ Voraussetzungen: `weasyprint` (Layout), `pymupdf` (Messung/Raster), Ink `#0B0F14` · Bone `#F5F5EF` · Kalina-Rot `#C1121F` · Steel `#3A4250` · Muted `#8A94A2` +Kalina-Rot hat auf Ink nur 3,09:1 Kontrast und ist deshalb **Grafik**, nicht Text. Für Text auf +Ink gilt `#E0454F` (4,70:1) — dieselbe Entscheidung wie im VS-Code-Theme und im Prompt. + +## Shell und Terminal + +Die CI endet nicht am Papier. `shell/` bringt denselben Satz in die Shell: zweizeiliger +Prompt, Terminal-Palette, ein Skript für beides. + +``` +┌─ kalina ~/kalina-ci · main ✚1 ✎2 · 4.2s +└─ ❯ +``` + +```bash +curl -fsSLo install.sh https://gitea.m-m.bio/mm/kalina-ci/raw/branch/main/shell/install.sh +bash install.sh --dry-run # zeigt, was passieren würde +bash install.sh # führt es aus +``` + +Kein Token nötig — das Repo ist öffentlich lesbar. Das Skript ist idempotent, sichert jede +Datei nach `.vor-kalina-ci-` und erkennt **foot**, **qterminal**, **xfce4-terminal** +und **xterm**; zsh installiert es über den vorhandenen Paketmanager. Schalter: +`--shell-only`, `--terminal-only`, `--no-chsh`. Details und die Fallen beim Ausrollen stehen in +[`shell/README.md`](shell/README.md). + ## Wie Agenten das nutzen Zwei Wege, gleicher Inhalt: diff --git a/SKILL.md b/SKILL.md index 18fc012..fe91620 100644 --- a/SKILL.md +++ b/SKILL.md @@ -2,8 +2,8 @@ name: kalina-ci description: Use when a PDF, page or slide must carry the KALINA corporate identity. One CSS, one CLI, one source. metadata: - version: "1.2.0" - stand: "2026-10-23" + version: "1.3.0" + stand: "2026-11-02" --- # KALINA CI — Corporate Identity für Dokumente und Seiten @@ -151,6 +151,24 @@ Bildprüfung läuft **lokal auf dem ROG**, nie in der Cloud — gleiches Ergebni Ink `#0B0F14` · Bone `#F5F5EF` · Kalina-Rot `#C1121F` · Steel `#3A4250` · Muted `#8A94A2` +Kalina-Rot trägt auf Ink nur 3,09:1 und ist **Grafik** (Marke, Cursor, Regel), nie Text. +Text auf Ink ist `#E0454F` (4,70:1). Dieselbe Regel gilt im CSS, im VS-Code-Theme und im +Shell-Prompt — wer sie bricht, bricht die Lesbarkeit, nicht den Geschmack. + +## Shell und Terminal (seit 1.3.0) + +Wer eine Maschine in die CI holen soll: nicht von Hand nachbauen, sondern + +```bash +curl -fsSLo install.sh https://gitea.m-m.bio/mm/kalina-ci/raw/branch/main/shell/install.sh +bash install.sh --dry-run && bash install.sh +``` + +Das Skript ist idempotent, sichert jede Datei und erkennt foot, qterminal, xfce4-terminal +sowie xterm. Die Paletten sind gemessen, nicht geraten — die drei Fallen (qtermwidget6 +kennt kein Benutzerverzeichnis, xfconf überstimmt `terminalrc`, foot will `[colors-dark]`) +stehen in `shell/README.md`. + ## Wenn ein anderer Agent das Design macht Werkzeuge und Agenten, die eine Seite bauen (Bildgeneratoren, externe Design-Dienste), diff --git a/docs/aenderungen.md b/docs/aenderungen.md index 0037d77..623da88 100644 --- a/docs/aenderungen.md +++ b/docs/aenderungen.md @@ -24,6 +24,8 @@ Die CI ist eine Vorlage mit vielen Nutzern (Menschen, Hermes, Paperclip-Agenten) `ref` und `trackingRef`, ein Update ist damit nachvollziehbar statt „irgendwann". - **Bereits ausgelieferte PDFs** werden nicht rückwirkend geändert. Ein Neubau braucht die Quelle (HTML) oder ein `kalina-pdf stamp` auf das alte PDF. +- **Maschinen mit Shell-Prompt:** `shell/install.sh` erneut ausführen (idempotent, sichert + jede Datei) — nicht die Dateien einzeln nachziehen, sonst laufen die Fassungen auseinander. ## Was NICHT über die CI läuft diff --git a/shell/README.md b/shell/README.md index 71f77e6..ece0c1b 100644 --- a/shell/README.md +++ b/shell/README.md @@ -22,7 +22,9 @@ kein oh-my-zsh und kein powerlevel10k noetig. ## Installation auf einer neuen Maschine ```sh -git clone http://192.168.188.161:3000/mm/kalina-ci.git +# oder direkt, ohne Klon (Repo ist oeffentlich lesbar): +# curl -fsSLo install.sh https://gitea.m-m.bio/mm/kalina-ci/raw/branch/main/shell/install.sh +git clone https://gitea.m-m.bio/mm/kalina-ci.git cd kalina-ci/shell ./install.sh --dry-run # zeigen, was passieren wuerde ./install.sh # ausfuehren diff --git a/shell/install.sh b/shell/install.sh index fb1818c..eb5fe48 100755 --- a/shell/install.sh +++ b/shell/install.sh @@ -22,6 +22,8 @@ TS="$(date +%Y%m%d-%H%M%S)" CONF_DIR="$HOME/.config/kalina-ci" PROMPT="$CONF_DIR/prompt.zsh" SRC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# Wo das Prompt-Modul herkommt, wenn es nicht neben dem Skript liegt +RAW="${KALINA_CI_RAW:-https://gitea.m-m.bio/mm/kalina-ci/raw/branch/main/shell}" DRY=0; DO_SHELL=1; DO_TERM=1; DO_CHSH=1 for arg in "$@"; do @@ -102,18 +104,24 @@ do_shell() { install_zsh || true run mkdir -p "$CONF_DIR" - if [ -f "$PROMPT" ] && [ -f "$SRC_DIR/prompt.zsh" ]; then - backup "$PROMPT" + if [ -f "$SRC_DIR/prompt.zsh" ]; then + [ -f "$PROMPT" ] && backup "$PROMPT" run cp -f "$SRC_DIR/prompt.zsh" "$PROMPT" ok "prompt.zsh aus $SRC_DIR uebernommen" - elif [ -f "$SRC_DIR/prompt.zsh" ]; then - run cp -f "$SRC_DIR/prompt.zsh" "$PROMPT" - ok "prompt.zsh installiert" elif [ -f "$PROMPT" ]; then ok "prompt.zsh liegt bereits in $CONF_DIR" else - warn "prompt.zsh weder neben dem Skript noch in $CONF_DIR — Shell-Teil uebersprungen" - return 1 + # Aufruf per Pipe oder aus /tmp: Modul aus dem Repo holen (Repo ist oeffentlich) + if [ "$DRY" = 1 ]; then + printf ' [dry] %s/prompt.zsh nach %s laden\n' "$RAW" "$PROMPT" + elif command -v curl >/dev/null && curl -fsSL "$RAW/prompt.zsh" -o "$PROMPT.tmp"; then + mv "$PROMPT.tmp" "$PROMPT"; ok "prompt.zsh von $RAW geholt" + elif command -v wget >/dev/null && wget -qO "$PROMPT.tmp" "$RAW/prompt.zsh"; then + mv "$PROMPT.tmp" "$PROMPT"; ok "prompt.zsh von $RAW geholt" + else + warn "prompt.zsh nicht erreichbar ($RAW) — Shell-Teil uebersprungen" + return 1 + fi fi local zshrc="$HOME/.zshrc" -- 2.43.0