Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins-claude/stl-game-config/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "stl-game-config",
"version": "1.2.1",
"version": "1.2.2",
"description": "Inspect, lint, and configure Steam games via SteamTinkerLaunch — live system/config reporting with JSON output, config linting, and template-based generation",
"author": {
"name": "Logan Gagne"
Expand Down
139 changes: 85 additions & 54 deletions plugins-claude/stl-game-config/scripts/system-info.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,73 +4,104 @@

set -e

# Detect GPU vendor
# sysfs DRM root; overridable so tests can supply fixture cards
DRM_ROOT="${STL_DRM_ROOT:-/sys/class/drm}"

# Detect the vendor of the GPU used for gaming. card0 is often the CPU's iGPU
# (e.g. Ryzen iGPU as card0, discrete NVIDIA as card1), so rank every card:
# NVIDIA > discrete AMD > Intel > AMD iGPU. An amdgpu device with under 2 GiB
# of VRAM is treated as an iGPU (its VRAM is a small BIOS carve-out).
detect_gpu_vendor() {
if command -v nvidia-smi &>/dev/null; then
echo "nvidia"
elif command -v amdgpu-pro-info &>/dev/null || ls /sys/class/drm/card0/device/vendor 2>/dev/null | grep -q "1002"; then
echo "amd"
elif ls /sys/class/drm/card0/device/vendor 2>/dev/null | grep -q "8086"; then
echo "intel"
else
# Fallback: check Vulkan devices
if command -v vulkaninfo &>/dev/null; then
vulkaninfo --summary 2>/dev/null | grep -i "NVIDIA" && echo "nvidia" && return
vulkaninfo --summary 2>/dev/null | grep -i "AMD" && echo "amd" && return
vulkaninfo --summary 2>/dev/null | grep -i "Intel" && echo "intel" && return
fi
echo "unknown"
local card vendor vram score best_score=0 best=""
for card in "$DRM_ROOT"/card[0-9]*; do
# Skip connector entries such as card0-DP-1
[[ "$(basename "$card")" =~ ^card[0-9]+$ ]] || continue
vendor=$(cat "$card/device/vendor" 2>/dev/null) || continue
case "$vendor" in
0x10de) score=4 vendor=nvidia ;;
0x1002)
vram=$(cat "$card/device/mem_info_vram_total" 2>/dev/null) || vram=0
if [ "${vram:-0}" -ge 2147483648 ]; then score=3; else score=1; fi
vendor=amd
;;
0x8086) score=2 vendor=intel ;;
*) continue ;;
esac
if [ "$score" -gt "$best_score" ]; then
best_score=$score
best=$vendor
fi
done
if [ -n "$best" ]; then
echo "$best"
return
fi

# Fallback: NVIDIA proprietary driver without nvidia-drm exposes no DRM card
if command -v nvidia-smi &>/dev/null && nvidia-smi -L &>/dev/null; then
echo "nvidia"
return
fi

# Fallback: check Vulkan devices
if command -v vulkaninfo &>/dev/null; then
vulkaninfo --summary 2>/dev/null | grep -qi "NVIDIA" && echo "nvidia" && return
vulkaninfo --summary 2>/dev/null | grep -qi "AMD" && echo "amd" && return
vulkaninfo --summary 2>/dev/null | grep -qi "Intel" && echo "intel" && return
fi
echo "unknown"
}

# Detect compositor/window manager
detect_compositor() {
if [ "$XDG_SESSION_TYPE" = "wayland" ]; then
case "$XDG_CURRENT_DESKTOP" in
*KDE*) echo "kde" ;;
*GNOME*) echo "gnome" ;;
*XFCE*) echo "xfce" ;;
*MATE*) echo "mate" ;;
*) echo "other-wayland" ;;
esac
elif [ "$XDG_SESSION_TYPE" = "x11" ]; then
case "$XDG_CURRENT_DESKTOP" in
*KDE*) echo "kde-x11" ;;
*GNOME*) echo "gnome-x11" ;;
*) echo "other-x11" ;;
esac
else
echo "unknown"
fi
if [ "$XDG_SESSION_TYPE" = "wayland" ]; then
case "$XDG_CURRENT_DESKTOP" in
*KDE*) echo "kde" ;;
*GNOME*) echo "gnome" ;;
*XFCE*) echo "xfce" ;;
*MATE*) echo "mate" ;;
*) echo "other-wayland" ;;
esac
elif [ "$XDG_SESSION_TYPE" = "x11" ]; then
case "$XDG_CURRENT_DESKTOP" in
*KDE*) echo "kde-x11" ;;
*GNOME*) echo "gnome-x11" ;;
*) echo "other-x11" ;;
esac
else
echo "unknown"
fi
}

