diff --git a/README.md b/README.md index 9f65cd9..6db8f4b 100644 --- a/README.md +++ b/README.md @@ -38,19 +38,27 @@ not written down anywhere. Existing configs are moved to `config/old/` rather than overwritten. -## Desktops +## The desktop -Panama configures **two** desktops that coexist. Both sessions stay available in -GDM, so you can switch back and forth while you settle in. +Hyprland, with a shell written from scratch. It began as a replacement for a +GNOME session — Forge for tiling, Dash-to-Dock, Openbar, Vitals — and was built +to reproduce it closely enough that muscle memory transferred: same keybinds, +same panel contents, same dock, same Tokyo Night Moon palette. -### GNOME -The original setup: Forge for tiling, Dash-to-Dock, Openbar, Vitals, -AppIndicator support. Configured through `config/dot/forge/` and gsettings. +That is history now rather than a second option. Panama installs and configures +one desktop, and the GNOME session it grew out of is neither installed nor +configured here. What each piece replaced is recorded in +[`config/dot/hypr/DESKTOP-PARITY.md`](config/dot/hypr/DESKTOP-PARITY.md) and in +the comments of the components themselves, because knowing what a thing was +modelled on explains why it behaves the way it does. -### Hyprland -A from-scratch replacement built to reproduce the GNOME setup closely enough -that muscle memory transfers — same keybinds, same panel contents, same dock, -same Tokyo Night Moon palette. +GNOME is not gone from the machine: `gnome-control-center` is a declared +dependency, and Panama's own Settings hands off to it for the panels it +deliberately does not own — Online Accounts, Color, Sound, Network, Keyboard, +Privacy, Wellbeing, Accessibility, and System for users, date and time, region +and remote desktop. The allow-list in +[`services/SystemSettings.qml`](config/dot/quickshell/services/SystemSettings.qml) +is what decides; anything not on it is a panel Panama owns itself. | Piece | What it is | |---|---| @@ -75,8 +83,36 @@ config/ bash/ .bashrc, aliases, env (env is gitignored) copy/ Files copied verbatim over / (needs sudo) dot/ Symlinked into ~/.config + firefox/ Vendored Firefox chrome, linked into the browser profile + local/ Icons and the cursor theme, linked into ~/.local/share old/ Backups of whatever was replaced (gitignored) + wallpapers/ Copied into ~/Pictures/Wallpapers when absent setup/ - packages/ One package per line + packages/ One package per line; extras/ holds the optional categories scripts/ Run in order by ./install +tests/ Contracts. See below +docs/ Settings reference, and the design specs behind the work +``` + +## Tests + +121 of them, under `tests/`, and each is a plain executable you can run on its +own: + +```sh +bash tests/setup/interview-contract +``` + +They are called contracts rather than unit tests because that is what they are: +each one pins a decision that was expensive to get right and is cheap to undo by +accident. Most read or measure the real thing — launching a shell to measure a +surface's geometry, standing stub commands on `PATH` to see what a stage would +have installed, running a script against a throwaway `HOME` — rather than +asserting things about source text, because the bugs worth catching here have all +been ones that source text looked fine for. + +``` +tests/setup/ The installer: the interview, package lists, hardware, extras +tests/quickshell/ The shell and its settings pages +tests/hypr/ The compositor config ``` diff --git a/config/dot/forge/config/.windows.json.~260c6b69 b/config/dot/forge/config/.windows.json.~260c6b69 deleted file mode 100644 index eb4b694..0000000 --- a/config/dot/forge/config/.windows.json.~260c6b69 +++ /dev/null @@ -1,72 +0,0 @@ -{ - "overrides": [ - { - "wmClass": "jetbrains-toolbox", - "mode": "float" - }, - { - "wmClass": "Com.github.amezin.ddterm", - "mode": "float" - }, - { - "wmClass": "Com.github.donadigo.eddy", - "mode": "float" - }, - { - "wmClass": "Conky", - "mode": "float" - }, - { - "wmClass": "Gnome-initial-setup", - "mode": "float" - }, - { - "wmClass": "org.gnome.Calculator", - "mode": "float" - }, - { - "wmClass": "gnome-terminal-preferences", - "mode": "float" - }, - { - "wmClass": "Guake", - "mode": "float" - }, - { - "wmClass": "zoom", - "mode": "float" - }, - { - "wmClass": "mpv", - "mode": "float" - }, - { - "wmClass": "Bitwarden", - "mode": "float" - }, - { - "wmClass": "Hidamari", - "mode": "float" - }, - { - "wmClass": "com.mattjakeman.ExtensionManager", - "mode": "float" - }, - { - "wmClass": "Cider", - "mode": "float" - }, - { - "wmClass": "Ulauncher", - "mode": "float" - }, - { - "wmClass": "com.nextcloud.desktopclient.nextcloud", - "mode": "float" - }, - { - "wmClass": "Emulator", - "mode": "float" - } - ] -} \ No newline at end of file diff --git a/config/dot/forge/config/.windows.json.~318f7cf9 b/config/dot/forge/config/.windows.json.~318f7cf9 deleted file mode 100644 index eb4b694..0000000 --- a/config/dot/forge/config/.windows.json.~318f7cf9 +++ /dev/null @@ -1,72 +0,0 @@ -{ - "overrides": [ - { - "wmClass": "jetbrains-toolbox", - "mode": "float" - }, - { - "wmClass": "Com.github.amezin.ddterm", - "mode": "float" - }, - { - "wmClass": "Com.github.donadigo.eddy", - "mode": "float" - }, - { - "wmClass": "Conky", - "mode": "float" - }, - { - "wmClass": "Gnome-initial-setup", - "mode": "float" - }, - { - "wmClass": "org.gnome.Calculator", - "mode": "float" - }, - { - "wmClass": "gnome-terminal-preferences", - "mode": "float" - }, - { - "wmClass": "Guake", - "mode": "float" - }, - { - "wmClass": "zoom", - "mode": "float" - }, - { - "wmClass": "mpv", - "mode": "float" - }, - { - "wmClass": "Bitwarden", - "mode": "float" - }, - { - "wmClass": "Hidamari", - "mode": "float" - }, - { - "wmClass": "com.mattjakeman.ExtensionManager", - "mode": "float" - }, - { - "wmClass": "Cider", - "mode": "float" - }, - { - "wmClass": "Ulauncher", - "mode": "float" - }, - { - "wmClass": "com.nextcloud.desktopclient.nextcloud", - "mode": "float" - }, - { - "wmClass": "Emulator", - "mode": "float" - } - ] -} \ No newline at end of file diff --git a/config/dot/forge/config/.windows.json.~38323208 b/config/dot/forge/config/.windows.json.~38323208 deleted file mode 100644 index eb4b694..0000000 --- a/config/dot/forge/config/.windows.json.~38323208 +++ /dev/null @@ -1,72 +0,0 @@ -{ - "overrides": [ - { - "wmClass": "jetbrains-toolbox", - "mode": "float" - }, - { - "wmClass": "Com.github.amezin.ddterm", - "mode": "float" - }, - { - "wmClass": "Com.github.donadigo.eddy", - "mode": "float" - }, - { - "wmClass": "Conky", - "mode": "float" - }, - { - "wmClass": "Gnome-initial-setup", - "mode": "float" - }, - { - "wmClass": "org.gnome.Calculator", - "mode": "float" - }, - { - "wmClass": "gnome-terminal-preferences", - "mode": "float" - }, - { - "wmClass": "Guake", - "mode": "float" - }, - { - "wmClass": "zoom", - "mode": "float" - }, - { - "wmClass": "mpv", - "mode": "float" - }, - { - "wmClass": "Bitwarden", - "mode": "float" - }, - { - "wmClass": "Hidamari", - "mode": "float" - }, - { - "wmClass": "com.mattjakeman.ExtensionManager", - "mode": "float" - }, - { - "wmClass": "Cider", - "mode": "float" - }, - { - "wmClass": "Ulauncher", - "mode": "float" - }, - { - "wmClass": "com.nextcloud.desktopclient.nextcloud", - "mode": "float" - }, - { - "wmClass": "Emulator", - "mode": "float" - } - ] -} \ No newline at end of file diff --git a/config/dot/forge/config/.windows.json.~42767d6d b/config/dot/forge/config/.windows.json.~42767d6d deleted file mode 100644 index eb4b694..0000000 --- a/config/dot/forge/config/.windows.json.~42767d6d +++ /dev/null @@ -1,72 +0,0 @@ -{ - "overrides": [ - { - "wmClass": "jetbrains-toolbox", - "mode": "float" - }, - { - "wmClass": "Com.github.amezin.ddterm", - "mode": "float" - }, - { - "wmClass": "Com.github.donadigo.eddy", - "mode": "float" - }, - { - "wmClass": "Conky", - "mode": "float" - }, - { - "wmClass": "Gnome-initial-setup", - "mode": "float" - }, - { - "wmClass": "org.gnome.Calculator", - "mode": "float" - }, - { - "wmClass": "gnome-terminal-preferences", - "mode": "float" - }, - { - "wmClass": "Guake", - "mode": "float" - }, - { - "wmClass": "zoom", - "mode": "float" - }, - { - "wmClass": "mpv", - "mode": "float" - }, - { - "wmClass": "Bitwarden", - "mode": "float" - }, - { - "wmClass": "Hidamari", - "mode": "float" - }, - { - "wmClass": "com.mattjakeman.ExtensionManager", - "mode": "float" - }, - { - "wmClass": "Cider", - "mode": "float" - }, - { - "wmClass": "Ulauncher", - "mode": "float" - }, - { - "wmClass": "com.nextcloud.desktopclient.nextcloud", - "mode": "float" - }, - { - "wmClass": "Emulator", - "mode": "float" - } - ] -} \ No newline at end of file diff --git a/config/dot/forge/config/.windows.json.~63ed4469 b/config/dot/forge/config/.windows.json.~63ed4469 deleted file mode 100644 index eb4b694..0000000 --- a/config/dot/forge/config/.windows.json.~63ed4469 +++ /dev/null @@ -1,72 +0,0 @@ -{ - "overrides": [ - { - "wmClass": "jetbrains-toolbox", - "mode": "float" - }, - { - "wmClass": "Com.github.amezin.ddterm", - "mode": "float" - }, - { - "wmClass": "Com.github.donadigo.eddy", - "mode": "float" - }, - { - "wmClass": "Conky", - "mode": "float" - }, - { - "wmClass": "Gnome-initial-setup", - "mode": "float" - }, - { - "wmClass": "org.gnome.Calculator", - "mode": "float" - }, - { - "wmClass": "gnome-terminal-preferences", - "mode": "float" - }, - { - "wmClass": "Guake", - "mode": "float" - }, - { - "wmClass": "zoom", - "mode": "float" - }, - { - "wmClass": "mpv", - "mode": "float" - }, - { - "wmClass": "Bitwarden", - "mode": "float" - }, - { - "wmClass": "Hidamari", - "mode": "float" - }, - { - "wmClass": "com.mattjakeman.ExtensionManager", - "mode": "float" - }, - { - "wmClass": "Cider", - "mode": "float" - }, - { - "wmClass": "Ulauncher", - "mode": "float" - }, - { - "wmClass": "com.nextcloud.desktopclient.nextcloud", - "mode": "float" - }, - { - "wmClass": "Emulator", - "mode": "float" - } - ] -} \ No newline at end of file diff --git a/config/dot/forge/config/.windows.json.~68bf2ae6 b/config/dot/forge/config/.windows.json.~68bf2ae6 deleted file mode 100644 index eb4b694..0000000 --- a/config/dot/forge/config/.windows.json.~68bf2ae6 +++ /dev/null @@ -1,72 +0,0 @@ -{ - "overrides": [ - { - "wmClass": "jetbrains-toolbox", - "mode": "float" - }, - { - "wmClass": "Com.github.amezin.ddterm", - "mode": "float" - }, - { - "wmClass": "Com.github.donadigo.eddy", - "mode": "float" - }, - { - "wmClass": "Conky", - "mode": "float" - }, - { - "wmClass": "Gnome-initial-setup", - "mode": "float" - }, - { - "wmClass": "org.gnome.Calculator", - "mode": "float" - }, - { - "wmClass": "gnome-terminal-preferences", - "mode": "float" - }, - { - "wmClass": "Guake", - "mode": "float" - }, - { - "wmClass": "zoom", - "mode": "float" - }, - { - "wmClass": "mpv", - "mode": "float" - }, - { - "wmClass": "Bitwarden", - "mode": "float" - }, - { - "wmClass": "Hidamari", - "mode": "float" - }, - { - "wmClass": "com.mattjakeman.ExtensionManager", - "mode": "float" - }, - { - "wmClass": "Cider", - "mode": "float" - }, - { - "wmClass": "Ulauncher", - "mode": "float" - }, - { - "wmClass": "com.nextcloud.desktopclient.nextcloud", - "mode": "float" - }, - { - "wmClass": "Emulator", - "mode": "float" - } - ] -} \ No newline at end of file diff --git a/config/dot/forge/config/windows.json b/config/dot/forge/config/windows.json deleted file mode 100644 index fc3c7db..0000000 --- a/config/dot/forge/config/windows.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "overrides": [ - { - "wmClass": "jetbrains-toolbox", - "mode": "float" - }, - { - "wmClass": "Com.github.amezin.ddterm", - "mode": "float" - }, - { - "wmClass": "Com.github.donadigo.eddy", - "mode": "float" - }, - { - "wmClass": "Conky", - "mode": "float" - }, - { - "wmClass": "Gnome-initial-setup", - "mode": "float" - }, - { - "wmClass": "org.gnome.Calculator", - "mode": "float" - }, - { - "wmClass": "gnome-terminal-preferences", - "mode": "float" - }, - { - "wmClass": "Guake", - "mode": "float" - }, - { - "wmClass": "zoom", - "mode": "float" - }, - { - "wmClass": "Bitwarden", - "mode": "float" - }, - { - "wmClass": "Hidamari", - "mode": "float" - }, - { - "wmClass": "com.mattjakeman.ExtensionManager", - "mode": "float" - }, - { - "wmClass": "Cider", - "mode": "float" - }, - { - "wmClass": "Ulauncher", - "mode": "float" - }, - { - "wmClass": "com.nextcloud.desktopclient.nextcloud", - "mode": "float" - }, - { - "wmClass": "mpv", - "mode": "float" - }, - { - "wmClass": "Spotify", - "mode": "float" - }, - { - "wmClass": "bitwarden", - "mode": "float" - } - ] -} \ No newline at end of file diff --git a/config/dot/forge/stylesheet/forge/stylesheet.css b/config/dot/forge/stylesheet/forge/stylesheet.css deleted file mode 100644 index aff744d..0000000 --- a/config/dot/forge/stylesheet/forge/stylesheet.css +++ /dev/null @@ -1,190 +0,0 @@ -.tiled { - color: rgba(236, 94, 94, 1); - opacity: 1; - border-width: 3px; -} - -.split { - color: rgba(255, 246, 108, 1); - opacity: 1; - border-width: 3px; -} - -.stacked { - color: rgba(247, 162, 43, 1); - opacity: 1; - border-width: 3px; -} - -.tabbed { - color: rgba(17, 199, 224, 1); - opacity: 1; - border-width: 3px; -} - -.floated { - color: rgba(180, 167, 214, 1); - border-width: 3px; - opacity: 1; -} - -.window-tiled-border { - border-width: 3px; - border-color: rgb(98,160,234); - border-style: solid; - border-radius: 14px; -} - -.window-split-border { - border-width: 3px; - border-color: rgb(98,160,234); - border-style: solid; - border-radius: 14px; -} - -/* forge-36le: St does not paint an asymmetric (single-side) border when a - * border-radius is set, so the directional hint never rendered. Drop the radius - * on the one-edge variants; St paints a straight single-side border reliably. */ - -.window-split-horizontal { - border-left-width: 0; - border-top-width: 0; - border-bottom-width: 0; - border-radius: 0; -} - -.window-split-vertical { - border-left-width: 0; - border-top-width: 0; - border-right-width: 0; - border-radius: 0; -} - -.window-stacked-border { - border-width: 3px; - border-color: rgb(98,160,234); - border-style: solid; - border-radius: 14px; -} - -.window-tabbed-border { - border-width: 3px; - border-color: rgb(98,160,234); - border-style: solid; - border-radius: 14px; -} - -.window-tabbed-bg { - border-radius: 8px; -} - -.window-tabbed-tab { - background-color: rgba(54, 47, 45, 1); - border-color: rgba(98,160,234,0.6); - border-width: 1px; - border-radius: 8px; - color: white; - margin: 1px; - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2); -} - -.window-tabbed-tab-active { - background-color: rgb(98,160,234); - color: black; - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2); -} - -.window-tabbed-tab-close { - padding: 3px; - margin: 4px; - border-radius: 16px; - width: 16px; - background-color: #e06666; -} - -.window-tabbed-tab-icon { - margin: 3px; -} - -.window-floated-border { - border-width: 3px; - border-color: rgb(98,160,234); - border-style: solid; - border-radius: 14px; -} - -.window-tilepreview-tiled { - border-width: 1px; - border-color: rgba(98,160,234,0.3); - border-style: solid; - border-radius: 14px; - background-color: rgba(98,160,234,0.2); -} - -.window-tilepreview-stacked { - border-width: 1px; - border-color: rgba(98,160,234,0.3); - border-style: solid; - border-radius: 14px; - background-color: rgba(98,160,234,0.2); -} - -.window-tilepreview-swap { - border-width: 1px; - border-color: rgba(162, 247, 43, 0.4); - border-style: solid; - border-radius: 14px; - background-color: rgba(162, 247, 43, 0.4); -} - -.window-tilepreview-tabbed { - border-width: 1px; - border-color: rgba(98,160,234,0.3); - border-style: solid; - border-radius: 14px; - background-color: rgba(98,160,234,0.2); -} - -/* Keybindings Cheatsheet Overlay */ - -.forge-cheatsheet { - background-color: #2d2d2d; - border-radius: 16px; - padding: 24px 32px; - border: 1px solid #4d4d4d; - box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4); -} - -.forge-cheatsheet-title { - font-size: 16px; - font-weight: bold; - color: #ffffff; - margin-bottom: 20px; - text-align: center; -} - -.forge-cheatsheet-category { - font-size: 13px; - font-weight: bold; - color: #78aeed; - margin-top: 16px; - margin-bottom: 8px; -} - -.forge-cheatsheet-row { - font-size: 12px; - color: #eeeeec; - margin: 4px 0; - padding: 2px 0; -} - -.forge-cheatsheet-key { - font-family: monospace; - font-weight: bold; - color: #f5c211; - min-width: 180px; -} - -.forge-cheatsheet-desc { - color: #d0cfcc; -} \ No newline at end of file diff --git a/config/dot/forge/stylesheet/forge/stylesheet.css.bak b/config/dot/forge/stylesheet/forge/stylesheet.css.bak deleted file mode 100644 index c80c7ac..0000000 --- a/config/dot/forge/stylesheet/forge/stylesheet.css.bak +++ /dev/null @@ -1,190 +0,0 @@ -.tiled { - color: rgba(236, 94, 94, 1); - opacity: 1; - border-width: 3px; -} - -.split { - color: rgba(255, 246, 108, 1); - opacity: 1; - border-width: 3px; -} - -.stacked { - color: rgba(247, 162, 43, 1); - opacity: 1; - border-width: 3px; -} - -.tabbed { - color: rgba(17, 199, 224, 1); - opacity: 1; - border-width: 3px; -} - -.floated { - color: rgba(180, 167, 214, 1); - border-width: 3px; - opacity: 1; -} - -.window-tiled-border { - border-width: 3px; - border-color: rgb(98,160,234); - border-style: solid; - border-radius: 14px; -} - -.window-split-border { - border-width: 3px; - border-color: rgb(98,160,234); - border-style: solid; - border-radius: 14px; -} - -/* forge-36le: St does not paint an asymmetric (single-side) border when a - * border-radius is set, so the directional hint never rendered. Drop the radius - * on the one-edge variants; St paints a straight single-side border reliably. */ - -.window-split-horizontal { - border-left-width: 0; - border-top-width: 0; - border-bottom-width: 0; - border-radius: 0; -} - -.window-split-vertical { - border-left-width: 0; - border-top-width: 0; - border-right-width: 0; - border-radius: 0; -} - -.window-stacked-border { - border-width: 3px; - border-color: rgb(98,160,234); - border-style: solid; - border-radius: 14px; -} - -.window-tabbed-border { - border-width: 3px; - border-color: rgb(98,160,234); - border-style: solid; - border-radius: 14px; -} - -.window-tabbed-bg { - border-radius: 8px; -} - -.window-tabbed-tab { - background-color: rgba(54, 47, 45, 1); - border-color: rgba(98,160,234,0.6); - border-width: 1px; - border-radius: 8px; - color: white; - margin: 1px; - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2); -} - -.window-tabbed-tab-active { - background-color: rgb(98,160,234); - color: black; - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2); -} - -.window-tabbed-tab-close { - padding: 3px; - margin: 4px; - border-radius: 16px; - width: 16px; - background-color: #e06666; -} - -.window-tabbed-tab-icon { - margin: 3px; -} - -.window-floated-border { - border-width: 1px; - border-color: rgb(98,160,234); - border-style: solid; - border-radius: 14px; -} - -.window-tilepreview-tiled { - border-width: 1px; - border-color: rgba(98,160,234,0.3); - border-style: solid; - border-radius: 14px; - background-color: rgba(98,160,234,0.2); -} - -.window-tilepreview-stacked { - border-width: 1px; - border-color: rgba(98,160,234,0.3); - border-style: solid; - border-radius: 14px; - background-color: rgba(98,160,234,0.2); -} - -.window-tilepreview-swap { - border-width: 1px; - border-color: rgba(162, 247, 43, 0.4); - border-style: solid; - border-radius: 14px; - background-color: rgba(162, 247, 43, 0.4); -} - -.window-tilepreview-tabbed { - border-width: 1px; - border-color: rgba(98,160,234,0.3); - border-style: solid; - border-radius: 14px; - background-color: rgba(98,160,234,0.2); -} - -/* Keybindings Cheatsheet Overlay */ - -.forge-cheatsheet { - background-color: #2d2d2d; - border-radius: 16px; - padding: 24px 32px; - border: 1px solid #4d4d4d; - box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4); -} - -.forge-cheatsheet-title { - font-size: 16px; - font-weight: bold; - color: #ffffff; - margin-bottom: 20px; - text-align: center; -} - -.forge-cheatsheet-category { - font-size: 13px; - font-weight: bold; - color: #78aeed; - margin-top: 16px; - margin-bottom: 8px; -} - -.forge-cheatsheet-row { - font-size: 12px; - color: #eeeeec; - margin: 4px 0; - padding: 2px 0; -} - -.forge-cheatsheet-key { - font-family: monospace; - font-weight: bold; - color: #f5c211; - min-width: 180px; -} - -.forge-cheatsheet-desc { - color: #d0cfcc; -} \ No newline at end of file diff --git a/docs/superpowers/specs/2026-08-20-panama-fresh-install-design.md b/docs/superpowers/specs/2026-08-20-panama-fresh-install-design.md index fa88440..5c5cd55 100644 --- a/docs/superpowers/specs/2026-08-20-panama-fresh-install-design.md +++ b/docs/superpowers/specs/2026-08-20-panama-fresh-install-design.md @@ -280,6 +280,33 @@ The README's Desktops section is rewritten to describe one desktop. The comment depends on it, so a future reader does not mistake it for GNOME-session residue and remove it. `gnome-settings-hyprland.desktop` stays. +Searching for the rest of it found nothing else to cut, and that is worth +recording so nobody goes looking again. `change-settings` never enabled a GNOME +extension. The mentions of Dash-to-Dock, Openbar and Vitals scattered through the +shell are comments saying what a component was modelled on — `Dock.qml` explaining +which intellihide behaviour it reproduces, `Theme.qml` naming where a colour came +from — and `DESKTOP-PARITY.md` is the table of what replaced what. Those are +provenance, not residue: they are the reason the components behave the way they +do, and deleting them would cost the explanation while saving nothing. `Vitals` in +`config/dot/quickshell/services/` is Panama's own bar service and merely shares a +name with the extension it replaced. + +The panel list this spec gave for the handoff was already wrong when it was +written: it named Wacom, which nothing hands off to, and Region, which is a +subpage of System rather than a panel. The nine actual panels are colour, +keyboard, network, online-accounts, privacy, sound, system, universal-access and +wellbeing, and the allow-list in `services/SystemSettings.qml` is what decides. +The comment on `gnome-control-center` in `desktop-packages` repeated the wrong +list and has been corrected to match. + +One test gap turned up here and is closed. The assets contract caught a directory +under `config/dot/` that nothing links, but not the inverse — a name left in the +`dirs` array with no directory behind it, which makes `link-dotfiles` point +`~/.config/` at nothing. Deleting Forge was the exact move that introduces +it, and nothing would have failed if the array entry had been left behind. A +dangling symlink is worse than a missing one, because everything that looks there +finds something. + ### The `panama` command Three subcommands are added to the existing dispatcher, which was written to grow @@ -401,7 +428,11 @@ installer. They remain recoverable from sunhat's git history. They are clutter, not risk; pruning them stays in phase 6. - Guard the `.cargo/env` source in `config/bash/.bashrc` and remove the Codex block. - Rewrite the README: one desktop, the real install stages, and the test suite. -- Audit `docs/settings.md` (21K) for claims that no longer hold. +- **Done, and it needed nothing.** `docs/settings.md` is generated from + `PreferenceSchema.qml` by `panama-settings-docs`, and a contract already fails + when the copy is stale. It is current, all 133 settings, and carries no claim + about GNOME or Forge at all. The audit this line asked for was a manual reading + of a file that cannot go stale without a test saying so. ## Phases diff --git a/setup/packages/desktop-packages b/setup/packages/desktop-packages index ea6702b..92fdfe8 100644 --- a/setup/packages/desktop-packages +++ b/setup/packages/desktop-packages @@ -20,8 +20,10 @@ ghostty # The Calendar agenda opens events in this; see CalendarAgenda.qml. gnome-calendar # NOT GNOME-session residue. Panama's own Settings hands off to this for the -# panels it deliberately does not own -- Online Accounts, Region, Colour, -# Accessibility, Wellbeing, Wacom. See SystemSettings.qml's panel allow-list. +# panels it deliberately does not own -- Online Accounts, Color, Sound, Network, +# Keyboard, Privacy, Wellbeing, Accessibility, and the System panel for users, +# date and time, region and remote desktop. See the allow-list in +# services/SystemSettings.qml, which is what decides. gnome-control-center # install-hardware sets the nouveau blacklist and nvidia-drm.modeset with # grubby, which replaces an argument it already set rather than appending a diff --git a/setup/scripts/link-dotfiles b/setup/scripts/link-dotfiles index d403d47..1c0c844 100755 --- a/setup/scripts/link-dotfiles +++ b/setup/scripts/link-dotfiles @@ -30,10 +30,15 @@ log "Symlinking Panama .bashrc file to ~/.bashrc" ln -s "$PANAMA_BASH/.bashrc" "$HOME/.bashrc" # Each entry is symlinked as ~/.config/ -> $PANAMA_DOT/. -# "forge" is the GNOME tiling extension; "hypr"/"quickshell"/"wofi" are the -# Hyprland desktop. They coexist deliberately — the GNOME session keeps working -# while Hyprland is being used, so you can log back into either. -dirs=("espanso" "forge" "ghostty" "gtk-3.0" "gtk-4.0" "hypr" "kitty" "nvim" \ +# +# One desktop. "forge" was here while the GNOME session was still the fallback +# and Hyprland was being built beside it -- that hedge has been paid off, and a +# configuration for an extension nothing installs is worse than no configuration +# at all, because it reads as a supported thing. +# +# gnome-control-center is a separate matter and stays declared: Panama's own +# Settings hands off to it for the panels it deliberately does not own. +dirs=("espanso" "ghostty" "gtk-3.0" "gtk-4.0" "hypr" "kitty" "nvim" \ "quickshell" "tmux" "uwsm" "vicinae" "wofi" "xdg-desktop-portal") # --- Vim vimrc --- diff --git a/tests/quickshell/declared-assets-contract b/tests/quickshell/declared-assets-contract index f4856d2..f1dc0ba 100755 --- a/tests/quickshell/declared-assets-contract +++ b/tests/quickshell/declared-assets-contract @@ -187,6 +187,28 @@ for dot_dir in "$repo_dir"/config/dot/*/; do || note "config/dot/$name is referenced by neither link-dotfiles nor the shell configuration, so nothing puts it into service" done +# ── 6. Names in the array with nothing behind them ─────────────────────────── +# +# The inverse of the check above, and the one that bites when a directory is +# removed rather than added: an entry left in `dirs` makes link-dotfiles point +# ~/.config/ at a path that does not exist, and a dangling symlink is +# worse than no symlink, because everything that looks there finds something. +# +# Missed the first time this contract was written. Deleting config/dot/forge in +# the GNOME excision was caught by nothing until the array entry was removed too, +# which was luck rather than a test. + +mapfile -t linked_dirs < <(sed -n '/^dirs=(/,/)/p' "$repo_dir/setup/scripts/link-dotfiles" \ + | grep -oE '"[^"]+"' | tr -d '"') + +(( ${#linked_dirs[@]} > 0 )) \ + || note "link-dotfiles' dirs array could not be read, so nothing checked what it links" + +for name in "${linked_dirs[@]}"; do + [[ -d "$repo_dir/config/dot/$name" ]] \ + || note "link-dotfiles links $name, but config/dot/$name does not exist -- that is a dangling symlink in ~/.config" +done + # ── Report ─────────────────────────────────────────────────────────────────── # One asset named by three different files is one finding, not three.