100 Commits
Author SHA1 Message Date
nevaforget e21c046e32 feat(packages): add thunar with volume and thumbnail support
Update PKGBUILD version / update-pkgver (push) Successful in 5s
thunar plus thunar-volman, thunar-archive-plugin, tumbler and
ffmpegthumbnailer. nautilus stays in the list and keeps its preload
service for now, so both file managers are installed side by side.
2026-08-18 17:35:55 +02:00
nevaforget e9e12cc280 fix(swaylock): ship config to /etc/swaylock, blur the background
swaylock reads ~/.swaylock/config, $XDG_CONFIG_HOME/swaylock/config and
SYSCONFDIR/swaylock/config — never /etc/xdg/, where the generic XDG sweep
put it. The config was made effective by seeding it into user homes, but
both seeds are conditional, so a machine that pulled no moonarch-git
update since swaylock arrived ran with no config at all: no wallpaper,
no Catppuccin ring.

The config now lives in defaults/etc/swaylock/config and is owned at
/etc/swaylock/config, which the package alone makes effective. Home
copies still win by search order, so the .install hook retires the
pristine ones; an edited copy stays.

Upstream swaylock has no blur (effect-blur is swaylock-effects only), so
the blur is baked into a second image: wallpaper-blur.jpg, generated with
downsample-blur-upsample. Regenerate it when the wallpaper changes.

moonarch-doctor gains check_swaylock_config, which names the config file
that actually wins and fails when none exists.
2026-08-18 17:33:28 +02:00
nevaforget 5526cdb6ad feat(quickshell): popouts close when the focus leaves them
Update PKGBUILD version / update-pkgver (push) Successful in 5s
An open popout only closed on a backdrop click, Escape, a toggle, or
another screen claiming the slot. Focus moving away without a click —
Alt+Tab, a focus keybind, a workspace switch, a newly mapped window —
left it standing over the desktop.

Three signals, all needed:

- the host surface losing the keyboard, read from Qt's Window.active
  (PanelWindow exports no focus state); the only one that catches a
  focus grab by another layer surface
- niri focusing an actual window, filtered on id >= 0: niri drops window
  focus to none while the popout holds the keyboard, so reacting to every
  change would make each open close itself
- the focused workspace changing, via the new Niri.focusedWorkspaceId;
  workspace ids are unique across outputs, so a monitor switch counts too

No exception for pkexec/keyring prompts raised by popout actions: they
take the focus, so the popout closes and the new state shows on the next
open. Rationale and measurements in DECISIONS.md.
2026-08-18 15:30:06 +02:00
nevaforget 32372b486a fix(quickshell): logout uses the loginctl "auto" session id
Update PKGBUILD version / update-pkgver (push) Successful in 4s
"self" fails with "Caller does not belong to any known session" — the
shell process is not always counted as a session member. "auto" resolves
to the current session and otherwise to the user's graphical session;
verified on systemd 261 to hit session 3, wayland, class user.
2026-08-14 23:31:45 +02:00
nevaforget fe552fc7a5 feat(quickshell): power popout replaces moonset
Update PKGBUILD version / update-pkgver (push) Successful in 4s
Five rows over a model, registered from Launcher.qml under "power" with
the borrowed anchor the clipboard popout uses, so shell.qml and every
user copy of it stay unchanged. Mod+Escape calls the popout by IPC.

Logout goes through `loginctl terminate-session self`, which needs no
XDG_SESSION_ID in the shell environment. Glyph codepoints were read out
of UbuntuSansNerdFont-Regular.ttf.

The reserve Waybar's power button keeps the IPC call and says in its
tooltip that it needs the Quickshell bar; there is no way to reach a
Quickshell popout from a session where Quickshell was killed.
2026-08-14 17:47:06 +02:00
nevaforget a17474f52d feat: replace moongreet with regreet, moonlock with swaylock
Update PKGBUILD version / update-pkgver (push) Successful in 4s
Greeter and lock screen move to the official repos. The greeter keeps
running inside its own niri instance, so niri-greeter.kdl only changes
which binary it spawns; regreet.toml and regreet.css return from f79128b^
with current theme and font names.

swaylock replaces moonlock in the stasis lid and lock_screen actions. Its
config is seeded to the user home, because swaylock never reads /etc/xdg
and the system-wide path does not work on NixOS.

moonlock stays installed: moonset invokes it by name and has no
lock_command option yet.
2026-08-14 14:21:13 +02:00
nevaforget 070a9065be feat(quickshell): replace walker's clipboard picker
Update PKGBUILD version / update-pkgver (push) Successful in 6s
Super+C opened walker's clipboard provider — the last keybind that still
reached walker at all. ClipboardPopout takes over and shells out to
cliphist: list on every open (cliphist has no change signal, so the open
is the refresh point), decode | wl-copy on Enter or click, and delete
with the entry's raw list line on stdin. Every call carries -db-path,
because the history lives in the session db that cliphist-text.service
creates, not in cliphist's ~/.cache default; every shell argument is
positional, so no clipboard content becomes part of a script.

Delete is Ctrl+D, not Del: focus sits in the search field, where Del is
a character delete. It is also what walker's provider used. A footer
hint spells the keys out, since a destructive shortcut is not guessable.

Image entries have no text preview, only a "[[ binary data 6 KiB png
128x128 ]]" placeholder. That placeholder now yields both the thumbnail
extension and a readable "png · 128x128 · 6 KiB" label, and the entry is
decoded to $XDG_RUNTIME_DIR/moonarch-clip for an Image to load — one
decode process per row, so rows do not serialize. The directory is
tmpfs, so thumbnails expire with the session like the history itself.

The popout is keybind-only, but register() needs an on-screen item for
the anchor rect, so it registers from Launcher.qml and borrows that one.
That also leaves shell.qml — and therefore every user copy of it —
unchanged. walker stays installed: moonarch-sink-switcher,
moonarch-cpugov and moonarch-vpn use it as a dmenu, and those are live
in the Waybar reserve config.
2026-08-10 17:04:39 +02:00
nevaforget a95b524d79 feat(quickshell): open a calendar on clock click
Update PKGBUILD version / update-pkgver (push) Successful in 6s
The clock's click toggled the date between short and long form, which the
tooltip already showed in full. It now opens a calendar popout instead.

CalendarPopout uses MonthGrid + WeekNumberColumn + DayOfWeekRow from
QtQuick.Controls (already imported by TrayMenu) so the locale rules —
week start, ISO week numbers, weekday and month names — come from Qt
rather than being re-implemented; only the delegates are ours. Leading
and trailing days stay visible but dimmed, since the grid always renders
six weeks and hiding them would leave the week-number column labelling
blank rows.

Clock takes the full bar height on `height`, not `implicitHeight`: on a
Text root that property is read-only, and the assignment fails the config
load outright.
2026-08-03 11:06:50 +02:00
nevaforget 798f73c5d3 fix(quickshell): always list audio devices in the popout
Update PKGBUILD version / update-pkgver (push) Successful in 6s
The output/input switchers were hidden below two devices, so a machine
with a single sink showed no device list at all — indistinguishable from
a broken popout. The list doubles as the readout of which device is
active, so show it whenever there is at least one node.
2026-07-31 10:59:41 +02:00
nevaforget 7568fe223d feat(quickshell): add camera switch module
Update PKGBUILD version / update-pkgver (push) Successful in 6s
Cameras are off after every boot and get switched on per camera from the
bar. This inverts the privacy problem instead of chasing it: the previous
entry point, detecting camera *use*, cannot see raw V4L2 access at all,
and inotify on /dev/video* cannot tell a real capture from a device query.
An unauthorized camera cannot be opened in the first place.