# Check if KDE HDR is enabled on primary monitor
check_kde_hdr_enabled() {
if [ "$(detect_compositor)" != "kde" ]; then
echo "false"
return
fi

# Check if kscreen-doctor is available
if ! command -v kscreen-doctor &>/dev/null; then
echo "false"
return
fi

# Get primary output and check HDR status
local output
output=$(kscreen-doctor -o 2>/dev/null | grep -E "HDR|DDC" | head -1)

if echo "$output" | grep -q "HDR: enabled"; then
echo "true"
else
echo "false"
fi
if [ "$(detect_compositor)" != "kde" ]; then
echo "false"
return
fi

# Check if kscreen-doctor and jq are available
if ! command -v kscreen-doctor &>/dev/null || ! command -v jq &>/dev/null; then
echo "false"
return
fi

# Primary output is the enabled one with priority 1. JSON output avoids the
# ANSI color codes kscreen-doctor -o emits even through a pipe.
local hdr
hdr=$(kscreen-doctor -j 2>/dev/null |
jq -r '[.outputs[]? | select(.enabled and .priority == 1)][0].hdr // false' 2>/dev/null) || true

if [ "$hdr" = "true" ]; then
echo "true"
else
echo "false"
fi
}

# Main output
main() {
cat <<EOF
cat <<EOF
{
"gpu_vendor": "$(detect_gpu_vendor)",
"compositor": "$(detect_compositor)",
Expand All @@ -79,4 +110,4 @@ main() {
EOF
}

main
main
2 changes: 1 addition & 1 deletion plugins-copilot/stl-game-config/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "stl-game-config",
"version": "1.2.1",
"version": "1.2.2",
"description": "Inspect, lint, and configure Steam games via SteamTinkerLaunch — live system/config reporting with JSON output, config linting, and template-based generation",
"author": {
"name": "Logan Gagne"
Expand Down
104 changes: 104 additions & 0 deletions tests/stl-game-config/test-system-info.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/usr/bin/env bash
# test-system-info.sh — assertions for check_kde_hdr_enabled and
# detect_gpu_vendor in system-info.sh.
# HDR: a PATH-injected kscreen-doctor mock prints fixture JSON for -j, so the
# result depends only on the fixture: HDR state of the primary (priority 1)
# enabled output, false on anything unparseable or non-KDE.
# GPU: STL_DRM_ROOT points at a fixture tree of cardN/device/vendor files.

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$SCRIPT_DIR/../../plugins-claude/stl-game-config/scripts/system-info.sh"

MOCK_DIR=$(mktemp -d)
trap 'rm -rf "$MOCK_DIR"' EXIT
FIXTURE="$MOCK_DIR/kscreen.json"

cat >"$MOCK_DIR/kscreen-doctor" <<EOF
#!/usr/bin/env bash
[ "\$1" = "-j" ] && cat "$FIXTURE"
EOF
chmod +x "$MOCK_DIR/kscreen-doctor"

PASS=0
FAIL=0

# assert_hdr <label> <want> <fixture-json> [desktop]
assert_hdr() {
local label="$1" want="$2" fixture="$3" desktop="${4:-KDE}" got
printf '%s' "$fixture" >"$FIXTURE"
got=$(PATH="$MOCK_DIR:$PATH" XDG_SESSION_TYPE=wayland XDG_CURRENT_DESKTOP="$desktop" \
bash "$SCRIPT" | jq -r '.kde_hdr_enabled')

if [[ "$got" == "$want" ]]; then
printf " \033[32m✓\033[0m %s\n" "$label"
((PASS++)) || true
else
printf " \033[31m✗\033[0m %s\n" "$label"
printf " want: %s got: %s\n" "$want" "$got"
((FAIL++)) || true
fi
}

echo "── check_kde_hdr_enabled ──"
assert_hdr "non-HDR secondary listed first, primary HDR on (issue #182)" true \
'{"outputs":[{"name":"DP-2","enabled":true,"priority":2},{"name":"DP-3","enabled":true,"priority":1,"hdr":true}]}'
assert_hdr "primary HDR off, secondary HDR on" false \
'{"outputs":[{"name":"DP-2","enabled":true,"priority":2,"hdr":true},{"name":"DP-3","enabled":true,"priority":1,"hdr":false}]}'
assert_hdr "single output without hdr key" false \
'{"outputs":[{"name":"DP-1","enabled":true,"priority":1}]}'
assert_hdr "disabled output carrying priority 1 is ignored" false \
'{"outputs":[{"name":"DP-1","enabled":false,"priority":1,"hdr":true}]}'
assert_hdr "invalid JSON" false 'not json'
assert_hdr "empty output" false ''
assert_hdr "non-KDE compositor" false \
'{"outputs":[{"name":"DP-1","enabled":true,"priority":1,"hdr":true}]}' GNOME

# Empty vulkaninfo and GPU-less nvidia-smi mocks so the no-card fallbacks are
# hermetic; NVIDIA_SMI_GPUS=1 makes nvidia-smi report a GPU
printf '#!/usr/bin/env bash\n' >"$MOCK_DIR/vulkaninfo"
printf '#!/usr/bin/env bash\n[ "${NVIDIA_SMI_GPUS:-0}" = 1 ]\n' >"$MOCK_DIR/nvidia-smi"
chmod +x "$MOCK_DIR/vulkaninfo" "$MOCK_DIR/nvidia-smi"

# assert_gpu <label> <want> <card-spec>...
# Each card-spec is name:vendor[:vram_bytes], e.g. card0:0x1002:536870912
assert_gpu() {
local label="$1" want="$2" drm got spec name vendor vram
shift 2
drm=$(mktemp -d -p "$MOCK_DIR")
for spec in "$@"; do
IFS=: read -r name vendor vram <<<"$spec"
mkdir -p "$drm/$name/device"
echo "$vendor" >"$drm/$name/device/vendor"
[ -n "$vram" ] && echo "$vram" >"$drm/$name/device/mem_info_vram_total"
done
got=$(PATH="$MOCK_DIR:$PATH" STL_DRM_ROOT="$drm" XDG_SESSION_TYPE=x11 \
bash "$SCRIPT" | jq -r '.gpu_vendor')

if [[ "$got" == "$want" ]]; then
printf " \033[32m✓\033[0m %s\n" "$label"
((PASS++)) || true
else
printf " \033[31m✗\033[0m %s\n" "$label"
printf " want: %s got: %s\n" "$want" "$got"
((FAIL++)) || true
fi
}

echo "── detect_gpu_vendor ──"
assert_gpu "AMD iGPU as card0, NVIDIA dGPU as card1" nvidia \
card0:0x1002:536870912 card1:0x10de
assert_gpu "Intel iGPU as card0, discrete AMD as card1" amd \
card0:0x8086 card1:0x1002:17163091968
assert_gpu "AMD iGPU as card0, Intel Arc as card1" intel \
card0:0x1002:536870912 card1:0x8086
assert_gpu "AMD iGPU only" amd card0:0x1002:536870912
assert_gpu "connector entries are ignored" nvidia \
card0:0x10de card0-DP-1:0x8086
assert_gpu "no DRM cards, no vulkan match" unknown
NVIDIA_SMI_GPUS=1 assert_gpu "no DRM cards, nvidia-smi lists a GPU" nvidia

echo ""
echo "PASS: $PASS FAIL: $FAIL"
exit $((FAIL > 0 ? 1 : 0))
Loading