From 21c588f17af127f3e828df56b60dd2ccd0e07844 Mon Sep 17 00:00:00 2001 From: jbergner Date: Mon, 31 Aug 2026 18:32:28 +0200 Subject: [PATCH] v0.8.1 --- DEVELOPMENT_STATUS.md | 10 +- GIT_DISTRIBUTION.md | 6 +- INSTALLATION.md | 4 +- Panel.qml | 4 +- README.md | 13 +- backend/bin/omarchy-citizen-backend | Bin 5984408 -> 5984408 bytes backend/cmd/omarchy-citizen-backend/main.go | 2 +- backend/cmd/omarchy-citizen-backend/stack.go | 2 +- citizenctl | 1071 ++++++------------ install.sh | 4 +- manifest.json | 2 +- tests/smoke-citizenctl.sh | 132 +++ tests/verify.sh | 21 + 13 files changed, 523 insertions(+), 748 deletions(-) create mode 100644 tests/smoke-citizenctl.sh create mode 100644 tests/verify.sh diff --git a/DEVELOPMENT_STATUS.md b/DEVELOPMENT_STATUS.md index f1ceca2..295b996 100644 --- a/DEVELOPMENT_STATUS.md +++ b/DEVELOPMENT_STATUS.md @@ -1,4 +1,4 @@ -# Development status — 0.8.0 +# Development status — 0.8.1 This archive is a **development preview**, not a claim that Star Citizen has been end-to-end validated on real gaming hardware yet. @@ -6,8 +6,10 @@ been end-to-end validated on real gaming hardware yet. ## Verified in this build - Shell scripts pass `bash -n`. +- `citizenctl` has a fake-backend regression test covering status, full setup, launch, repair and updater routing. +- GitHub Actions CI runs shell checks, Go tests/vet/build and the adapter smoke test. - Go unit tests pass. -- Go backend builds as version `0.8.0`. +- Go backend builds as version `0.8.1`. - Git-plugin updater integration test passes. - Backend contains the owned `game-status`, `game-install`, `game-launch`, and `game-repair` paths. @@ -20,10 +22,10 @@ been end-to-end validated on real gaming hardware yet. ## Still needs real-hardware validation The following must be tested on an Omarchy machine with a real Vulkan-capable -AMD/NVIDIA/Intel GPU before calling 0.8.0 a production release: +AMD/NVIDIA/Intel GPU before calling 0.8.1 a production release: - fresh Wine prefix creation with the selected runner -- current Winetricks verbs (`arial`, `tahoma`, `dxvk`, `powershell`, `win11`) +- current Winetricks verbs (`arial`, `tahoma`, `powershell`, `win11`) plus separately managed DXVK - current RSI Launcher unattended installation - first RSI login and game download - actual Star Citizen launch and EAC behavior diff --git a/GIT_DISTRIBUTION.md b/GIT_DISTRIBUTION.md index f254f5c..858a241 100644 --- a/GIT_DISTRIBUTION.md +++ b/GIT_DISTRIBUTION.md @@ -38,12 +38,12 @@ Update ruft das Backend Omarchys eigenen nicht-interaktiven Plugin-Updater auf. Vor jedem Commit/Release: ```bash -cd backend -./build.sh -cd .. +./tests/verify.sh omarchy plugin validate . ``` +Die GitHub-Actions-Datei `.github/workflows/ci.yml` führt dieselben Kernprüfungen automatisch bei Push und Pull Request aus. + Dann Versionsnummern in `manifest.json`, `citizenctl`, Go-Backend und Dokumentation synchron halten, committen und pushen. diff --git a/INSTALLATION.md b/INSTALLATION.md index 1fc6a5e..eb0826c 100644 --- a/INSTALLATION.md +++ b/INSTALLATION.md @@ -1,4 +1,4 @@ -# Omarchy Citizen 0.8.0 – Rundum-Sorglos +# Omarchy Citizen 0.8.1 – Rundum-Sorglos ## Installation @@ -85,7 +85,7 @@ Das Paket enthält zusätzlich: - Maintenance-Ergebnis - Updater-Log -## Wine-Kompatibilitätsfallback (0.8.0) +## Wine-Kompatibilitätsfallback (0.8.1) Autopilot verwendet nicht blind die höchste Versionsnummer. diff --git a/Panel.qml b/Panel.qml index 552594d..968ef41 100644 --- a/Panel.qml +++ b/Panel.qml @@ -12,7 +12,7 @@ Panel { property var anchorItem: null property var hostWidget: null - property string pluginVersion: "0.8.0" + property string pluginVersion: "0.8.1" property string health: "checking" property string depsState: "checking" property string depsMissing: "" @@ -106,7 +106,7 @@ Panel { values[lines[i].slice(0, p)] = lines[i].slice(p + 1) } - pluginVersion = values.plugin_version || "0.8.0" + pluginVersion = values.plugin_version || "0.8.1" health = values.health || "setup" depsState = values.deps || "missing" depsMissing = values.deps_missing || "" diff --git a/README.md b/README.md index c4eaf3c..83730f2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Omarchy Citizen 0.8.0 — Development Preview +# Omarchy Citizen 0.8.1 — Development Preview Omarchy Citizen is moving from a frontend around the LUG installer to an **owned, self-maintaining Star Citizen stack for Omarchy**. @@ -49,3 +49,14 @@ See `DEVELOPMENT_STATUS.md`. ## License MIT. + + +## 0.8.1 adapter hotfix + +The 0.8.0 preview accidentally mixed legacy shell actions with the new Go-owned +stack. `citizenctl` has been rewritten as a thin adapter. There is now one +authoritative implementation for install/status/launch/repair: the Go backend. + +A regression test exercises the adapter with a fake backend, including the exact +full-setup path that previously failed with `backend_game_status: command not +found` / `notify: command not found`. diff --git a/backend/bin/omarchy-citizen-backend b/backend/bin/omarchy-citizen-backend index 53f13fb14e9e12dfeea89318c71d0c462f8421db..13b01091832cb46c0afea57deb84a7d45001f837 100644 GIT binary patch delta 6343 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 delta 6312 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 TYQB403NRN)wYay<%g_IR1^C(c diff --git a/backend/cmd/omarchy-citizen-backend/main.go b/backend/cmd/omarchy-citizen-backend/main.go index 8ea978c..a24f73a 100644 --- a/backend/cmd/omarchy-citizen-backend/main.go +++ b/backend/cmd/omarchy-citizen-backend/main.go @@ -16,7 +16,7 @@ import ( ) const ( - appVersion = "0.8.0" + appVersion = "0.8.1" pluginID = "local.omarchy-citizen" ) diff --git a/backend/cmd/omarchy-citizen-backend/stack.go b/backend/cmd/omarchy-citizen-backend/stack.go index 204abc8..d920ec5 100644 --- a/backend/cmd/omarchy-citizen-backend/stack.go +++ b/backend/cmd/omarchy-citizen-backend/stack.go @@ -580,7 +580,7 @@ func (a *App) ensurePrefixComponents(gc GameConfig) error { cache := filepath.Join(a.cacheDir, "winetricks-cache", tag) _ = os.MkdirAll(cache, 0o755) env = append(env, "W_CACHE="+cache, "WINETRICKS_DOWNLOADER=curl") - cmd := exec.Command(wt, "-q", "arial", "tahoma", "dxvk", "powershell", "win11") + cmd := exec.Command(wt, "-q", "arial", "tahoma", "powershell", "win11") cmd.Env = env out, err := cmd.CombinedOutput() a.logf("winetricks %s output=%s", tag, compactDiagnostic(string(out))) diff --git a/citizenctl b/citizenctl index 7af7b52..3381a05 100644 --- a/citizenctl +++ b/citizenctl @@ -2,139 +2,194 @@ set -u PLUGIN_ID="local.omarchy-citizen" -PLUGIN_VERSION="0.8.0" +PLUGIN_VERSION="0.8.1" -CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/starcitizen-lug" -DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}" -CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/omarchy-citizen" -STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy-citizen" -UPDATE_CACHE="$CACHE_DIR/lug-update-status" -LOG_FILE="$STATE_DIR/omarchy-citizen.log" -WINE_CONF="$CONFIG_DIR/winedir.conf" -GAME_CONF="$CONFIG_DIR/gamedir.conf" +XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" +XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}" +XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}" +XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}" + +PLUGIN_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" SELF="$(readlink -f "${BASH_SOURCE[0]}")" -PLUGIN_DIR="$(cd -- "$(dirname -- "$SELF")" && pwd)" +STATE_DIR="$XDG_STATE_HOME/omarchy-citizen" +CACHE_DIR="$XDG_CACHE_HOME/omarchy-citizen" +DATA_DIR="$XDG_DATA_HOME/omarchy-citizen" +LOG_FILE="$STATE_DIR/omarchy-citizen.log" +UPDATER_LOG="$STATE_DIR/updater.log" +RSI_LOG="$STATE_DIR/rsi-launcher.log" SANITIZER="$PLUGIN_DIR/support-sanitize.py" BACKEND_EXTERNAL="$HOME/.local/lib/omarchy-citizen/omarchy-citizen-backend" BACKEND_BUNDLED="$PLUGIN_DIR/backend/bin/omarchy-citizen-backend" -MANAGED_LUG="$DATA_DIR/omarchy-citizen/vendor/lug-helper/lug-helper.appimage" -MANAGED_WINE="$DATA_DIR/omarchy-citizen/vendor/wine/current" +MANAGED_LUG="$DATA_DIR/vendor/lug-helper/lug-helper.appimage" +MANAGED_WINE="$DATA_DIR/vendor/wine/current" -GUI_PACKAGES=(zenity polkit cabextract unzip) - -mkdir -p "$CACHE_DIR" "$STATE_DIR" +mkdir -p "$STATE_DIR" "$CACHE_DIR" +ACTION="${1:-status}" rotate_log() { - local max_bytes=$((4 * 1024 * 1024)) - local keep_bytes=$((2 * 1024 * 1024)) - if [[ -f "$LOG_FILE" ]] && (( $(stat -c '%s' "$LOG_FILE" 2>/dev/null || echo 0) > max_bytes )); then - tail -c "$keep_bytes" "$LOG_FILE" > "$LOG_FILE.tmp" 2>/dev/null || true - mv -f "$LOG_FILE.tmp" "$LOG_FILE" 2>/dev/null || true + local max=$((4 * 1024 * 1024)) keep=$((2 * 1024 * 1024)) size=0 + if [[ -f "$LOG_FILE" ]]; then + size="$(stat -c '%s' "$LOG_FILE" 2>/dev/null || echo 0)" + if (( size > max )); then + tail -c "$keep" "$LOG_FILE" > "$LOG_FILE.tmp" 2>/dev/null || true + mv -f "$LOG_FILE.tmp" "$LOG_FILE" 2>/dev/null || true + fi fi } -rotate_log - -ACTION="${1:-primary}" - log_line() { - local message="$*" - printf '%s [%s] %s\n' "$(date '+%Y-%m-%dT%H:%M:%S%z')" "$$" "$message" >> "$LOG_FILE" 2>/dev/null || true + printf '%s [%s] %s\n' "$(date '+%Y-%m-%dT%H:%M:%S%z')" "$$" "$*" >>"$LOG_FILE" 2>/dev/null || true } +rotate_log log_line "action=$ACTION version=$PLUGIN_VERSION" +notify() { + local title="$1" body="$2" + if command -v omarchy-notification-send >/dev/null 2>&1; then + omarchy-notification-send "$title" "$body" >/dev/null 2>&1 || true + elif command -v notify-send >/dev/null 2>&1; then + notify-send "$title" "$body" >/dev/null 2>&1 || true + fi +} + +notify_error() { + local body="$1" + log_line "error=$body" + if command -v zenity >/dev/null 2>&1; then + zenity --error --width=560 --title="Omarchy Citizen" --text="$body" >/dev/null 2>&1 || true + else + notify "Omarchy Citizen" "$body" + printf 'Omarchy Citizen: %s\n' "$body" >&2 + fi +} find_backend() { if [[ -x "$BACKEND_EXTERNAL" ]]; then printf '%s\n' "$BACKEND_EXTERNAL" - return 0 - fi - if [[ -x "$BACKEND_BUNDLED" ]]; then + elif [[ -x "$BACKEND_BUNDLED" ]]; then printf '%s\n' "$BACKEND_BUNDLED" - return 0 + else + return 1 fi - return 1 } -backend_status() { - local game_output="" plugin_output="" health="setup" prefix_state="missing" launcher_state="missing" game_state="missing" - local wine_version="" dxvk_version="" lug_version="" hardware="unknown" hardware_reason="" gpu="" vulkan="unknown" +backend_exec() { + local backend + backend="$(find_backend)" || { + printf 'Go-Backend nicht gefunden. Plugin bitte neu installieren.\n' >&2 + return 127 + } + "$backend" "$@" +} - if game_output="$(backend_game_status 2>/dev/null)"; then - health="$(printf '%s\n' "$game_output" | sed -n 's/^health=//p' | head -n1)" - prefix_state="$(printf '%s\n' "$game_output" | sed -n 's/^prefix_state=//p' | head -n1)" - launcher_state="$(printf '%s\n' "$game_output" | sed -n 's/^launcher_state=//p' | head -n1)" - game_state="$(printf '%s\n' "$game_output" | sed -n 's/^game_state=//p' | head -n1)" - wine_version="$(printf '%s\n' "$game_output" | sed -n 's/^wine_version=//p' | head -n1)" - dxvk_version="$(printf '%s\n' "$game_output" | sed -n 's/^dxvk_version=//p' | head -n1)" - lug_version="$(printf '%s\n' "$game_output" | sed -n 's/^lug_version=//p' | head -n1)" - hardware="$(printf '%s\n' "$game_output" | sed -n 's/^hardware=//p' | head -n1)" - hardware_reason="$(printf '%s\n' "$game_output" | sed -n 's/^hardware_reason=//p' | head -n1)" - gpu="$(printf '%s\n' "$game_output" | sed -n 's/^gpu=//p' | head -n1)" - vulkan="$(printf '%s\n' "$game_output" | sed -n 's/^vulkan=//p' | head -n1)" +backend_game_status() { backend_exec game-status; } +backend_plugin_status() { backend_exec status; } +backend_game_install() { backend_exec game-install; } +backend_game_launch() { backend_exec game-launch; } +backend_game_repair() { backend_exec game-repair; } +autopilot_enable() { backend_exec autopilot enable; } +autopilot_maintain() { backend_exec maintain; } +wine_doctor() { backend_exec doctor; } + +kv_get() { + local key="$1" + sed -n "s/^${key}=//p" | head -n1 +} + +status() { + local game="" plugin="" + local health="setup" hardware="unknown" hardware_reason="" gpu="" vulkan="unknown" + local prefix="missing" launcher="missing" game_state="missing" wine="" dxvk="" lug="" game_autopilot="false" + local backend_state="missing" backend_version="" managed="manual" auto_apply="false" auto_maintain="false" + local update="unavailable" local_commit="" remote_commit="" maintenance="" + + if game="$(backend_game_status 2>/dev/null)"; then + health="$(printf '%s\n' "$game" | kv_get health)" + hardware="$(printf '%s\n' "$game" | kv_get hardware)" + hardware_reason="$(printf '%s\n' "$game" | kv_get hardware_reason)" + gpu="$(printf '%s\n' "$game" | kv_get gpu)" + vulkan="$(printf '%s\n' "$game" | kv_get vulkan)" + prefix="$(printf '%s\n' "$game" | kv_get prefix_state)" + launcher="$(printf '%s\n' "$game" | kv_get launcher_state)" + game_state="$(printf '%s\n' "$game" | kv_get game_state)" + wine="$(printf '%s\n' "$game" | kv_get wine_version)" + dxvk="$(printf '%s\n' "$game" | kv_get dxvk_version)" + lug="$(printf '%s\n' "$game" | kv_get lug_version)" + game_autopilot="$(printf '%s\n' "$game" | kv_get autopilot)" fi + if plugin="$(backend_plugin_status 2>/dev/null)"; then + backend_state="ready" + backend_version="$(printf '%s\n' "$plugin" | kv_get backend_version)" + managed="$(printf '%s\n' "$plugin" | kv_get managed)" + auto_apply="$(printf '%s\n' "$plugin" | kv_get auto_apply)" + auto_maintain="$(printf '%s\n' "$plugin" | kv_get auto_maintain)" + update="$(printf '%s\n' "$plugin" | kv_get update)" + local_commit="$(printf '%s\n' "$plugin" | kv_get local_commit)" + remote_commit="$(printf '%s\n' "$plugin" | kv_get remote_commit)" + maintenance="$(printf '%s\n' "$plugin" | kv_get maintenance_result)" + fi + + [[ -n "$health" ]] || health="setup" + [[ -n "$prefix" ]] || prefix="missing" + [[ -n "$launcher" ]] || launcher="missing" + [[ -n "$game_state" ]] || game_state="missing" + [[ -n "$hardware" ]] || hardware="unknown" + [[ -n "$vulkan" ]] || vulkan="unknown" + [[ -n "$update" ]] || update="unavailable" + printf 'plugin_version=%s\n' "$PLUGIN_VERSION" - printf 'health=%s\n' "${health:-setup}" + printf 'health=%s\n' "$health" printf 'deps=ready\n' printf 'deps_missing=\n' - printf 'helper=%s\n' "$([[ -n "$lug_version" ]] && echo ready || echo missing)" - printf 'helper_managed=autopilot\n' - printf 'helper_version=%s\n' "$lug_version" + printf 'helper=%s\n' "$([[ -n "$lug" ]] && echo ready || echo missing)" + printf 'helper_managed=optional\n' + printf 'helper_version=%s\n' "$lug" printf 'update=unknown\n' printf 'update_version=\n' - printf 'prefix=%s\n' "${prefix_state:-missing}" - if [[ "$prefix_state" == "partial" ]]; then printf 'prefix_detail=unvollständig\n'; else printf 'prefix_detail=\n'; fi - printf 'launcher=%s\n' "${launcher_state:-missing}" - printf 'game=%s\n' "${game_state:-missing}" + printf 'prefix=%s\n' "$prefix" + printf 'prefix_detail=%s\n' "$([[ "$prefix" == partial ]] && echo unvollständig || true)" + printf 'launcher=%s\n' "$launcher" + printf 'game=%s\n' "$game_state" + printf 'backend=%s\n' "$backend_state" + printf 'backend_version=%s\n' "$backend_version" + printf 'plugin_managed=%s\n' "$managed" + printf 'plugin_auto=%s\n' "$auto_apply" + printf 'plugin_update=%s\n' "$update" + printf 'plugin_local_commit=%s\n' "$local_commit" + printf 'plugin_remote_commit=%s\n' "$remote_commit" + printf 'autopilot=%s\n' "$([[ "$auto_maintain" == true ]] && echo true || echo "$game_autopilot")" + printf 'managed_lug_version=%s\n' "$lug" + printf 'managed_wine_version=%s\n' "$wine" + printf 'managed_dxvk_version=%s\n' "$dxvk" + printf 'maintenance_result=%s\n' "$maintenance" printf 'hardware=%s\n' "$hardware" printf 'hardware_reason=%s\n' "$hardware_reason" printf 'hardware_gpu=%s\n' "$gpu" printf 'hardware_vulkan=%s\n' "$vulkan" - - if plugin_output="$(backend_status 2>/dev/null)"; then - printf 'backend=ready\n' - else - printf 'backend=missing\n' - fi - printf 'backend_version=%s\n' "$(printf '%s\n' "$plugin_output" | sed -n 's/^backend_version=//p' | head -n1)" - printf 'plugin_managed=%s\n' "$(printf '%s\n' "$plugin_output" | sed -n 's/^managed=//p' | head -n1)" - printf 'plugin_auto=%s\n' "$(printf '%s\n' "$plugin_output" | sed -n 's/^auto_apply=//p' | head -n1)" - printf 'plugin_update=%s\n' "$(printf '%s\n' "$plugin_output" | sed -n 's/^update=//p' | head -n1)" - printf 'plugin_local_commit=%s\n' "$(printf '%s\n' "$plugin_output" | sed -n 's/^local_commit=//p' | head -n1)" - printf 'plugin_remote_commit=%s\n' "$(printf '%s\n' "$plugin_output" | sed -n 's/^remote_commit=//p' | head -n1)" - printf 'autopilot=%s\n' "$(printf '%s\n' "$plugin_output" | sed -n 's/^auto_maintain=//p' | head -n1)" - printf 'managed_lug_version=%s\n' "${lug_version}" - printf 'managed_wine_version=%s\n' "${wine_version}" - printf 'managed_dxvk_version=%s\n' "${dxvk_version}" - printf 'maintenance_result=%s\n' "$(printf '%s\n' "$plugin_output" | sed -n 's/^maintenance_result=//p' | head -n1)" } hardware_info() { - local out reason gpu vulkan - out="$(backend_game_status 2>/dev/null || true)" - reason="$(printf '%s\n' "$out" | sed -n 's/^hardware_reason=//p')" - gpu="$(printf '%s\n' "$out" | sed -n 's/^gpu=//p')" - vulkan="$(printf '%s\n' "$out" | sed -n 's/^vulkan=//p')" + local game reason gpu vulkan + game="$(backend_game_status 2>/dev/null || true)" + reason="$(printf '%s\n' "$game" | kv_get hardware_reason)" + gpu="$(printf '%s\n' "$game" | kv_get gpu)" + vulkan="$(printf '%s\n' "$game" | kv_get vulkan)" if command -v zenity >/dev/null 2>&1; then - zenity --warning --width=600 --title="Omarchy Citizen – Hardware" --text="Star Citizen ist auf diesem System noch nicht spielbereit.\n\nGPU:\n${gpu:-nicht erkannt}\n\nVulkan: ${vulkan:-unbekannt}\n\n${reason:-Hardware-Prüfung fehlgeschlagen.}" >/dev/null 2>&1 || true + zenity --warning --width=620 --title="Omarchy Citizen – Hardware" \ + --text="Star Citizen ist auf diesem System noch nicht spielbereit.\n\nGPU:\n${gpu:-nicht erkannt}\n\nVulkan: ${vulkan:-unbekannt}\n\n${reason:-Hardware-Prüfung fehlgeschlagen.}" >/dev/null 2>&1 || true else - printf '%s\n' "$reason" + printf 'GPU: %s\nVulkan: %s\n%s\n' "${gpu:-nicht erkannt}" "${vulkan:-unbekannt}" "${reason:-Hardware-Prüfung fehlgeschlagen.}" fi } probe_detached_start() { - local label="$1" - shift - + local label="$1"; shift "$@" >>"$LOG_FILE" 2>&1 & - local pid=$! - - sleep 0.45 - + local pid=$! rc=0 + sleep 0.35 if ! kill -0 "$pid" 2>/dev/null; then - local rc=0 wait "$pid" || rc=$? if (( rc != 0 )); then log_line "$label failed rc=$rc" @@ -143,232 +198,29 @@ probe_detached_start() { else disown "$pid" 2>/dev/null || true fi - log_line "$label accepted" - return 0 } launch_terminal_action() { local action="$1" log_line "launch-terminal action=$action" - - # Prefer direct argv-safe terminal launching. This avoids the presentation - # wrapper joining arguments into one shell command string. if command -v uwsm-app >/dev/null 2>&1 && command -v xdg-terminal-exec >/dev/null 2>&1; then - if probe_detached_start "uwsm-xdg-terminal" \ - setsid uwsm-app -- xdg-terminal-exec \ - --app-id=org.omarchy.terminal \ - --title="Omarchy Citizen Setup" \ - -e bash "$SELF" "$action"; then - printf 'terminal=opened\n' - return 0 - fi + probe_detached_start "uwsm-xdg-terminal" setsid uwsm-app -- xdg-terminal-exec \ + --app-id=org.omarchy.terminal --title="Omarchy Citizen" -e bash "$SELF" "$action" && return 0 fi - if command -v xdg-terminal-exec >/dev/null 2>&1; then - if probe_detached_start "xdg-terminal" \ - xdg-terminal-exec \ - --title="Omarchy Citizen Setup" \ - -e bash "$SELF" "$action"; then - printf 'terminal=opened\n' - return 0 - fi + probe_detached_start "xdg-terminal" xdg-terminal-exec --title="Omarchy Citizen" -e bash "$SELF" "$action" && return 0 fi - - # Final compatibility fallback for older/current Omarchy installations. if command -v omarchy-launch-floating-terminal-with-presentation >/dev/null 2>&1; then - if probe_detached_start "omarchy-floating-terminal" \ - omarchy-launch-floating-terminal-with-presentation bash "$SELF" "$action"; then - printf 'terminal=opened\n' - return 0 - fi + probe_detached_start "omarchy-terminal" omarchy-launch-floating-terminal-with-presentation bash "$SELF" "$action" && return 0 fi - - echo "Das Setup-Terminal konnte nicht geöffnet werden." >&2 - notify_error "Das Setup-Terminal konnte nicht geöffnet werden. - -Bitte klicke auf „Support-Paket erstellen“. Der fehlgeschlagene Startversuch ist dort protokolliert." + notify_error "Das Omarchy-Citizen-Terminal konnte nicht geöffnet werden. Bitte ein Support-Paket erstellen." return 1 } - -backup_lug_target_configs() { - local stamp="$1" - local f - mkdir -p "$CONFIG_DIR" - for f in "$WINE_CONF" "$GAME_CONF"; do - if [[ -f "$f" ]]; then - mv -- "$f" "${f}.incomplete-${stamp}" - log_line "backed up LUG config $(basename "$f") -> $(basename "${f}.incomplete-${stamp}")" - fi - done -} - -stop_prefix_wineserver() { - local prefix="$1" - local wineserver="" - - # Kill only a wineserver associated with the runner inside this target prefix. - # Do not kill unrelated Wine applications globally. - wineserver="$(find "$prefix/runners" -type f -path '*/bin/wineserver' -perm -u+x -print -quit 2>/dev/null || true)" - if [[ -n "$wineserver" ]]; then - WINEPREFIX="$prefix" "$wineserver" -k >>"$LOG_FILE" 2>&1 || true - sleep 0.5 - fi -} - -recover_incomplete_prefix_terminal() { - set -Ee - exec > >(tee -a "$LOG_FILE") 2>&1 - - local prefix stamp backup datap4k="" - - recovery_failed() { - local rc=$? - trap - ERR - echo - echo "==================================================" - echo " REPARATUR KONNTE NICHT ABGESCHLOSSEN WERDEN" - echo "==================================================" - echo - echo "Fehlercode: $rc" - echo - echo "Dein vorheriger Ordner wurde nicht gelöscht." - echo "Im SC-Panel kannst du jetzt „Support-Paket erstellen“ wählen." - echo - log_line "recover-prefix-terminal failed rc=$rc" - notify "Omarchy Citizen" "Setup-Reparatur fehlgeschlagen. Bitte erstelle ein Support-Paket." - if [[ -t 0 ]]; then - read -r -p "Drücke Enter, um dieses Fenster zu schließen … " _ || true - else - sleep 10 - fi - exit "$rc" - } - trap recovery_failed ERR - - prefix="$(find_incomplete_prefix 2>/dev/null)" || { - echo "Es wurde kein unvollständiger Wine-Prefix mehr gefunden." - echo "Starte stattdessen die normale Einrichtung." - log_line "recover-prefix-terminal no incomplete prefix found" - trap - ERR - return 0 - } - - datap4k="$prefix/drive_c/Program Files/Roberts Space Industries/StarCitizen/LIVE/Data.p4k" - - echo - echo "==================================================" - echo " Omarchy Citizen – Setup sicher reparieren" - echo "==================================================" - echo - echo "Unvollständiger Wine-Prefix:" - echo " $prefix" - echo - - # Never move real game data ourselves. - if [[ -f "$datap4k" ]]; then - echo "Vorhandene Star-Citizen-Spieldaten wurden erkannt." - echo "Omarchy Citizen verschiebt diese Daten nicht selbst." - echo "Die Reparatur wird an den LUG Helper übergeben." - echo - log_line "recover-prefix-terminal Data.p4k present; delegate to LUG" - run_helper_visible --install - trap - ERR - return 0 - fi - - stamp="$(date '+%Y%m%d-%H%M%S')" - backup="${prefix}-incomplete-${stamp}" - - echo "Der halbfertige Ordner wird NICHT gelöscht." - echo "Er wird gesichert als:" - echo " $backup" - echo - echo "Danach wird der offizielle LUG-Installer sauber neu gestartet." - echo - - log_line "recover-prefix-terminal prefix=$prefix backup=$backup" - - stop_prefix_wineserver "$prefix" - - mv -- "$prefix" "$backup" - backup_lug_target_configs "$stamp" - - echo "✓ Backup erstellt." - echo - echo "Starte frische LUG-Einrichtung …" - echo - - run_helper_visible --install - - echo - echo "Prüfe den neu angelegten Wine-Prefix …" - if read_prefix >/dev/null 2>&1; then - echo "✓ Wine-Prefix ist vollständig initialisiert." - log_line "recover-prefix-terminal succeeded" - trap - ERR - notify "Omarchy Citizen" "Wine-Prefix wurde erfolgreich neu erstellt." - echo - echo "Reparatur abgeschlossen. Du kannst dieses Fenster schließen." - return 0 - fi - - echo - echo "Der LUG-Installer wurde beendet, aber drive_c/system.reg/user.reg" - echo "sind weiterhin nicht vollständig vorhanden." - echo - log_line "recover-prefix-terminal LUG returned but prefix still incomplete" - return 1 -} - -recover_incomplete_prefix() { - launch_terminal_action recover-prefix-terminal -} - -guided_setup_interactive() { - log_line "guided-setup begin" - - if ! find_helper >/dev/null 2>&1; then - launch_terminal_action install-stack-terminal - return 0 - fi - - if find_incomplete_prefix >/dev/null 2>&1; then - log_line "guided setup found incomplete prefix; opening visible recovery terminal" - launch_terminal_action recover-prefix-terminal - return $? - fi - - run_helper_sync --preflight-check || true - - if ! read_prefix >/dev/null 2>&1; then - run_helper_sync --install || true - elif ! prefix="$(read_prefix 2>/dev/null)" || [[ ! -f "$prefix/sc-launch.sh" ]]; then - run_helper_sync --update-launch-script || true - fi - - prefix="$(read_prefix 2>/dev/null || true)" - if [[ -n "$prefix" && -f "$prefix/sc-launch.sh" ]]; then - game_dir="$(read_game_dir 2>/dev/null || true)" - if [[ -z "$game_dir" || ! -f "$game_dir/LIVE/Bin64/StarCitizen.exe" ]]; then - log_line "guided-setup opening RSI Launcher for game installation" - nohup bash "$prefix/sc-launch.sh" >>"$LOG_FILE" 2>&1 & - fi - fi - - notify "Omarchy Citizen" "Einrichtung abgeschlossen. Falls Star Citizen noch fehlt, ist der RSI Launcher für die Installation geöffnet." - log_line "guided-setup end" -} - -guided_setup() { - launch_terminal_action install-stack-terminal -} - install_stack_terminal() { set -Ee exec > >(tee -a "$LOG_FILE") 2>&1 - setup_failed() { local rc=$? trap - ERR @@ -376,44 +228,40 @@ install_stack_terminal() { echo "==================================================" echo " SETUP KONNTE NICHT ABGESCHLOSSEN WERDEN" echo "==================================================" - echo echo "Fehlercode: $rc" - echo "Im SC-Panel kannst du mit einem Klick ein Support-Paket erstellen." - log_line "owned-stack setup failed rc=$rc" + echo "Alle Details wurden protokolliert. Im SC-Panel genügt 'Support-Paket erstellen'." notify "Omarchy Citizen" "Setup fehlgeschlagen. Bitte Support-Paket erstellen." if [[ -t 0 ]]; then read -r -p "Drücke Enter zum Schließen … " _ || true; fi exit "$rc" } trap setup_failed ERR - echo echo "==================================================" echo " Omarchy Citizen – Spielbereit machen" echo "==================================================" echo - echo "Omarchy Citizen verwaltet den kritischen Gaming-Stack jetzt selbst." - echo "Der LUG Helper entscheidet nicht mehr, welche Wine-Version installiert wird." - echo - local hw - hw="$(backend_game_status)" - if [[ "$(printf '%s\n' "$hw" | sed -n 's/^health=//p')" == "hardware-blocked" ]]; then + local game health reason + game="$(backend_game_status 2>/dev/null || true)" + health="$(printf '%s\n' "$game" | kv_get health)" + if [[ "$health" == "hardware-blocked" ]]; then + reason="$(printf '%s\n' "$game" | kv_get hardware_reason)" echo "Hardware-Prüfung nicht bestanden:" - printf '%s\n' "$hw" | grep -E '^(hardware_reason|gpu|vulkan)=' + echo "${reason:-Keine Star-Citizen-taugliche Vulkan-GPU erkannt.}" trap - ERR return 2 fi - echo "1/4 Autopilot aktivieren und Quellen synchronisieren …" + echo "1/4 Autopilot aktivieren und Gaming-Stack synchronisieren …" autopilot_enable echo - echo "2/4 Kompatiblen Wine-Runner prüfen …" + echo "2/4 Wine-Runner auf diesem Rechner prüfen …" wine_doctor echo - echo "3/4 Wine-Prefix, Komponenten und RSI Launcher installieren/reparieren …" + echo "3/4 Wine-Prefix, Komponenten und offiziellen RSI Launcher einrichten …" backend_game_install echo - echo "4/4 Gaming-Stack abschließend synchronisieren …" + echo "4/4 Wartungsstand abschließend synchronisieren …" autopilot_maintain || true trap - ERR @@ -421,490 +269,251 @@ install_stack_terminal() { echo "==================================================" echo " SOFTWARE-STACK BEREIT" echo "==================================================" - echo - echo "Der RSI Launcher kann jetzt gestartet werden." - echo "Anmeldung und der eigentliche Spieldownload erfolgen im offiziellen RSI Launcher." + echo "Der offizielle RSI Launcher ist eingerichtet. Anmeldung und Spieldownload erfolgen dort." notify "Omarchy Citizen" "Software-Stack ist bereit. RSI Launcher kann gestartet werden." } -update_helper_terminal() { - set -Ee - exec > >(tee -a "$LOG_FILE") 2>&1 - echo "Synchronisiere LUG Helper, Wine Runner und DXVK über Autopilot …" - autopilot_maintain - echo "✓ Gaming-Stack ist aktuell." -} - -system_update_terminal() { - set -e - log_line "omarchy update begin" - omarchy update - rm -f "$UPDATE_CACHE" - log_line "omarchy update end rc=0" -} - -launch_game() { - log_line "launch via owned backend" - if ! backend_game_launch >>"$LOG_FILE" 2>&1; then - notify_error "Star Citizen konnte nicht gestartet werden. Nutze „Problem beheben“ oder erstelle ein Support-Paket." - return 1 - fi -} - -primary_action() { - local st health backend - backend="$(find_backend 2>/dev/null || true)" - [[ -n "$backend" ]] && systemctl --user start omarchy-citizen-update.service >/dev/null 2>&1 || true - st="$(status)" - health="$(printf '%s\n' "$st" | sed -n 's/^health=//p' | head -n1)" - case "$health" in - ready|install-game) - launch_game - ;; - hardware-blocked) - hardware_info - ;; - *) - launch_terminal_action install-stack-terminal - ;; - esac -} - repair_stack_terminal() { set -Ee exec > >(tee -a "$LOG_FILE") 2>&1 - echo "Omarchy Citizen prüft und repariert den gesamten Star-Citizen-Stack …" + repair_failed() { + local rc=$? + trap - ERR + echo + echo "REPARATUR FEHLGESCHLAGEN (Code $rc)" + echo "Bitte im SC-Panel ein Support-Paket erstellen." + notify "Omarchy Citizen" "Reparatur fehlgeschlagen. Bitte Support-Paket erstellen." + if [[ -t 0 ]]; then read -r -p "Drücke Enter zum Schließen … " _ || true; fi + exit "$rc" + } + trap repair_failed ERR + + echo "Omarchy Citizen repariert den verwalteten Gaming-Stack …" autopilot_maintain || true backend_game_repair + wine_doctor + trap - ERR echo "Reparatur abgeschlossen." + notify "Omarchy Citizen" "Gaming-Stack wurde repariert." } -repair_assistant_interactive() { - local st health - st="$(status)" - health="$(printf '%s\n' "$st" | sed -n 's/^health=//p' | head -n1)" - if [[ "$health" == "hardware-blocked" ]]; then hardware_info; return; fi +update_stack_terminal() { + set -Ee + exec > >(tee -a "$LOG_FILE") 2>&1 + echo "Synchronisiere Wine, DXVK, RSI Launcher und optionale Support-Werkzeuge …" + autopilot_maintain + echo "Gaming-Stack ist aktuell." +} + +system_update_terminal() { + set -Ee + exec > >(tee -a "$LOG_FILE") 2>&1 + if ! command -v omarchy >/dev/null 2>&1; then + echo "Omarchy-Befehl nicht gefunden." >&2 + return 1 + fi + echo "Starte den offiziellen Omarchy-Systemupdate-Pfad …" + omarchy update -y +} + +primary_action() { + local game health + game="$(backend_game_status 2>/dev/null || true)" + health="$(printf '%s\n' "$game" | kv_get health)" + case "$health" in + hardware-blocked) hardware_info ;; + ready|install-game) backend_game_launch ;; + repair|launcher-repair) launch_terminal_action repair-stack-terminal ;; + *) launch_terminal_action install-stack-terminal ;; + esac +} + +repair_assistant() { launch_terminal_action repair-stack-terminal } -repair_assistant() { repair_assistant_interactive; } +plugin_update_check() { backend_exec check; } +plugin_update_now() { backend_exec update; } +plugin_auto_enable() { backend_exec auto enable; } +plugin_auto_disable() { backend_exec auto disable; } + +open_file() { + local path="$1" + [[ -f "$path" ]] || { notify_error "Datei noch nicht vorhanden: $path"; return 1; } + xdg-open "$path" >/dev/null 2>&1 & +} + +open_debug_log() { open_file "$LOG_FILE"; } +open_updater_log() { open_file "$UPDATER_LOG"; } +open_log() { open_file "$RSI_LOG"; } +open_wiki() { xdg-open "https://wiki.starcitizen-lug.org" >/dev/null 2>&1 & } +open_ngl_page() { xdg-open "https://www.nglproject.com/de#downloads" >/dev/null 2>&1 & } + +open_helper() { + if [[ -x "$MANAGED_LUG" ]]; then + nohup env APPIMAGE_EXTRACT_AND_RUN=1 "$MANAGED_LUG" >>"$LOG_FILE" 2>&1 & + else + open_wiki + fi +} sanitize_to() { - local source="$1" - local target="$2" - - if [[ ! -f "$source" ]]; then - return 0 - fi - + local source="$1" target="$2" + [[ -f "$source" ]] || return 0 if command -v python3 >/dev/null 2>&1 && [[ -f "$SANITIZER" ]]; then - python3 "$SANITIZER" < "$source" > "$target" + python3 "$SANITIZER" <"$source" >"$target" else - sed \ - -e "s#${HOME//\#/\\#}#~#g" \ - -e 's/[A-Za-z0-9._%+-]\+@[A-Za-z0-9.-]\+\.[A-Za-z]\{2,\}//g' \ - "$source" > "$target" + sed -e "s#${HOME//\#/\\#}#~#g" "$source" >"$target" fi } capture_sanitized() { - local target="$1" - shift + local target="$1"; shift local tmp="$CACHE_DIR/capture-$$-$RANDOM.txt" - { - "$@" - } >"$tmp" 2>&1 || true + "$@" >"$tmp" 2>&1 || true sanitize_to "$tmp" "$target" rm -f "$tmp" } support_build() { - local stamp support_id work downloads archive prefix="" game_dir="" + local stamp support_id work downloads archive game_prefix="" stamp="$(date '+%Y%m%d-%H%M%S')" support_id="OC-${stamp}-$(printf '%s-%s-%s' "$stamp" "$$" "$RANDOM" | sha256sum | cut -c1-6)" - work="$CACHE_DIR/support-$support_id" - - if command -v xdg-user-dir >/dev/null 2>&1; then - downloads="$(xdg-user-dir DOWNLOAD 2>/dev/null || true)" - else - downloads="" - fi + downloads="$(command -v xdg-user-dir >/dev/null 2>&1 && xdg-user-dir DOWNLOAD 2>/dev/null || true)" [[ -n "$downloads" && -d "$downloads" ]] || downloads="$HOME/Downloads" - mkdir -p "$downloads" "$work" + mkdir -p "$downloads" + work="$CACHE_DIR/support-$support_id" + rm -rf "$work" && mkdir -p "$work" - log_line "support build id=$support_id" - - cat > "$work/README_SUPPORT.txt" <"$work/README_SUPPORT.txt" < "$work/citizen-status.txt" - - if backend="$(find_backend 2>/dev/null)"; then - capture_sanitized "$work/updater-status.json" "$backend" status --json - fi - if [[ -f "$STATE_DIR/updater.log" ]]; then - tail -n 1200 "$STATE_DIR/updater.log" > "$CACHE_DIR/updater-log-$$.txt" - sanitize_to "$CACHE_DIR/updater-log-$$.txt" "$work/updater.log" - rm -f "$CACHE_DIR/updater-log-$$.txt" - fi - - capture_sanitized "$work/omarchy-debug.txt" omarchy debug --no-sudo --print - - if backend="$(find_backend 2>/dev/null)"; then - capture_sanitized "$work/autopilot-status.txt" "$backend" status - capture_sanitized "$work/game-status.txt" "$backend" game-status - capture_sanitized "$work/wine-doctor.txt" "$backend" doctor - fi - - { - echo "=== Kernel / Desktop ===" - uname -rmo 2>/dev/null || true - printf 'XDG_SESSION_TYPE=%s\n' "${XDG_SESSION_TYPE:-unknown}" - printf 'XDG_CURRENT_DESKTOP=%s\n' "${XDG_CURRENT_DESKTOP:-unknown}" - printf 'WAYLAND_DISPLAY=%s\n' "${WAYLAND_DISPLAY:-unknown}" - echo - echo "=== Memory ===" - free -h 2>/dev/null || true - echo - echo "=== Filesystems ===" - df -hT / "$HOME" 2>/dev/null || true - echo - echo "=== Block devices ===" - lsblk -o NAME,SIZE,FSTYPE,FSAVAIL,MOUNTPOINTS 2>/dev/null || true - echo - echo "=== GPU ===" - lspci -nnk 2>/dev/null | grep -A4 -Ei 'VGA|3D|Display' || true - echo - echo "=== Vulkan ===" - if command -v vulkaninfo >/dev/null 2>&1; then - vulkaninfo --summary 2>/dev/null || true - else - echo "vulkaninfo not installed" - fi - echo - echo "=== Star Citizen kernel limits ===" - sysctl vm.max_map_count 2>/dev/null || true - printf 'hard_open_files=%s\n' "$(ulimit -Hn 2>/dev/null || true)" - } > "$CACHE_DIR/system-$$.txt" - sanitize_to "$CACHE_DIR/system-$$.txt" "$work/system.txt" - rm -f "$CACHE_DIR/system-$$.txt" - - { - echo "=== Relevant packages ===" - pacman -Q omarchy omarchy-dev lug-helper zenity polkit cabextract unzip 2>/dev/null || true - echo - echo "=== AUR helper ===" - yay --version 2>/dev/null | head -n 4 || true - echo - echo "=== Commands ===" - for cmd in omarchy lug-helper yay zenity wine winetricks gamescope gamemoderun; do - if command -v "$cmd" >/dev/null 2>&1; then - printf '%s=present\n' "$cmd" - else - printf '%s=missing\n' "$cmd" - fi - done - } > "$work/packages.txt" + status >"$work/citizen-status.txt" 2>&1 || true + capture_sanitized "$work/backend-game-status.txt" backend_exec game-status + capture_sanitized "$work/backend-status.txt" backend_exec status + capture_sanitized "$work/wine-doctor.txt" backend_exec doctor if command -v omarchy >/dev/null 2>&1; then capture_sanitized "$work/plugin-validation.txt" omarchy plugin validate "$PLUGIN_DIR" + if omarchy debug --no-sudo --print >"$CACHE_DIR/omarchy-debug-$$.txt" 2>&1; then + sanitize_to "$CACHE_DIR/omarchy-debug-$$.txt" "$work/omarchy-debug.txt" + else + { omarchy version 2>/dev/null || true; omarchy commands --all 2>/dev/null || true; } >"$CACHE_DIR/omarchy-debug-$$.txt" + sanitize_to "$CACHE_DIR/omarchy-debug-$$.txt" "$work/omarchy-debug.txt" + fi + rm -f "$CACHE_DIR/omarchy-debug-$$.txt" fi - if [[ -f "$LOG_FILE" ]]; then - tail -n 1500 "$LOG_FILE" > "$CACHE_DIR/plugin-log-$$.txt" - sanitize_to "$CACHE_DIR/plugin-log-$$.txt" "$work/omarchy-citizen.log" - rm -f "$CACHE_DIR/plugin-log-$$.txt" - fi - - if [[ -f /tmp/omarchy-update.log ]]; then - tail -n 500 /tmp/omarchy-update.log > "$CACHE_DIR/update-log-$$.txt" - sanitize_to "$CACHE_DIR/update-log-$$.txt" "$work/omarchy-update-tail.log" - rm -f "$CACHE_DIR/update-log-$$.txt" - fi - - # LUG Helper writes the detailed Wine-prefix installation output here. - # This is the most useful file when winetricks/Wine prefix creation fails. - latest_lug_install_log="$(find /tmp -maxdepth 1 -type f -name 'lughelper-install-*.log' -printf '%T@ %p\n' 2>/dev/null \ - | sort -nr | head -n1 | cut -d' ' -f2- || true)" - if [[ -n "$latest_lug_install_log" && -f "$latest_lug_install_log" ]]; then - tail -n 1200 "$latest_lug_install_log" > "$CACHE_DIR/lug-install-$$.txt" - sanitize_to "$CACHE_DIR/lug-install-$$.txt" "$work/lug-helper-install-tail.log" - rm -f "$CACHE_DIR/lug-install-$$.txt" - fi - - configured="$(configured_prefix 2>/dev/null || true)" - if [[ -n "$configured" ]]; then - { - printf 'configured_prefix=%s\n' "$configured" - printf 'directory_exists=%s\n' "$([[ -d "$configured" ]] && echo yes || echo no)" - printf 'drive_c=%s\n' "$([[ -d "$configured/drive_c" ]] && echo present || echo missing)" - printf 'system_reg=%s\n' "$([[ -f "$configured/system.reg" ]] && echo present || echo missing)" - printf 'user_reg=%s\n' "$([[ -f "$configured/user.reg" ]] && echo present || echo missing)" - printf 'runner_dirs=%s\n' "$(find "$configured/runners" -mindepth 1 -maxdepth 1 -type d -printf '%f ' 2>/dev/null || true)" - } > "$CACHE_DIR/prefix-health-$$.txt" - sanitize_to "$CACHE_DIR/prefix-health-$$.txt" "$work/wine-prefix-health.txt" - rm -f "$CACHE_DIR/prefix-health-$$.txt" - fi - - prefix="$(read_prefix 2>/dev/null || true)" - game_dir="$(read_game_dir 2>/dev/null || true)" - { - printf 'wine_prefix=%s\n' "${prefix:-not-configured}" - printf 'game_dir=%s\n' "${game_dir:-not-configured}" - printf 'launch_script=%s\n' "$([[ -n "$prefix" && -f "$prefix/sc-launch.sh" ]] && echo present || echo missing)" - printf 'game_binary=%s\n' "$([[ -n "$game_dir" && -f "$game_dir/LIVE/Bin64/StarCitizen.exe" ]] && echo present || echo missing)" - } > "$CACHE_DIR/paths-$$.txt" - sanitize_to "$CACHE_DIR/paths-$$.txt" "$work/star-citizen-path-status.txt" - rm -f "$CACHE_DIR/paths-$$.txt" + echo "=== kernel ==="; uname -rmo 2>/dev/null || true + echo "=== memory ==="; free -h 2>/dev/null || true + echo "=== filesystems ==="; df -hT / "$HOME" 2>/dev/null || true + echo "=== gpu ==="; lspci -nnk 2>/dev/null | grep -A5 -Ei 'VGA|3D|Display' || true + echo "=== vulkan ==="; command -v vulkaninfo >/dev/null 2>&1 && vulkaninfo --summary 2>&1 || true + echo "=== limits ==="; sysctl vm.max_map_count 2>/dev/null || true; ulimit -Hn 2>/dev/null || true + } >"$CACHE_DIR/system-$$.txt" + sanitize_to "$CACHE_DIR/system-$$.txt" "$work/system.txt" + rm -f "$CACHE_DIR/system-$$.txt" - if [[ -n "$prefix" && -f "$prefix/sc-launch.log" ]]; then - tail -n 600 "$prefix/sc-launch.log" > "$CACHE_DIR/sc-launch-$$.txt" - sanitize_to "$CACHE_DIR/sc-launch-$$.txt" "$work/sc-launch-tail.log" - rm -f "$CACHE_DIR/sc-launch-$$.txt" - fi + for pair in "$LOG_FILE:omarchy-citizen.log" "$UPDATER_LOG:updater.log" "$RSI_LOG:rsi-launcher.log"; do + local src="${pair%%:*}" dst="${pair#*:}" + if [[ -f "$src" ]]; then + tail -n 1800 "$src" >"$CACHE_DIR/log-$$.txt" + sanitize_to "$CACHE_DIR/log-$$.txt" "$work/$dst" + rm -f "$CACHE_DIR/log-$$.txt" + fi + done - if [[ -n "$prefix" && -f "$prefix/sc-launch.sh" ]]; then - head -n 350 "$prefix/sc-launch.sh" > "$CACHE_DIR/sc-script-$$.txt" - sanitize_to "$CACHE_DIR/sc-script-$$.txt" "$work/sc-launch-script-sanitized.txt" - rm -f "$CACHE_DIR/sc-script-$$.txt" + game_prefix="$(backend_game_status 2>/dev/null | kv_get prefix || true)" + if [[ -n "$game_prefix" ]]; then + printf 'prefix=%s\n' "$game_prefix" >"$CACHE_DIR/prefix-$$.txt" + sanitize_to "$CACHE_DIR/prefix-$$.txt" "$work/prefix.txt" + rm -f "$CACHE_DIR/prefix-$$.txt" fi archive="$downloads/Omarchy-Citizen-Support-$support_id.tar.gz" tar -C "$work" -czf "$archive" . rm -rf "$work" - - log_line "support archive=$archive" - - if command -v wl-copy >/dev/null 2>&1; then - printf '%s' "$archive" | wl-copy - fi - - if command -v zenity >/dev/null 2>&1; then - zenity --info --width=580 \ - --title="Support-Paket erstellt" \ - --text="Support-ID: -$support_id - -Das bereinigte Support-Paket wurde in deinem Downloads-Ordner erstellt: - -$(basename "$archive") - -Der Dateipfad wurde – falls die Zwischenablage verfügbar ist – kopiert. - -Schicke dieses Archiv zusammen mit der Support-ID an den Plugin-Support." \ - >/dev/null 2>&1 || true - else - notify "Omarchy Citizen" "Support-Paket erstellt: $(basename "$archive")" - fi - - if command -v xdg-open >/dev/null 2>&1; then - xdg-open "$downloads" >/dev/null 2>&1 & - fi - + notify "Omarchy Citizen" "Support-Paket erstellt: $(basename "$archive")" + command -v xdg-open >/dev/null 2>&1 && xdg-open "$downloads" >/dev/null 2>&1 & printf '%s\n' "$archive" } -support_start() { - support_build -} - -open_debug_log() { - if [[ ! -f "$LOG_FILE" ]]; then - notify_error "Noch kein Debug-Log vorhanden." - return 1 - fi - xdg-open "$LOG_FILE" >/dev/null 2>&1 & -} - -open_log() { - local prefix log - prefix="$(read_prefix 2>/dev/null)" || { - notify_error "Noch kein Star-Citizen-Wine-Prefix gefunden." - return 1 - } - - log="$prefix/sc-launch.log" - if [[ ! -f "$log" ]]; then - notify_error "Noch kein Start-Log gefunden. - -Starte den RSI Launcher mindestens einmal." - return 1 - fi - - xdg-open "$log" >/dev/null 2>&1 & -} - -open_wiki() { - xdg-open "https://wiki.starcitizen-lug.org" >/dev/null 2>&1 & -} - -open_ngl_page() { - xdg-open "https://www.nglproject.com/de#downloads" >/dev/null 2>&1 & -} - ngl_info() { - local msg - msg="NGL ist ein optionaler Community-Mod für den Windows-RSI-Launcher. - -Omarchy Citizen behandelt NGL als EXPERIMENTELL und installiert es nie ohne deine Auswahl und Bestätigung. - -Der Mod läuft im selben Wine-Prefix wie dein RSI Launcher." - + local msg="NGL ist ein optionaler Community-Mod für den RSI Launcher. Omarchy Citizen installiert ihn nur nach deiner ausdrücklichen Dateiauswahl in den verwalteten Wine-Prefix." if command -v zenity >/dev/null 2>&1; then - zenity --info --width=520 --title="Omarchy Citizen – NGL" --text="$msg" >/dev/null 2>&1 & + zenity --info --width=540 --title="Omarchy Citizen – NGL" --text="$msg" >/dev/null 2>&1 || true else - notify "Omarchy Citizen – NGL" "$msg" + printf '%s\n' "$msg" fi } -ngl_install_interactive() { - local prefix script selected workdir exe - - if ! command -v zenity >/dev/null 2>&1; then - notify_error "Die NGL-Installation benötigt die grafische Dateiauswahl. Bitte zuerst das normale Setup ausführen." - return 1 - fi - - prefix="$(read_prefix 2>/dev/null)" || { - notify_error "Star Citizen muss zuerst eingerichtet werden." - return 1 - } - - script="$prefix/sc-launch.sh" - [[ -f "$script" ]] || { - notify_error "Das Star-Citizen-Start-Script fehlt. Nutze zuerst „Problem beheben“." - return 1 - } - - selected="$(zenity \ - --file-selection \ - --title="NGL Installer auswählen" \ - --filename="$HOME/Downloads/" \ - --file-filter="NGL Installer | *.zip *.ZIP *.exe *.EXE" \ - --file-filter="Alle Dateien | *" 2>/dev/null)" || return 0 - - [[ -f "$selected" ]] || return 1 - - workdir="$CACHE_DIR/ngl-installer" - rm -rf -- "$workdir" - mkdir -p "$workdir" - - case "${selected,,}" in - *.zip) - unzip -q "$selected" -d "$workdir" || { - notify_error "Der NGL-Installer konnte nicht entpackt werden." - return 1 - } - exe="$(find "$workdir" -type f \( -iname '*ngl*.exe' -o -iname '*installer*.exe' -o -iname '*setup*.exe' -o -iname '*.exe' \) \ - -printf '%p\n' | head -n 1)" - ;; - *.exe) - exe="$selected" - ;; - *) - notify_error "Bitte eine NGL-ZIP- oder EXE-Datei auswählen." - return 1 - ;; - esac - - [[ -n "${exe:-}" && -f "$exe" ]] || { - notify_error "Kein Windows-Installer in der ausgewählten Datei gefunden." - return 1 - } - - if ! zenity --question --width=560 \ - --title="NGL experimentell installieren?" \ - --ok-label="Installer starten" \ - --cancel-label="Abbrechen" \ - --text="NGL ist Community-Code und läuft im selben Wine-Prefix wie dein RSI Launcher. - -Bitte nutze ausschließlich Downloads von nglproject.com. - -Fortfahren?" 2>/dev/null; then - return 0 - fi - - log_line "NGL installer confirmed by user" - - { - printf 'wine ' - printf '%q' "$exe" - printf '\nexit\n' - } | bash "$script" shell >>"$LOG_FILE" 2>&1 -} - ngl_install() { - ngl_install_interactive + local game prefix selected exe workdir wine + command -v zenity >/dev/null 2>&1 || { notify_error "Für die NGL-Dateiauswahl wird zenity benötigt."; return 1; } + game="$(backend_game_status)" + prefix="$(printf '%s\n' "$game" | kv_get prefix)" + [[ -n "$prefix" && -d "$prefix/drive_c" ]] || { notify_error "Star Citizen muss zuerst eingerichtet werden."; return 1; } + wine="$(readlink -f "$MANAGED_WINE")/bin/wine" + [[ -x "$wine" ]] || { notify_error "Der verwaltete Wine-Runner fehlt."; return 1; } + + selected="$(zenity --file-selection --title="NGL Installer auswählen" --filename="$HOME/Downloads/" \ + --file-filter="NGL Installer | *.zip *.ZIP *.exe *.EXE" --file-filter="Alle Dateien | *" 2>/dev/null)" || return 0 + [[ -f "$selected" ]] || return 1 + exe="$selected" + if [[ "${selected,,}" == *.zip ]]; then + workdir="$CACHE_DIR/ngl-installer" + rm -rf "$workdir" && mkdir -p "$workdir" + unzip -q "$selected" -d "$workdir" || { notify_error "NGL-ZIP konnte nicht entpackt werden."; return 1; } + exe="$(find "$workdir" -type f -iname '*.exe' -print -quit)" + fi + [[ -n "$exe" && -f "$exe" ]] || { notify_error "Kein Windows-Installer gefunden."; return 1; } + zenity --question --width=560 --title="NGL experimentell installieren?" \ + --ok-label="Installer starten" --cancel-label="Abbrechen" \ + --text="NGL ist Community-Code und läuft im selben Wine-Prefix wie der RSI Launcher. Bitte nur Downloads von nglproject.com verwenden." 2>/dev/null || return 0 + nohup env WINEPREFIX="$prefix" WINEDEBUG=-all "$wine" "$exe" >>"$LOG_FILE" 2>&1 & } case "$ACTION" in - status) status ;; - hardware-info) hardware_info ;; - autopilot-enable) autopilot_enable ;; - autopilot-maintain) autopilot_maintain ;; - wine-doctor) wine_doctor ;; - primary) primary_action ;; - setup) guided_setup ;; - recover-prefix) recover_incomplete_prefix ;; - recover-prefix-terminal) recover_incomplete_prefix_terminal ;; - guided-setup-interactive) guided_setup_interactive ;; - repair) repair_assistant ;; - repair-interactive) repair_assistant_interactive ;; - repair-stack-terminal) repair_stack_terminal ;; - support) support_start ;; - support-build) support_build ;; - debug-log) open_debug_log ;; - plugin-update-check) plugin_update_check ;; - plugin-update-now) plugin_update_now ;; - plugin-auto-enable) plugin_auto_enable ;; - plugin-auto-disable) plugin_auto_disable ;; - updater-log) open_updater_log ;; - check-update) check_update ;; - install-stack) launch_terminal_action install-stack-terminal ;; - install-stack-terminal) install_stack_terminal ;; - update-helper) launch_terminal_action update-helper-terminal ;; - update-helper-terminal) update_helper_terminal ;; - system-update) launch_terminal_action system-update-terminal ;; - system-update-terminal) system_update_terminal ;; - launch) launch_game ;; - helper) run_helper_gui ;; - install) run_helper_gui --install ;; - preflight) run_helper_gui --preflight-check ;; - runners) run_helper_gui --manage-runners ;; - dxvk) run_helper_gui --manage-dxvk ;; - repair-launch) run_helper_gui --update-launch-script ;; - repair-rsi) run_helper_gui --update-rsi-launcher ;; - dirs) run_helper_gui --show-directories ;; - log) open_log ;; - wiki) open_wiki ;; - ngl-page) open_ngl_page ;; - ngl-info) ngl_info ;; - ngl-install) ngl_install ;; - ngl-install-interactive) ngl_install_interactive ;; - *) - notify_error "Unbekannte Omarchy-Citizen-Aktion: $ACTION" - exit 2 - ;; + status) status ;; + hardware-info) hardware_info ;; + primary) primary_action ;; + setup|install-stack) launch_terminal_action install-stack-terminal ;; + install-stack-terminal) install_stack_terminal ;; + repair|repair-interactive|recover-prefix) repair_assistant ;; + repair-stack-terminal|recover-prefix-terminal) repair_stack_terminal ;; + support|support-build) support_build ;; + debug-log) open_debug_log ;; + log) open_log ;; + updater-log) open_updater_log ;; + plugin-update-check|check-update) plugin_update_check ;; + plugin-update-now) plugin_update_now ;; + plugin-auto-enable) plugin_auto_enable ;; + plugin-auto-disable) plugin_auto_disable ;; + autopilot-enable) autopilot_enable ;; + autopilot-maintain|update-helper) launch_terminal_action update-stack-terminal ;; + update-stack-terminal|update-helper-terminal) update_stack_terminal ;; + wine-doctor) launch_terminal_action wine-doctor-terminal ;; + wine-doctor-terminal) set -e; wine_doctor ;; + system-update) launch_terminal_action system-update-terminal ;; + system-update-terminal) system_update_terminal ;; + launch) backend_game_launch ;; + helper) open_helper ;; + preflight) open_helper ;; + runners|dxvk) launch_terminal_action update-stack-terminal ;; + repair-launch|repair-rsi) launch_terminal_action repair-stack-terminal ;; + dirs) ( xdg-open "$DATA_DIR" >/dev/null 2>&1 & ) ;; + wiki) open_wiki ;; + ngl-page) open_ngl_page ;; + ngl-info) ngl_info ;; + ngl-install|ngl-install-interactive) ngl_install ;; + *) notify_error "Unbekannte Omarchy-Citizen-Aktion: $ACTION"; exit 2 ;; esac diff --git a/install.sh b/install.sh index 753a60c..0e998b1 100644 --- a/install.sh +++ b/install.sh @@ -48,7 +48,7 @@ omarchy plugin enable "$PLUGIN_ID" omarchy restart shell >/dev/null 2>&1 || true echo -echo "Omarchy Citizen 0.8.0 wurde installiert:" +echo "Omarchy Citizen 0.8.1 wurde installiert:" echo " $DEST" echo echo "Links-Klick auf 'SC' in der Omarchy-Leiste öffnet das Star-Citizen-Panel." @@ -56,5 +56,5 @@ echo echo "Falls 'SC' nicht sichtbar ist:" echo " omarchy bar move $PLUGIN_ID --section right" echo -echo "LUG Helper Status:" +echo "Omarchy Citizen Status:" bash "$DEST/citizenctl" status diff --git a/manifest.json b/manifest.json index 1b26502..1e30232 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "schemaVersion": 1, "id": "local.omarchy-citizen", "name": "Omarchy Citizen", - "version": "0.8.0", + "version": "0.8.1", "author": "Community prototype", "license": "MIT", "description": "Omarchy Citizen self-managed Star Citizen stack: compatible Wine selection, owned prefix/launcher installation, automatic DXVK/RSI updates, hardware gate, rollback and support diagnostics.", diff --git a/tests/smoke-citizenctl.sh b/tests/smoke-citizenctl.sh new file mode 100644 index 0000000..bc1daa2 --- /dev/null +++ b/tests/smoke-citizenctl.sh @@ -0,0 +1,132 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +TMP="$(mktemp -d)" +trap 'rm -rf "$TMP"' EXIT +mkdir -p "$TMP/home/.local/lib/omarchy-citizen" "$TMP/bin" "$TMP/home/Downloads" +CALLS="$TMP/calls.log" + +cat > "$TMP/home/.local/lib/omarchy-citizen/omarchy-citizen-backend" <<'BACKEND' +#!/usr/bin/env bash +set -u +printf '%s\n' "$*" >> "${FAKE_CALLS:?}" +case "${1:-status}" in + game-status) + cat <&2; exit 3 ;; +esac +BACKEND +chmod +x "$TMP/home/.local/lib/omarchy-citizen/omarchy-citizen-backend" + +cat > "$TMP/bin/xdg-terminal-exec" <<'TERM' +#!/usr/bin/env bash +printf 'terminal:%s\n' "$*" >> "${FAKE_CALLS:?}" +exit 0 +TERM +cat > "$TMP/bin/uwsm-app" <<'UWSM' +#!/usr/bin/env bash +[[ "${1:-}" == "--" ]] && shift +exec "$@" +UWSM +cat > "$TMP/bin/notify-send" <<'NOTIFY' +#!/usr/bin/env bash +exit 0 +NOTIFY +cat > "$TMP/bin/xdg-user-dir" <<'XDG' +#!/usr/bin/env bash +printf '%s/Downloads\n' "$HOME" +XDG +chmod +x "$TMP/bin/"* + +export HOME="$TMP/home" +export XDG_CONFIG_HOME="$HOME/.config" +export XDG_DATA_HOME="$HOME/.local/share" +export XDG_STATE_HOME="$HOME/.local/state" +export XDG_CACHE_HOME="$HOME/.cache" +export PATH="$TMP/bin:/usr/bin:/bin" +export FAKE_CALLS="$CALLS" + +# 1. Status must be fully routed through the Go backend without missing shell functions. +out="$(bash "$ROOT/citizenctl" status 2>&1)" +grep -q '^plugin_version=0.8.1$' <<<"$out" +grep -q '^health=install$' <<<"$out" +grep -q '^managed_wine_version=11.14-1$' <<<"$out" +! grep -qi 'command not found' <<<"$out" + +# 2. The complete setup terminal action must call all owned backend stages. +: > "$CALLS" +bash "$ROOT/citizenctl" install-stack-terminal >/dev/null 2>&1 +grep -q '^autopilot enable$' "$CALLS" +grep -q '^doctor$' "$CALLS" +grep -q '^game-install$' "$CALLS" +grep -q '^maintain$' "$CALLS" + +# 3. Primary setup routing must open the visible setup terminal. +: > "$CALLS" +FAKE_HEALTH=install bash "$ROOT/citizenctl" primary >/dev/null 2>&1 +grep -q 'terminal:.*install-stack-terminal' "$CALLS" + +# 4. A ready installation launches through the Go backend directly. +: > "$CALLS" +FAKE_HEALTH=ready FAKE_PREFIX_STATE=ready FAKE_LAUNCHER_STATE=ready FAKE_GAME_STATE=ready \ + bash "$ROOT/citizenctl" primary >/dev/null 2>&1 +grep -q '^game-launch$' "$CALLS" + +# 5. Repair routing remains visible. +: > "$CALLS" +FAKE_HEALTH=repair bash "$ROOT/citizenctl" primary >/dev/null 2>&1 +grep -q 'terminal:.*repair-stack-terminal' "$CALLS" + +# 6. Plugin updater wrapper must not collide with the combined status function. +: > "$CALLS" +bash "$ROOT/citizenctl" plugin-update-check >/dev/null 2>&1 +grep -q '^check$' "$CALLS" + +echo 'citizenctl smoke tests: OK' diff --git a/tests/verify.sh b/tests/verify.sh new file mode 100644 index 0000000..952890c --- /dev/null +++ b/tests/verify.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT" + +for f in citizenctl install.sh INSTALLIEREN.sh uninstall.sh; do + bash -n "$f" +done +python3 -m py_compile support-sanitize.py + +( + cd backend + gofmt -w cmd/omarchy-citizen-backend/*.go + go test ./... + go vet ./... + bash build.sh +) + +bash tests/smoke-citizenctl.sh + +echo "Omarchy Citizen verification: OK"