Mechanism is `authorized` on the USB device. Measured: writing 0 drops the
/dev/videoN nodes and the PipeWire node, writing 1 brings them back and
uvcvideo rebinds itself.

A camera is identified by USB interface class 0x0e in the descriptor blob,
which stays complete while the device is deauthorized (the interface
directories do not) — so no state of our own is needed to keep a
switched-off camera listable and switchable.

The privileged helper re-derives every precondition from kernel data: id
shape, resolved path under /sys/devices, DEVTYPE=usb_device, and a video
interface class. It cannot be used to deauthorize a hub, keyboard or disk.

Switching a camera on authorizes the whole USB device, so the popout names
every other function it carries and flags in red what does not belong on a
camera. Shown rather than blocked: the internal camera carries a DFU
interface and multimedia devices commonly expose HID for their buttons, so
a class filter would lock out legitimate hardware.

Device-supplied labels are rendered as plain text and stripped of the
invisible and directional Unicode range, so a name cannot masquerade as
another device's.

A hot-plugged camera stays on — plugging one in is a deliberate act.
2026-07-29 16:46:56 +02:00
nevaforget 6b345258a4 fix(quickshell): repair privacy indicator detection
The indicator never became visible. Three causes, each measured with
throwaway probe configs against quickshell 0.3.0:

- Link groups report state Unlinked (-1) unless bound by a
  PwObjectTracker, so the "is the link active" guard rejected
  everything. Node properties need the same binding.
- PwNodeType flags share bits between in- and out-streams
  (AudioInStream 13, AudioOutStream 21), so the bitwise test also
  matched playback — browser audio alone set micActive.
- Video streams are left as Untracked with isStream false, so no
  screencast or camera could ever match.

Match media.class of active link endpoints instead, the signal waybar's
privacy module uses. Desktop-audio recording is excluded via the peer
class Audio/Sink, since quickshell does not expose stream.monitor.

Raw V4L2 camera use stays undetectable (no pipewire node exists);
rationale for not observing /dev/video* is in DECISIONS.md.
2026-07-29 14:28:12 +02:00
nevaforget fe1fa43a4d feat(quickshell): bar height 36, invert geometry coupling, unify centering
Update PKGBUILD version / update-pkgver (push) Successful in 6s
moduleHeight (24) becomes the primary vertical token and barHeight is
derived as moduleHeight + moduleMarginV * 2. Previously ModuleBox sized
its pill as barHeight - moduleMarginV * 2, so lowering the bar shrank
every pill by the same amount — the margin is absolute and does not
scale. Bar height is now set via moduleMarginV while the pills hold.

Widget implicitHeight stays on barHeight: ModuleBox has no clip, so the
items overflow the pill and keep the whole bar height clickable, which
matters because the display edge stops the pointer.

Also fixes pre-existing vertical centering. anchors.verticalCenter
centers the Text layout box (ascent + descent) and rounds down on an odd
layout height, which put the network and bluetooth glyphs 1 px above the
bar mid and several others off by 0.5 px. Replaced across 13 widgets with
height: parent.height + verticalAlignment: Text.AlignVCenter, which
centers by font metrics. Workspace dots move from a hardcoded 22 to
moduleHeight.

Verified by pixel measurement: all 7 pills on rows 6-29 (mid 17.50 = bar
mid) and all 14 glyphs with even ink height exactly on 17.50. The
remaining 7 have odd ink height, where 17.50 is not representable on the
pixel grid; two of those are Image, where verticalAlignment does not
apply.
2026-07-28 12:03:32 +02:00
nevaforget 30c9b55be4 fix(quickshell): prefer wired over wifi in network widget
Update PKGBUILD version / update-pkgver (push) Successful in 6s
When both a wired and a wifi connection are up, NetworkManager routes
over ethernet (lower metric) and nm-applet shows the wired icon. The
network indicator and popout checked wifi first, so an ethernet-connected
machine with wifi still associated wrongly showed the wifi glyph and
SSID. Check wiredDev first in the icon, tooltip, popout activeDev, and
compact connection text.
2026-07-16 15:13:56 +02:00
nevaforget 9ce20a096f docs: confirm Kvantum reads /etc/xdg config (open item resolved)
Fresh-path test after the r152 rebuild: with ~/.config/Kvantum moved
aside, a niri-spawned VLC still rendered Catppuccin — Kvantum reads
/etc/xdg/Kvantum/kvantum.kvconfig, so the glob deploy suffices and no
user-home seed is needed.
2026-07-15 15:35:20 +02:00
nevaforget 152253642a fix(quickshell): clear launcher search field on reopen
Update PKGBUILD version / update-pkgver (push) Successful in 6s
The host's Loader keeps the LauncherPopout instance alive across
close/reopen, so a stale query from the previous open lingered in the
search field. Reset the input in focusFirst() (called by PopoutHost on
every open); the text reset cascades through onTextChanged -> query ->
currentIndex.
2026-07-15 15:25:38 +02:00
nevaforget 5fe7d2aaeb feat(qt): theme Qt apps with Catppuccin via Kvantum
Qt apps (e.g. VLC) rendered in the default Fusion style — GTK theming
does not cover Qt. Add the Kvantum style engine + Catppuccin Mocha
Lavender theme, wired via QT_STYLE_OVERRIDE, which covers both Qt5 and
Qt6 (QT_QPA_PLATFORMTHEME can select only one plugin at a time).

Also move all GUI-toolkit env vars (QT_*/GDK/SDL/CLUTTER) from zshrc to
niri's environment{} block: niri is systemd-started, so zsh exports
never reached niri-spawned GUI apps (verified via /proc/environ), only
terminal-launched ones — the app launcher included.

- packages: kvantum, kvantum-qt5, qt6ct + kvantum-theme-catppuccin-git (AUR)
- niri config.kdl: environment{} block; zshrc: GUI-toolkit vars removed
- qt6ct.conf (style=kvantum, icon_theme=Colloid), Kvantum/kvantum.kvconfig
  (theme=catppuccin-mocha-lavender, the Lavender accent)
- CLAUDE.md + DECISIONS.md
2026-07-15 15:20:21 +02:00
nevaforget de44949c0c feat(niri): bind Mod+Space to the quickshell launcher
Replace walker on Mod+Space with the quickshell launcher popout
(qs ipc call popout toggle launcher). walker stays installed and keeps
Super+C clipboard plus its run/calc modes (no longer keybound).
2026-07-15 13:13:46 +02:00
nevaforget 9760400c18 fix(quickshell): let popout-spawned prompts take keyboard focus
Update PKGBUILD version / update-pkgver (push) Successful in 5s
The popout used Exclusive layer-shell keyboard focus while open. On the overlay layer that sits above all normal windows, so a keyring/PSK/polkit prompt spawned by a popout action (e.g. selecting a VPN) mapped unfocused and stayed untypeable — focus was stuck on quickshell.

Switch to OnDemand. Verified on niri 26.04: a keybind-opened popout still grabs the keyboard on open (Escape/Tab/arrow navigation preserved) while an externally-mapped toplevel can steal focus. General fix — covers every popout and every prompt type, no per-action handler.
2026-07-09 09:17:09 +02:00
nevaforget 9566f0d45c docs: record why nm-applet stays in autostart
Update PKGBUILD version / update-pkgver (push) Successful in 5s
Its tray icon is redundant next to the quickshell network widget, but
nm-applet is the session's NM secret agent: agent-owned VPN passwords
(keyring) are delivered — and saved on GUI import — only through it.
Documents the rejected alternatives (indicator flag, tray filter,
system-owned secrets, standalone agents) so this isn't re-litigated.
2026-07-08 16:47:33 +02:00
nevaforget 376ea66e36 feat(quickshell): show connecting, VPN, and wired state on the network indicator
The bar icon only knew off/no-connection/signal strength: an NM (re)connect
read as "no connection", an active VPN was invisible, and a wired-only
machine showed a dead wifi glyph.

