50 lines
5.4 KiB
Markdown
50 lines
5.4 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## What this repo is
|
|
|
|
Master dotfiles repo for a Hyprland desktop on Arch Linux. It has two halves:
|
|
|
|
- `src/` — a small interactive TypeScript CLI (install/update/remove) that manages packages and dotfiles.
|
|
- `packages/` — the actual dotfiles, laid out as [GNU Stow](https://www.gnu.org/software/stow/) packages (one top-level dir per app, mirroring `$HOME`, e.g. `packages/waybar/.config/waybar/config`).
|
|
|
|
The CLI is the only orchestration layer; it shells out to the real `stow`, `pacman`, and `yay` binaries rather than reimplementing symlinking or package management.
|
|
|
|
## Commands
|
|
|
|
```
|
|
npm install
|
|
npm start install # interactive: choose packages, installs them, backs up conflicting files, symlinks into $HOME
|
|
npm start update # pacman -Syu + yay -Syu, then re-links (stow --restow) any new files
|
|
npm start remove # removes symlinks (stow -D), restores the most recent backup (does NOT uninstall packages)
|
|
npx tsc --noEmit # typecheck
|
|
npm test # runs test/ via Node's built-in test runner (node:test) through tsx
|
|
./docker/test.sh "npm test" # run the full suite, including stow-dependent tests skipped on a bare host
|
|
```
|
|
|
|
There is no build step — `tsx` runs the TypeScript directly.
|
|
|
|
## Testing
|
|
|
|
`test/*.test.ts` uses Node's built-in `node:test` + `node:assert` (via `tsx --test`) — no test framework dependency was added. `test/gpu.test.ts` and `test/packages.test.ts` are pure unit tests. `test/stow.test.ts` exercises the real `stow` binary and real filesystem calls against a throwaway `$HOME` (a `mkdtempSync` dir, swapped in via `process.env.HOME` before `stow.ts` is dynamically imported, since `os.homedir()` reads `$HOME` and the module's path constants are computed at import time); each case is skipped when `stow` isn't installed, which is the case on a bare host — run `./docker/test.sh "npm test"` to execute those for real inside a container that has `stow`.
|
|
|
|
`docker/test.sh` (see `docker/Dockerfile`) spins up a disposable Arch container with `stow`/`nodejs`/`npm`/`git`/`sudo` preinstalled and the repo copied to a writable path inside it, so `npm install`, Stow symlinks, and backups never touch the host. Run it with no args for an interactive shell, or pass a command string to run non-interactively.
|
|
|
|
## Architecture
|
|
|
|
- `src/packages.ts` — the package model. Each entry has a `tier` (`required` installs with no prompt; `recommended` is offered via checkbox), an optional `group` for mutually-exclusive alternatives (e.g. `waybar` vs `ags` both have `group: "bar"`, only one gets picked via a select prompt — `launcher` currently has just `hyprlauncher` but is kept as a group so alternatives can be added the same way), and an optional `dir` for when a package's Stow directory name needs to differ from the package name. `toDirs()` converts chosen package names to their Stow directory names.
|
|
- `src/gpu.ts` — `detectGpuVendors()` shells out to `lspci` and matches VGA/3D controller lines against NVIDIA/AMD/Intel keywords (word-boundary regexes — a naive `/amd|ati/i` used to false-positive on the "ati" inside "Corporation"); `driverPackagesFor()` maps detected vendors to their Arch driver packages. `install.ts` shows every detected vendor's packages in a pre-checked confirm prompt (installing all of them on hybrid/Optimus laptops), and if NVIDIA is kept, `stow.ts`'s `writeNvidiaEnvConfig()` writes `~/.config/hypr/conf.d/nvidia.lua` (machine-generated, not stowed) with the Wayland env vars Hyprland's NVIDIA docs recommend.
|
|
- `src/stow.ts` — all filesystem/process side effects live here: bootstrapping `yay` and oh-my-zsh/zinit if missing, installing packages via `yay`, enabling the `sddm` systemd service (`ensureSddmEnabled`), backing up real (non-symlink) files that would collide with a Stow target into `~/.dotfiles-backup/<timestamp>/`, and wrapping `stow`/`--restow`/`-D` (always invoked with an explicit `-d <PACKAGES_DIR>` so behavior doesn't depend on cwd). Also reads/writes `~/.config/dotfiles/state.json`, which records which package dirs were chosen at install time — `update` and `remove` act on this list rather than re-prompting.
|
|
- `src/install.ts`, `src/update.ts`, `src/remove.ts` — the three subcommands, each a thin sequence of calls into `stow.ts`, using `@clack/prompts` for interactive selection in `install.ts`.
|
|
- `src/cli.ts` — dispatches `install|update|remove` via Node's built-in `node:util.parseArgs`.
|
|
- `packages/hyprland/.config/hypr/hyprland.lua` — Hyprland's config, in its **current Lua format** (`hl.config`/`hl.bind`/`hl.monitor`/`hl.on`/`hl.env`), not the old `hyprland.conf` ini/hyprlang syntax deprecated since Hyprland 0.55. Easy detail to get wrong when editing — check `wiki.hypr.land` (or the raw `hyprland-wiki` GitHub markdown) for current syntax rather than assuming the old ini style.
|
|
|
|
### Adding a new app
|
|
|
|
Add a directory under `packages/` mirroring its `$HOME` layout (e.g. `packages/foo/.config/foo/config`), then add a matching entry to `src/packages.ts` (`dir` if the Stow directory name differs from the package name, `group` if it's a mutually-exclusive alternative to another package).
|
|
|
|
### Backup/restore
|
|
|
|
Backups are stored under `~/.dotfiles-backup/<timestamp>/`, mirroring the relative path of whatever real file was moved aside before stowing. `remove` restores only the most recent backup automatically; restoring an older one is a manual `cp -a ~/.dotfiles-backup/<timestamp>/. ~/`.
|