Add Hyprland skill and configuration files; enhance installation process with GPU detection and SDDM support

This commit is contained in:
2026-07-05 22:40:27 +02:00
parent 913ebaab14
commit 93de248c5a
14 changed files with 341 additions and 28 deletions
+42
View File
@@ -0,0 +1,42 @@
import { execFileSync } from "node:child_process";
export type GpuVendor = "nvidia" | "amd" | "intel";
// ponytail: card-generation nuance (e.g. Nouveau for pre-Turing NVIDIA cards) isn't
// handled — add if an unsupported-card report comes in.
const DRIVER_PACKAGES: Record<GpuVendor, string[]> = {
nvidia: ["nvidia-open-dkms", "nvidia-utils", "egl-wayland"],
amd: ["mesa", "vulkan-radeon", "libva-mesa-driver"],
intel: ["mesa", "vulkan-intel", "intel-media-driver"],
};
const VENDOR_PATTERNS: [RegExp, GpuVendor][] = [
[/nvidia/i, "nvidia"],
[/\b(amd|ati)\b/i, "amd"],
[/intel/i, "intel"],
];
export function detectGpuVendors(): GpuVendor[] {
let output: string;
try {
output = execFileSync("lspci", [], { encoding: "utf8" });
} catch {
return [];
}
const controllerLines = output
.split("\n")
.filter((line) => /VGA compatible controller|3D controller/i.test(line));
const found = new Set<GpuVendor>();
for (const line of controllerLines) {
for (const [pattern, vendor] of VENDOR_PATTERNS) {
if (pattern.test(line)) found.add(vendor);
}
}
return [...found];
}
export function driverPackagesFor(vendors: GpuVendor[]): string[] {
return vendors.flatMap((vendor) => DRIVER_PACKAGES[vendor]);
}
+26
View File
@@ -1,11 +1,14 @@
import * as p from "@clack/prompts";
import { groups, packages, toDirs } from "./packages.js";
import { detectGpuVendors, driverPackagesFor } from "./gpu.js";
import {
backupConflicts,
ensureSddmEnabled,
ensureYay,
ensureZsh,
installPackages,
stow,
writeNvidiaEnvConfig,
writeState,
} from "./stow.js";
@@ -36,10 +39,33 @@ export async function install() {
if (p.isCancel(picks)) return p.cancel("Install cancelled.");
for (const name of picks as string[]) chosen.add(name);
const gpuVendors = detectGpuVendors();
const gpuOptions = gpuVendors.flatMap((vendor) =>
driverPackagesFor([vendor]).map((pkg) => ({ value: pkg, label: `${vendor}: ${pkg}` })),
);
let gpuPicks: string[] = [];
if (gpuOptions.length > 0) {
const picked = await p.multiselect({
message: "Detected GPU(s) — confirm driver packages to install",
options: gpuOptions,
initialValues: gpuOptions.map((o) => o.value),
required: false,
});
if (p.isCancel(picked)) return p.cancel("Install cancelled.");
gpuPicks = picked as string[];
for (const name of gpuPicks) chosen.add(name);
}
installPackages([...chosen]);
ensureSddmEnabled();
if (chosen.has("zsh")) ensureZsh();
if (gpuVendors.includes("nvidia") && driverPackagesFor(["nvidia"]).some((pkg) => gpuPicks.includes(pkg))) {
writeNvidiaEnvConfig();
}
const dirs = toDirs([...chosen]);
const backupDir = backupConflicts(dirs);
if (backupDir) p.log.info(`Backed up conflicting files to ${backupDir}`);
+2
View File
@@ -10,6 +10,8 @@ export type Pkg = {
export const packages: Pkg[] = [
{ name: "hyprland", tier: "required" },
{ name: "xdg-desktop-portal-hyprland", tier: "required" },
{ name: "sddm", tier: "required" },
{ name: "pciutils", tier: "required" },
{ name: "waybar", tier: "recommended", group: "bar" },
{ name: "ags", tier: "recommended", group: "bar", aur: true },
{ name: "wofi", tier: "recommended", group: "launcher" },
+18
View File
@@ -63,6 +63,24 @@ export function ensureZsh() {
}
}
export function ensureSddmEnabled() {
try {
execFileSync("systemctl", ["is-enabled", "--quiet", "sddm"]);
} catch {
run("sudo", ["systemctl", "enable", "sddm.service"]);
}
}
// Machine-generated, not stowed — only written when install detects an NVIDIA GPU.
export function writeNvidiaEnvConfig() {
const dir = join(homedir(), ".config", "hypr", "conf.d");
mkdirSync(dir, { recursive: true });
writeFileSync(
join(dir, "nvidia.lua"),
'hl.env("LIBVA_DRIVER_NAME", "nvidia")\nhl.env("__GLX_VENDOR_LIBRARY_NAME", "nvidia")\n',
);
}
// Move real (non-symlink) files that would collide with a stow target out of the way.
export function backupConflicts(dirs: string[]): string | null {
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");