- Connecting: cycle the strength ramp (nm-applet style) while the wifi
  device is in ConnectionState.Connecting (covers reconnects too)
- VPN: swap to MDI wifi-strength-N-lock glyphs; wired+VPN uses
  security-network (MDI has no ethernet-lock); tooltip lists active VPNs
- Wired: ethernet glyph, ranked above wifi-off so ethernet-only machines
  show their connection

VPN state moves from NetworkPopout (2s poll while shown) into a shared
NetworkService singleton — the indicator needs it permanently, and an
always-on poll is wasteful. Event-driven via a long-running `nmcli monitor`
(300ms debounce, events burst) with a 60s fallback poll. Rationale:
DECISIONS.md (2026-07-08).
2026-07-08 15:42:26 +02:00
nevaforget 456f2ade99 feat(quickshell): add application launcher + hover affordance
Update PKGBUILD version / update-pkgver (push) Successful in 6s
New Launcher bar widget (first in the left cluster) opening a LauncherPopout
over DesktopEntries — search field + keyboard-navigable app list, launches via
entry.execute(). Icon-click only for now; Mod+Space stays on walker (drun-only
scope, walker keeps dmenu/run/calc).

Placing a popout in the left cluster forced the shared host anchor to become
side-aware: left-cluster triggers left-align (body grows rightward), right
cluster keeps the original right-align — otherwise a left-anchored popout
renders off-screen. The anchor rect now carries the trigger's left edge + width
(PopoutState.openByName, Tray).

Clickable bar widgets gain a hover affordance via opacity (0.8), not color:
the icon color already encodes status (muted/off/active/critical), so a
color-based hover would clobber that signal. Launcher keeps an accent hover as
it carries no status color.
2026-07-08 11:09:28 +02:00
nevaforget c1c2af1abd feat(quickshell): expand network popout with VPN, info, and collapsible sections
Rework the minimal wifi-list popout into a full network panel:
- compact current-connection line (SSID + signal, or Wired/off state)
- VPN section toggling connections via nmcli (Networking API has no VPN state)
- collapsible available-networks list; scanner now gated on shown AND expanded
- collapsible IP details (address/gateway/DNS) via nmcli device show
- nm-connection-editor launcher

Add a shared Divider component for popout section rules and register it in qmldir.
Rebind Super+N from moonarch-vpn to the quickshell network popout toggle.
2026-07-08 10:21:34 +02:00
nevaforget a229ee9c6a feat(quickshell): operate popouts fully by keyboard
Update PKGBUILD version / update-pkgver (push) Successful in 6s
Popouts can now be opened by niri keybind and driven entirely without a
mouse — the whole point of the keybinds.

- keybind: PopoutRouter singleton + IpcHandler (target "popout") route
  toggle/open/close to the focused monitor's PopoutState via
  Niri.activeOutput; each widget registers its popout by name and its
  click handler toggles by name. Mod+A now opens the audio popout
  (replacing walker's audio menu).
- navigation: shared controls (Toggle/ListRow/VolumeSlider) and the new
  IconButton are focusable (activeFocusOnTab, focus ring, Space/Enter,
  slider Left/Right); PopoutPanel focuses the first control on open and
  maps Up/Down onto Qt's Tab chain; an open popout grabs the keyboard.
- ad-hoc glyph buttons (audio mute, media transport, notif dismiss, BT
  forget) folded into IconButton; destructive actions turn red.

Tray stays mouse-only (per-icon menu, not keybind-addressable).
2026-07-08 09:46:01 +02:00
nevaforget 8680a6e5dd docs(quickshell): mark cross-screen single-popout as verified
Live multi-monitor test confirmed the cross-screen fold; the running
instance's log stayed error/warning-free through popout interaction.
2026-07-06 23:43:07 +02:00
nevaforget c34d1d29fe feat(quickshell): keep only one popout open across all screens
Update PKGBUILD version / update-pkgver (push) Successful in 6s
Each bar owns a per-screen PopoutState, so on multi-monitor a popout
could stay open on one screen while another opened on the next — and
per-screen `shown` drives global services (bluetooth discovery, wifi
scan), so closing one screen's popout could kill the service under the
other's still-open popout.

A small PopoutBus singleton holds an `owner` token: open() claims it,
and any state that loses ownership folds up. Per-screen state (and thus
per-screen anchoring/rendering) stays; only cross-screen exclusivity is
added.
2026-07-06 23:34:55 +02:00
nevaforget a7bf8fe37b fix(quickshell): tie up loose ends from the popout composition refactor
The composition + composable-popouts refactor (450580a, 89988c1) left
three rough edges:

- 6 popouts still read the removed PopoutState.currentName in their
  `shown` gate (undefined === "x" → permanently false), so wifi scan,
  bluetooth discovery, threshold reread, governor refresh, toast-silence
  and tray drill-down reset never fired again. Only the current component
  is ever instantiated, so `hasCurrent` alone is the correct gate.
- ModuleBox stopped self-hiding when empty: the Battery box on a desktop
  (no battery) and an empty tray rendered a bare rounded pill. Gate the
  shared container on `inner.implicitWidth > 0` so the fix covers both.
- CLAUDE.md customization example missed `import Quickshell` (unloadable
  as written) and called a Row's rejected centerIn anchor "harmless"
  (Row warns at runtime and ignores it).
2026-07-06 23:34:35 +02:00
nevaforget 89988c1405 feat(quickshell): composable popouts — each widget owns its popout
The composition refactor left Popouts.qml a hardcoded switch, so a
user-composed widget could join the bar but couldn't open a popout in
the shared animated overlay — second-class, and a widget without a
popout is useless for most cases. quickshell's native PopupWindow would
be composable but drops the unfold/morph animation; keep the animation,
make the registry composable instead (caelestia's central Panels.qml
registry was considered and rejected — it fits a few author-owned edge
drawers, not many user-composable per-widget popouts).

PopoutState.open() now takes a Component instead of a name; each widget
carries its popout inline and hands it to the shared host, which renders
whatever is current. Popouts.qml is gone — no central registry, a user
widget brings its own popout and it renders in the same morphing frame.

Verified: qmllint clean, and an end-to-end config where a user widget
opens its own popout on startup instantiates with no errors or binding
loops. Visual/animation not machine-verifiable.
2026-07-06 17:17:59 +02:00
nevaforget 450580aec1 refactor(quickshell)!: replace toggle-config with QML composition
The user-extension layer (moonarch.json + UserConfig singleton +
per-widget enabled() gates + UserWidgets slot) was a bespoke graft.
quickshell has no native settings/toggle/override concept — a config
is composable QML, and $XDG_CONFIG_HOME wins over $XDG_CONFIG_DIRS
(verified in the docs and src/launch/command.cpp).

Ship the bar as a named config (/etc/xdg/quickshell/moonarch/, launched
`-c moonarch`) of importable components; the composition (which widgets,
in what order) lives in shell.qml. Users customize by copying shell.qml
to ~/.config/quickshell/moonarch/ (wins by XDG precedence) and editing
it — reorder, add, and replace all fall out of plain composition, which
also retires the deferred reorder/user-popout/override items.

Also fixes the ModuleBox childrenRect binding loop (Item -> Row).

BREAKING CHANGE: ~/.config/quickshell/moonarch.json and UserWidgets.qml
are no longer read; per-widget toggles are gone in favor of composition.

Verified: qmllint clean (only quickshell C++ type-resolution artifacts),
quickshell loads the default config and a cross-dir composed config with
no binding loops or errors.
2026-07-06 13:17:36 +02:00
nevaforget 31af05f1b6 feat: make quickshell the default bar + notification daemon
Update PKGBUILD version / update-pkgver (push) Successful in 2s
The quickshell pilot proved out in daily use; promote it from manual
pilot to the session default. Additive — no hard deletes: Waybar and
swaync stay installed as reserves.

- niri spawns `quickshell` instead of `moonarch-waybar`; Alt+W toggles
  quickshell ⇄ Waybar for the rare fallback
- swaync's spawn-at-startup is commented out so it releases
  org.freedesktop.Notifications for quickshell's own server (verified:
  quickshell owns the name; flip the comment to return to swaync)
- quickshell added to packages/official.txt (config ships automatically
  via moonarch-git's defaults/xdg install loop)

Remaining: push → CI rebuilds moonarch-git → pacman -Syu; niri changes
take effect on relogin.
2026-07-05 21:00:36 +02:00
nevaforget d2bd8ec470 feat(quickshell): user-extendable bar via config toggles + widget slot
quickshell has no native config merge, so the system bar could only be
adopted wholesale (fork it, lose system updates). This adds an in-repo
extension path: users toggle widgets and add their own without forking.

- UserConfig singleton reads ~/.config/quickshell/moonarch.json
  ({"widgets":{"<key>":false}}); absent/broken = all on, live-reloaded
- qmldir (generated) exposes singletons + components so user QML can
  import "file:///etc/xdg/quickshell" and reuse Theme/ModuleBox/…
- Bar gates its 16 widgets on UserConfig.enabled(key) and loads an
  optional UserWidgets.qml into a right-cluster slot
- verified against quickshell 0.3.0: toggles hide widgets, user widget
  themes correctly, empty/broken config keeps everything on, no binding loops

Pilot only — qmldir must ship when the pilot is packaged. See DECISIONS.md.
2026-07-05 20:00:58 +02:00
nevaforget 9eeeb9c2ee refactor(quickshell): drop the gamemode indicator
It polled GameMode's ClientCount via a busctl fork every 5s, running
regardless of visibility — 24/7 on every machine, worst of all mid-game,
for a value that is 0 almost all the time. Event-driven (persistent
busctl monitor on GameRegistered/GameUnregistered) would fix the waste
but isn't worth it for an indicator only shown while a fullscreen game
runs — when the bar usually isn't visible anyway. Status stays available
via `gamemoded -s`. See DECISIONS.md.
2026-07-05 13:49:44 +02:00
nevaforget 3ad18b677f fix(quickshell): harden mpris widget/popout against firefox + playerctld quirks
Firefox drops mpris:length on pause (seek slider jumped to 0) and exposes
artUrl only intermittently for YouTube (popout showed no cover); playerctld's
proxy player mirrors or lingers as a titleless ghost in the widget.

- popout caches the last known length per track so the seek slider stays put
- popout derives a YouTube thumbnail from the track URL as an artUrl fallback,
  with a music-glyph placeholder when neither is available
- widget skips the playerctld proxy and requires a real trackTitle, so a
  metadata-less browser tab no longer leaks the app name into the bar
2026-07-05 13:49:34 +02:00
nevaforget 7d118e23a4 style(quickshell): align popout active-marker to a shared left column
Network and Bluetooth showed the connected check on the right, while
Audio and CpuGov use a leading check column. Move both to the same
left-aligned 12px marker slot so every popout has one bundled left edge.

Bluetooth keeps connecting…/pairing… in the right cluster — those are
transient status text, not the connected bool the marker represents.
2026-07-05 12:09:27 +02:00
nevaforget 27043d7b57 fix(quickshell): sync cpugov indicator + popout via shared service
Indicator and popout tracked governor state separately, so switching the
profile in the popout left the bar icon/tooltip stale. Add CpuGovService
(singleton, like NightlightService) as the single source of the
auto-cpufreq force profile; both bind to it, so a switch — or an
out-of-band walker change — refreshes both at once.

Indicator now reads the force profile (auto-cpufreq --get-state) instead
of scaling_governor, which flips with load under "default" and mismarked
Auto. Drops the dead "balanced" case; "default" maps to the Auto glyph.
2026-07-05 12:00:46 +02:00
nevaforget d2295aaacf feat(quickshell): port remaining Waybar modules + native nightlight
Brings the bar pilot to Waybar parity (minus taskbar/power). New indicators
and popouts: nightlight, cpu governor, gamemode, updates, privacy, backlight,
and mpris media controls.

Nightlight is reimplemented natively — quickshell runs wlsunset as a child
Process (toggle = running, temperature via restart, state persisted to an XDG
state file), replacing the fragile systemd-service-as-toggle. Privacy detects
mic/screenshare via active PipeWire links (not idle stream presence) to avoid
false positives from the always-on rnnoise input. cpugov/updates reuse the
existing moonarch helper scripts for their privileged/cached logic.

Also: PopoutPanel.panelWidth is now per-popout overridable, VolumeSlider gained
a release signal (apply-on-release), and the right cluster is regrouped by
function (media, tray, alerts, connectivity, output, modes, battery).

Still a pilot: not deployed, packaged, or niri-spawned.
2026-07-05 10:09:56 +02:00
nevaforget a19ab8b5d8 fix(nightlight): keep wlsunset alive when Waybar is absent
ExecStartPost signalled Waybar via `pkill -RTMIN+11 waybar`; with no Waybar
running (e.g. a quickshell-only session) pkill exits 1, which failed the unit
and — via Restart=on-failure — spun wlsunset in a ~3s restart loop that
flickered the screen and could not be switched off (stuck "activating").

Prefix the ExecStartPost with `-` so a missing Waybar is non-fatal. The
refresh signal still fires when Waybar is present.
2026-07-05 10:09:26 +02:00
nevaforget 33bb0a2576 feat(quickshell): add bar pilot (parallel to Waybar, not deployed)
Exploratory step toward consolidating the shell stack onto quickshell/QML
— one toolkit and one Catppuccin theme instead of Waybar plus separate
daemons. Runs manually via `quickshell -p`, alongside the still-deployed
Waybar; deliberately kept out of the deploy path (not niri-spawned, not
packaged, not in the package lists) until daily-drive acceptance.

Includes: Catppuccin Theme singleton, Niri IPC service, shared popout
framework, bar widgets (clock, workspaces, window title, tray drill-down,
network/bluetooth/audio/battery incl. conservation toggle, idle inhibitor),
themed tooltips, and a NotificationServer-based daemon (toasts + center +
DND + IPC). The notification daemon cannot coexist with swaync (single bus
owner), so swaync stays the deployed daemon; quickshell's is opt-in.

Rationale and tradeoffs recorded in DECISIONS.md.
2026-07-04 23:32:55 +02:00
nevaforget d101b23351 docs: translate CLAUDE.md to English
Update PKGBUILD version / update-pkgver (push) Successful in 5s
Per the committed=English rule. Also documents the windowed-video idle-inhibit added in the same series.
2026-06-16 10:46:05 +02:00
nevaforget e6b7f53794 feat: keep windowed browser video awake via wayland-pipewire-idle-inhibit
stasis ignores browser audio (pactl, browser-excluded), so windowed/muted browser video let the screen sleep. Add wayland-pipewire-idle-inhibit (AUR + user service) holding a Wayland idle-inhibitor while audio plays. Enabled on fresh installs and checked by moonarch-doctor.
2026-06-16 10:46:05 +02:00
nevaforget 806841d435 feat(portal): keep windowed browser video from sleeping the screen
Update PKGBUILD version / update-pkgver (push) Successful in 3s
Add /etc/xdg-desktop-portal/niri-portals.conf with Inhibit=none. The gtk
portal reports Inhibit success even though nothing implements it under Niri,
so Firefox/Waterfox skips the native Wayland idle-inhibit. With no backend the
browser falls back to zwp_idle_inhibit, which Niri honors.
2026-06-12 11:10:00 +02:00
nevaforget f9f73db10f docs(stasis): correct monitor_media comment to match real behavior
monitor_media detects media via pactl sink-inputs and excludes browser
audio by design; it does not catch windowed browser video. ignore_remote_media
only affects remote players (Spotify-remote, Chromecast).
2026-06-12 11:10:00 +02:00
nevaforget dbc2997de0 fix(fonts): repair Waybar font and add system-wide fontconfig defaults
Update PKGBUILD version / update-pkgver (push) Successful in 3s
Nerd Fonts renamed "Ubuntu" -> "UbuntuSans"; Waybar's dead family name token-matched to Hack. Correct the explicit name and ship owned conf.d defaults mapping the generic families to the moonarch fonts.

- waybar/style.css: "Ubuntu Nerd Font" -> "UbuntuSans Nerd Font"
- conf.d/65-moonarch-fonts.conf: sans-serif/monospace, binding="strong" (weak prefer ranks behind the generic fallback)
- document fontconfig defaults in CLAUDE.md and DECISIONS.md
2026-06-08 13:39:25 +02:00
nevaforget dc47d1a6ec fix(nightlight): default OFF, drop wlsunset from auto-enable list
Coordinated fix with moonarch-pkgbuilds: post-install.sh enabled
wlsunset by default, while the PKGBUILD shipped a global-scope
WantedBy symlink. Together that made the toggle's user-scope disable
a no-op — filter persisted across reboots regardless of user intent.

Removing wlsunset from USER_SERVICES makes "off" the install default;
the toggle now works in user scope only, where disable can take effect.
2026-05-04 14:15:58 +02:00
nevaforget 952776c4f9 batsaver: switch to pkexec helper, drop broken udev permission hack
Update PKGBUILD version / update-pkgver (push) Successful in 2s
The wheel-write-via-udev approach for charge_control_end_threshold has
been broken since 2026-04-08: the audit-remediation commit added
ACTION=="add" to the rule, but the threshold attribute doesn't exist
yet at the add event on Lenovo, so chmod fails silently and permissions
are never set. moonarch-batsaver-toggle has been returning Permission
denied since.

Replace the udev-rule approach with a pkexec helper:

  defaults/bin/moonarch-batsaver-apply    privileged: validate + write
  defaults/bin/moonarch-batsaver-toggle   user: read sysfs, dispatch via pkexec
  defaults/bin/moonarch-batsaver-restore  boot-time root restore (extracted
                                          from inline ExecStart for clarity)

Default Standard-pkexec prompt — password cached per session for the
~5min auth window; no polkit no-password rule, no privilege escalation
surface from misvalidated input. Same pattern Battery-Health-Charging
GNOME extension uses.

The boot-time restore service now skips the kernel write when the
sysfs value already matches the saved state (Lenovo drivers reject
same-value writes with EINVAL).

DECISIONS.md documents the failure analysis and trade-offs.
CLAUDE.md updated to describe the new flow.
moonarch-doctor: udev-effectiveness check removed.
2026-05-04 12:17:31 +02:00
nevaforget f4d60d387e ci(update-pkgver): only trigger on package-relevant paths
Update PKGBUILD version / update-pkgver (push) Successful in 5s
Workflow had no path filter — every push to main fired the pkgver-bump
which in turn triggered the heavy build-and-publish pipeline in
moonarch-pkgbuilds, even for changes that the moonarch-git PKGBUILD
does not package: README/DECISIONS edits, post-install.sh, lib.sh,
or workflow tweaks themselves.

Restrict the trigger to defaults/, packages/, and the two scripts
that PKGBUILD actually installs (moonarch-update, moonarch-doctor).
Comment lists explicitly what the filter excludes so the next reader
doesn't have to reverse-engineer it.
2026-05-04 11:14:09 +02:00
nevaforget 1e8b0d4ab0 cleanup: remove invented zsh override layer, harden moondoc
Earlier ClaudeCode sessions had wired a `~/.zshrc.d/*.zsh` snippet loop
plus a `~/.zshrc.local` fallback into defaults/shell/zshrc and made
post-install.sh create the directory unconditionally — neither is a zsh
convention nor documented anywhere. Remove both, simplify post-install
to write only `source /etc/zsh/zshrc.moonarch`, drop stale rustup
next-step hint, drop dead `confirm()` in lib.sh (orphan since
transform.sh deletion 2026-04-21).

moonarch-doctor: replace useless existence checks (zshrc.moonarch,
/usr/share/moonarch/) with real signal. User-service and helper-script
lists now derive from `pacman -Qql moonarch-git` (drift-proof) plus an
explicit list of post-install-enabled externals (currently `stasis`).
New udev-effectiveness check for charge_control_end_threshold —
verifies group=wheel + group-writable, surfaces broken rules instead
of staying silent.

Translate two German ABOUTME comments (moonarch-waybar-cpugov,
moonarch-waybar-gpustat) to English for consistency.
2026-05-04 11:09:45 +02:00
nevaforget 7b6ba3b0d1 fix(vpn): use 'id' keyword instead of '--' in nmcli connection up/down
Update PKGBUILD version / update-pkgver (push) Successful in 2s
Newer nmcli no longer parses '--' as end-of-options for 'connection up',
it treats it as the connection name and fails with "Unbekannte
Verbindung »--«". The 'id' keyword is the canonical way to mark the
following argument as the connection name.
2026-04-24 20:41:08 +02:00
nevaforget aef7f64b59 refactor(mpv): move ModernZ overrides into mpv.conf via script-opts-append
Update PKGBUILD version / update-pkgver (push) Successful in 2s
- drop defaults/etc/mpv/script-opts/modernz.conf (deploy timing conflict
  with mpv-modernz-git)
- put all ModernZ tweaks in mpv.conf: Catppuccin Lavender accent, scale
  0.75, title font 18, ontop_button off, autofit-larger 80%
- quote hex values to survive mpv's mid-line # comment parsing
- niri window-rule opens mpv floating
- doctor no longer compares mpv configs (now directly owned by pkg)
2026-04-24 17:52:12 +02:00
nevaforget 0064170430 feat: add mpv with ModernZ OSC as default video player
Update PKGBUILD version / update-pkgver (push) Successful in 3s
- mpv-modernz-git + mpv-thumbfast-git in aur.txt
- /etc/mpv/mpv.conf disables stock OSC + title bar
- /etc/mpv/script-opts/modernz.conf overrides colors to Catppuccin Mocha (lavender accent)
- moonarch-doctor checks deployed mpv configs
2026-04-24 17:32:05 +02:00
nevaforget 39094ee026 fix(stasis): flip ignore_remote_media so browser video inhibits idle
Browsers only raise org.freedesktop.ScreenSaver.Inhibit during fullscreen
playback; a windowed YouTube tab sent no inhibit, so stasis ran the full
idle plan to suspend despite active video. Letting browser MPRIS count
as a media player closes the gap without the wake-lock hacks.

See DECISIONS.md (2026-04-24).
2026-04-24 14:40:30 +02:00
nevaforget d5c1b8a155 fix: audit LOW fixes — nmcli guards, sink cancel, cpugov stderr, gpu interval
Update PKGBUILD version / update-pkgver (push) Successful in 2s
- moonarch-vpn: add `--` argument-terminator to `nmcli connection up/down`
  so a profile name starting with `-` is never interpreted as a flag.
- moonarch-sink-switcher: guard against empty `$sink` when walker is
  cancelled, since awk masks walker's non-zero exit. Prevents the error
  `pactl set-default-sink ""` on every dismissal.
- moonarch-waybar-cpugov: redirect stderr so non-cpufreq systems (VMs,
  some desktops) do not spam the journal on every 60s poll.
- waybar config: switch custom/gpu-usage from `restart-interval: 10` to
  `interval: 60`. The module lives in a closed drawer, a 10 s poll spawn
  was unnecessary background noise.
2026-04-24 13:59:20 +02:00
nevaforget 8aaf7cae5b fix: audit MEDIUM fixes — merge fallback, service hardening, CI token
- moonarch-waybar: on merge failure, remove the stale output so waybar
  falls back to the system config (previously it kept running with stale
  merged data despite the error notification claiming otherwise).
- moonarch-doctor: hoist INSTALLED assignment above both OFFICIAL and AUR
  blocks so the script survives set -u when only aur.txt is present.
- zshrc parse_git_branch: gate on git rev-parse and replace three grep
  subshells with bash pattern matching, cutting prompt latency from
  ~5 subprocesses per render to 2 (status + symbolic-ref).
- moonarch-batsaver.service: validate the threshold is an integer 1-100
  before writing to sysfs, add NoNewPrivileges and protection directives
  instead of relying on kernel validation alone.
- ci/act-runner/Dockerfile: drop the broad "pacman -Sy *" sudoers entry
  (only -S --needed is required by makepkg), and pin run.sh to
  act_runner:0.3.1 so it cannot drift ahead of the pinned binary.
- .gitea/workflows/update-pkgver.yaml: push via credential.helper=store
  with a chmod 600 temp file instead of `git -c http.extraHeader=...`,
  so the token no longer shows up in /proc/PID/cmdline.
2026-04-24 13:15:52 +02:00
nevaforget 89c3a9261e feat: add cursor-theme to GTK4 defaults for greeter
Update PKGBUILD version / update-pkgver (push) Successful in 3s
GTK3 defaults already had gtk-cursor-theme-name + size; GTK4 did not. Moongreet (GTK4) under greetd therefore fell back to the default cursor even with XCURSOR_THEME set on cage. Add the two lines so GTK4 apps pick up Sweet-cursors from system defaults before any window is created.
2026-04-24 10:53:26 +02:00
nevaforget e4ea267b6b feat: set cursor theme in moongreet config for greeter
Update PKGBUILD version / update-pkgver (push) Successful in 3s
Moongreet v0.9.0 reads cursor-theme/cursor-size from its TOML config
because GTK4 under greetd does not honour XCURSOR_THEME. Ship the
Sweet-cursors setting here so the greeter renders the intended cursor
on a fresh install without needing the env-prefix hack in greetd.
2026-04-24 08:57:28 +02:00
nevaforget 8485a63ab7 fix(moonup): read prompts from /dev/tty, robust GUI pause
Update PKGBUILD version / update-pkgver (push) Successful in 3s
Pacman/paru can drain or close stdin, so after the first interactive step
the EXIT trap's pause was silently skipped (the `-t 0` check failed) and
every subsequent confirm() prompt hit EOF — which with `[[ -z $response ]]`
auto-accepted, letting install/remove actions run unattended.

- _pause_on_exit: drop the `-t 0` guard and read from /dev/tty
- confirm(): read from /dev/tty so EOF on stdin can't masquerade as "yes"
- Move the trap installation above the gettext i18n init so an early
  failure (e.g. missing gettext) still triggers the pause message.
2026-04-23 08:08:52 +02:00
nevaforget 6e14258ad9 fix(doctor): drop obsolete paru repo check, cover walker + nautilus
Update PKGBUILD version / update-pkgver (push) Successful in 3s
The `[moonarch-pkgbuilds]` paru-repo check was a false failure: that
mechanism was retired on 2026-04-20 and the install hook strips the
legacy paru.conf section on upgrade.

Audit of the rest of the doctor surfaced two related gaps — the
user-services loop skipped `walker.service` and `nautilus.service`,
even though moonarch-git ships both and enables them via
graphical-session.target.wants. Added them to the loop and filled in
the missing `wlsunset` in the CLAUDE.md listing.
2026-04-22 08:56:23 +02:00
nevaforget 9432bc4831 fix(post-install): seed stasis config into user home
Stasis ignores /etc/xdg/ and only reads ~/.config/stasis/stasis.rune
(primary) or /etc/stasis/stasis.rune (fallback). On first start with no
user config it writes its own hardcoded default, so Moonarch's tuned
idle plans were never active on fresh installs.

Seed the template from /etc/xdg/stasis/stasis.rune into the user home
before stasis ever starts, only if the user file is missing. See
DECISIONS.md for verification against upstream v1.1.0.
2026-04-22 08:49:04 +02:00
nevaforget 373bfd4a9b fix(moonup): keep terminal open on errors via EXIT trap
The previous end-of-script `read` never ran when `set -e` aborted mid-way
(pacman conflict, paru failure, Ctrl+C), so foot closed on errors —
exactly when the user most needs to see the output.

Move the pause into a trap on EXIT, gated by `MOONUP_WAIT=1` so CLI use
stays non-interactive. Waybar on-click now sets the env var.
2026-04-22 08:23:25 +02:00
nevaforget c2cee85488 chore: drop moongreet polkit rule, now shipped by moongreet-git
Update PKGBUILD version / update-pkgver (push) Successful in 3s
The rule was never installed by any PKGBUILD from this repo anyway.
Moved to moongreet/config/polkit/ in v0.8.3 where it belongs — moonarch
should not own greeter-specific auth rules.
2026-04-21 09:12:11 +02:00
nevaforget 971a6eb577 refactor(install): restore fresh-install flow, drop transform.sh and personas
Long-standing gaps in post-install.sh plus cleanup:

- post-install.sh:18 was `sudo pacman -S paru` on the wrong
  assumption paru had landed in [extra]. Verified: paru/paru-bin
  are AUR-only. Restored the original git-clone + makepkg
  bootstrap, added the rust buildep that archinstall does not
  pull in.
- post-install.sh never installed AUR extras — walker, elephant,
  waypaper, stasis, themes all silently skipped. Now pulls
  packages/aur.txt after moonarch-git.
- packages/official.txt: drop glab, go, npm (unused) and rustup
  (only needed for the paru build, handled imperatively now).
- packages/aur.txt: add walker-bin (was missing entirely).
- transform.sh + legacy update.sh shim removed — transform was
  never used in practice.
- Apollo persona block out of CLAUDE.md, prior DECISIONS entries
  rewritten from Apollo/Ragnar to ClaudeCode.
- README Transform section and scripts/ listing trimmed.
- lib.sh ABOUTME updated — only post-install.sh sources it now.
2026-04-21 09:04:23 +02:00
nevaforget 0a38347cb9 feat(install): registry-only path, drop paru --pkgbuilds from setup
Update PKGBUILD version / update-pkgver (push) Successful in 2s
post-install.sh and transform.sh no longer write paru.conf entries for
the PKGBUILD repo — the Arch registry is the single source of truth.
pacman -Sy + paru -S moonarch-git now suffices. See DECISIONS.md.
2026-04-20 14:20:02 +02:00
nevaforget f4f6ede2a7 feat: i18n moonarch-update via pacman gettext + inline DE
Update PKGBUILD version / update-pkgver (push) Successful in 2s
Prompts and log lines now follow the user's LANG. Reuses pacman's
gettext catalog for strings with matching upstream msgids
(Proceed with installation?, [Y/n], Starting full system upgrade...,
Do you want to remove these packages?). Moonarch-specific strings
go through an inline _t "en" "de" helper keyed off ${LANG%%.*}.

confirm() switches to pacman-style: :: prefix, default Y, accepts
y/Y/j/J. No PKGBUILD change — gettext ships with base.
2026-04-19 15:47:28 +02:00
nevaforget ee85b87d3a fix: signal waybar after wlsunset starts to update nightlight icon
Waybar starts before wlsunset (due to ExecStartPre sleep) and only
checks the service status once. ExecStartPost sends SIGRTMIN+11 so
waybar refreshes the nightlight module after wlsunset is ready.
2026-04-16 10:36:05 +02:00
nevaforget fcac91b540 fix: add polkit rule to allow greeter user to reboot and shutdown
The greetd greeter session is inactive in logind, so polkit defaults
require admin authentication for power actions. This rule grants the
greeter user permission for reboot and power-off without authentication.
2026-04-15 14:23:49 +02:00
nevaforget 324dda0548 fix: remove fixed notification popup height to prevent scrollbar
Update PKGBUILD version / update-pkgver (push) Successful in 3s
notification-window-height was set to 150px, causing long notifications
to be clipped with a scrollbar. Set to -1 (compositor-managed) so popups
adapt to content height.
2026-04-15 14:08:53 +02:00
nevaforget 0433f08f08 feat: manage wlsunset via systemd user service
Update PKGBUILD version / update-pkgver (push) Successful in 4s
Move nightlight from niri spawn-at-startup to a systemd user service
with After=kanshi.service to ensure all outputs are configured before
wlsunset starts. Toggle now uses enable/disable --now for persistent
state across reboots.
2026-04-14 17:42:24 +02:00
nevaforget 9bc753e092 fix: use niri include instead of copying system config to user dir
Update PKGBUILD version / update-pkgver (push) Successful in 2s
transform.sh was hard-copying /etc/xdg/niri/config.kdl to ~/.config/niri/,
causing the user config to go stale after system updates. Now seeds a minimal
user config with `include "/etc/xdg/niri/config.kdl"` so system defaults
always stay current and users can add overrides below the include.
2026-04-11 21:03:42 +02:00
nevaforget a360d12bde fix: reduce swaync notification size and cap popup height
Update PKGBUILD version / update-pkgver (push) Successful in 3s
Smaller font (14px → 12px), smaller icon (64px → 36px via CSS variable),
and notification-window-height limit (150px) to prevent oversized popups
from long notification bodies.
2026-04-10 16:15:48 +02:00
nevaforget 97e4b81930 docs: add moonarch-doctor and shorthand aliases to README and CLAUDE.md
Update PKGBUILD version / update-pkgver (push) Failing after 3s
2026-04-10 08:21:38 +02:00
nevaforget b8753bf84f fix: remove docker from defaults, fix cliphist-image ordering cycle
Docker is a dev dependency, not a desktop environment default. Remove
from package list, archinstall config, services and README.

Fix systemd ordering cycle that prevented cliphist-image from starting:
cliphist-text had After=graphical-session.target which combined with
PartOf= and cliphist-image's After=cliphist-text created a cycle.
2026-04-10 08:18:55 +02:00
nevaforget a55c7ea9d1 feat: add moonarch-doctor system health checker
Diagnostic script that verifies services, configs, packages and paths
against the expected moonarch system state. Reports pass/fail/warn with
colored output and summary. Deployed as moonarch-doctor (alias: moondoc).
2026-04-10 08:18:45 +02:00
nevaforget ab066724f0 fix: keep terminal open after moonarch-update completes
Update PKGBUILD version / update-pkgver (push) Successful in 3s
Add "press any key" prompt when running interactively (stdin is a TTY).
Remove dead wrapper in defaults/bin/ that was overwritten by PKGBUILD.
2026-04-10 07:33:46 +02:00
nevaforget 2363e76b4a feat: add moonarch-waybar config merger wrapper
Update PKGBUILD version / update-pkgver (push) Successful in 4s
Waybar's include directive cannot merge arrays, making per-machine
module customization impossible without duplicating the entire config.

moonarch-waybar merges an optional ~/.config/waybar/userconfig with
the system config, supporting prepend/append on module arrays and
object merge for module definitions. Generates user style.css with
@import of system styles on first run.

System waybar config converted from JSONC to valid JSON for jq
compatibility. Niri startup and hotkey updated to use the wrapper.
2026-04-09 17:04:24 +02:00
nevaforget 4dd8aae2f0 fix: change drawer transition direction for sound and brightness groups
Update PKGBUILD version / update-pkgver (push) Successful in 2s
Open drawers to the right instead of left, matching their position
on the right side of the bar.
2026-04-09 12:15:59 +02:00
nevaforget 47ae8d5d51 docs: add wlsunset nightlight to README
Update PKGBUILD version / update-pkgver (push) Successful in 2s
Add nightlight scripts to project structure, wlsunset to startup
sequence diagram, and Night Light entry to component choice table.
2026-04-09 12:10:05 +02:00
nevaforget 4c609135e9 feat: add wlsunset nightlight toggle with Waybar module
Update PKGBUILD version / update-pkgver (push) Successful in 3s
Add blue light filter support via wlsunset, toggleable through a Waybar
module in the brightness group. Nightlight icon is the primary element,
backlight slider expands on click.

- Add wlsunset package to official.txt
- Add moonarch-nightlight toggle script (kill/restart wlsunset)
- Add moonarch-waybar-nightlight status script (JSON output)
- Add custom/nightlight module to group/brightness in Waybar config
- Add Catppuccin Yellow highlight for active nightlight state
- Add wlsunset autostart in Niri config (5000K night temperature)
2026-04-09 12:08:35 +02:00
nevaforget f6869c9cea fix: detect implicitly installed packages in moonarch-update
Update PKGBUILD version / update-pkgver (push) Successful in 3s
Use pacman -Qq (all installed) instead of -Qqe (explicit only) so
packages installed as dependencies are not falsely reported as missing.
2026-04-09 11:47:51 +02:00
nevaforget 48b0de071e feat: add brightness slider to Waybar backlight module
Update PKGBUILD version / update-pkgver (push) Successful in 2s
Wrap backlight in a drawer group with backlight/slider, mirroring the
existing sound group pattern. Slider appears on hover/click.
2026-04-09 11:43:36 +02:00
nevaforget b6beabe500 feat: add moonarch-update wrapper for interactive system updates
Update PKGBUILD version / update-pkgver (push) Successful in 2s
Wraps paru in a script that waits for keypress after completion,
preventing foot from closing immediately. Used as Waybar on-click
action for the updates module.
2026-04-09 11:34:11 +02:00
nevaforget 8ddbb23851 feat: add waybar module for package update notifications
Update PKGBUILD version / update-pkgver (push) Successful in 3s
Add moonarch-waybar-updates script that checks for available updates
from both official repos (checkupdates) and AUR (paru -Qua). Uses a
cache mechanism to avoid excessive mirror hits while still detecting
freshly installed updates within 60 seconds.
2026-04-09 10:54:49 +02:00
nevaforget 46ba8365db feat: style taskbar active state with bottom border indicator
Add a visible bottom border to the active taskbar button for clear
focus indication. Reserve border space on all buttons with a transparent
border to prevent icon shifting on state changes.
2026-04-09 06:35:57 +02:00
nevaforget d815e21b1d feat: prepare CSS to hide empty battery group (Waybar PR #4941)
Update PKGBUILD version / update-pkgver (push) Successful in 3s
2026-04-08 17:01:19 +02:00
nevaforget 6d3a7c8d72 feat: enable always-center-single-column in niri layout
Update PKGBUILD version / update-pkgver (push) Successful in 2s
2026-04-08 14:10:26 +02:00
nevaforget ac2b210a1f fix: audit remediation — security, quality and performance fixes
Update PKGBUILD version / update-pkgver (push) Successful in 3s
- CI Dockerfile: verify act_runner SHA256, restrict sudoers to safe
  pacman arguments (S-C1, S-C2)
- cliphist: split into cliphist-text + cliphist-image services with
  Type=simple for proper PID tracking and restart (Q-C3)
- batsaver-toggle: validate sysfs input as numeric, check state file
  write (Q-C2, S-W2)
- udev battery rule: add ACTION=="add" filter to avoid firing on
  every battery event (Q-W3)
- cpugov: replace eval with direct expansion, switch waybar module
  to signal-based updates, send SIGRTMIN+10 after toggle (Q-W1,
  S-W1, P-W4)
- Remove docker group auto-assignment from install scripts (S-I1)
2026-04-08 11:45:56 +02:00
nevaforget e1e80ca414 fix: rename battery group to avoid CSS ID conflict, clean up waybar styles
Update PKGBUILD version / update-pkgver (push) Successful in 3s
group/battery shared its CSS ID (#battery) with the battery module,
causing padding overrides to affect the group box instead of just the
module. Renamed to group/bat. Moved cpugov into indicators group.
Reorganized style.css sections for clarity.
2026-04-08 10:45:34 +02:00
nevaforget 579a948449 feat: add battery conservation mode with Waybar toggle
Update PKGBUILD version / update-pkgver (push) Successful in 2s
Laptops with charge_control_end_threshold support get a click-to-toggle
on the battery module (80% ↔ 100%). A ♥ icon appears when conservation
is active, hidden when inactive. State persists across reboots via
systemd oneshot service. udev rule grants wheel group write access
so no sudo is needed for toggling.
2026-04-08 09:55:46 +02:00
nevaforget 6a258151fa fix: show bluetooth icon instead of status text in Waybar
Update PKGBUILD version / update-pkgver (push) Successful in 2s
The bluetooth module displayed " {status}" (icon + text like
"on"/"off") which was inconsistent with other icon-only modules.
2026-04-07 17:28:15 +02:00
nevaforget 037d311607 refactor: clean up Waybar styles, remove user-defaults mechanism
- Remove defaults/user/ and the user-defaults copy loop from
  post-install.sh and transform.sh — Waybar falls back to
  /etc/xdg/waybar/ via XDG spec, no provisioning needed.
- Remove USER_DEFAULTS constant from lib.sh.
- Clean up style.css: remove dead selectors (#net, #cava,
  #custom-updates, #custom-notification), commented-out blocks,
  empty rules, duplicate properties, and hardcoded hex color.
- Restructure module styling: generic top-level box via
  > widget > *, group children reset via widget widget > *,
  explicit exceptions for workspaces/taskbar/window.
- Normalize section comments and whitespace.
- Update README to remove user/waybar/ from project structure.
2026-04-07 17:27:47 +02:00
nevaforget 2b8e40f37f docs: update README and DECISIONS for Walker moonarch theme
Update PKGBUILD version / update-pkgver (push) Successful in 3s
2026-04-07 13:13:44 +02:00
nevaforget ef8ff7099f feat: rename Walker theme to moonarch, add explicit Catppuccin colors
Rename gtk-inherit theme to moonarch with fixed Colloid-Grey-Dark-
Catppuccin color definitions. Reduces border brightness and shadow
weight for a subtler appearance.

Closes #3
2026-04-07 13:11:06 +02:00
nevaforget 7a2b1ece05 docs: update README and DECISIONS for archinstall v4 and kanshi fixes 2026-04-07 12:24:07 +02:00
nevaforget 62495d8e3d fix: prevent kanshi config from breaking wdisplays-persistent
Update PKGBUILD version / update-pkgver (push) Successful in 3s
Remove ABOUTME comments from kanshi default config — they broke
the profile parser in wdisplays-persistent store.c, preventing
config saves. Also skip kanshi in transform.sh when user profiles
already exist, since display layouts are machine-specific.
2026-04-07 12:23:06 +02:00
nevaforget 76f5602b47 Migrate archinstall config to v4 format
archinstall v4.1 introduced new canonical key names. Update
user_configuration.json to the current schema:
- audio_config → nested under app_config
- bootloader → bootloader_config with explicit uki flag
- gfx_driver value updated to "All open-source (default)"
- custom-commands → custom_commands (underscore)
2026-04-07 11:56:01 +02:00
nevaforget 466ba773dc docs: fix remaining stale references in README and CLAUDE.md
Update PKGBUILD version / update-pkgver (push) Successful in 2s
- scripts/: replace update.sh with moonarch-update, fix description
- Update section: remove stale "syncs repo, deploys XDG" claim
- User services: add stasis to table
- CLAUDE.md: mention systemd user services in defaults/ description
2026-04-07 11:37:44 +02:00
nevaforget 9f994d03fb docs: update README for swaync, cliphist service, /usr/bin paths
Update PKGBUILD version / update-pkgver (push) Successful in 2s
- dunst → swaync throughout
- Clipboard section: cliphist + Walker, wiped on session start
- Helper scripts: /usr/local/bin → /usr/bin (package-managed)
- User services: moved to /etc/systemd/user/, added cliphist/nautilus
- Startup diagram: swaync, nm-applet, systemd services listed
- moonarch-dnd removed (dunst-specific)
2026-04-07 11:34:30 +02:00
nevaforget 80c395fc14 feat: add cliphist service, move user services to /etc/systemd/user/
Update PKGBUILD version / update-pkgver (push) Successful in 2s
- Add cliphist.service that wipes clipboard history on session start
  (crash-safe: cleans up at next boot, not at shutdown)
- Move kanshi, walker, nautilus services from ~/.config/systemd/user/
  to /etc/systemd/user/ (system-level defaults, consistent with
  moonarch's config philosophy)
- Remove cliphist spawn-sh-at-startup from niri config (managed by
  systemd service now)
- Add cliphist to USER_SERVICES in post-install.sh and transform.sh

Closes #1
2026-04-07 11:27:49 +02:00
nevaforget 25baf88a2a fix: move paru repo config into moonarch.install to break bootstrap loop
Update PKGBUILD version / update-pkgver (push) Successful in 3s
The paru PKGBUILD repo config was only set up by post-install.sh and
transform.sh. If the config was missing on an existing system,
moonarch-git couldn't update — the fix required the package that
delivers the fix.

Now moonarch.install sets up the config on every install/upgrade.
post-install.sh keeps it for first-time bootstrap (before moonarch-git
exists). transform.sh no longer manages it.
2026-04-07 11:11:58 +02:00
nevaforget 29550b8a14 fix: audit remediation — 6 fixes across quality, performance, security
Update PKGBUILD version / update-pkgver (push) Successful in 2s
Q-01: Fix broken upower regex in moonarch-btnote (lookaheads never matched)
Q-02: Fix transform.sh paru repo section name ([moonarch] → [moonarch-pkgbuilds]),
      config path (~/.config → /etc), and partial sync (-Sy → -Syu)
Q-03: Add missing stasis package to aur.txt (idle management broken on fresh install)
S-01: Switch CI git clones from HTTP to HTTPS (MITM risk in Docker network)
S-02: Restrict CI builder sudo to /usr/bin/pacman only
P-01: Refactor moonarch-waybar-gpustat — remove while loop, use jq --arg style
2026-04-07 10:50:57 +02:00
nevaforget 27247a4ffb fix: remove duplicate VPN notifications from moonarch-vpn
Update PKGBUILD version / update-pkgver (push) Successful in 2s
nm-applet already sends notifications for VPN state changes.
The script's own notify-send calls caused duplicates on every toggle.

Closes #4
2026-04-07 10:19:41 +02:00
nevaforget fdedc8071f Add nautilus preload service for faster file manager startup
Update PKGBUILD version / update-pkgver (push) Successful in 2s
xdg-open ~ (Super+E) cold-starts Nautilus every time, causing
noticeable delay. A GApplication service keeps Nautilus warm in the
background so subsequent opens are near-instant. Follows the same
pattern as the existing walker.service.

Closes #2
2026-04-07 09:03:18 +02:00