4.0.0.alpha-cn.1
2260
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4ab51df2b0 |
Require a factory snapshot to reset a computer (#6680)
Machines without @factory fell back to a degraded reset that kept the current system and only wiped user state. Turn them away with an explanation instead, and drop the degraded staging path. The first-boot worker still honors a wipe-degraded marker so a reset staged by an older version finishes its scrub rather than handing the machine over with the seller's accounts intact. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
9f13bfc157 |
Center the timezone picker in first-boot setup
The timezone prompt falls back to `gum filter` when tzupdate can't guess a zone, which is the common case on a first boot with no network yet. That was the one widget in the form without a GUM_*_PADDING export, so it drew flush left while every other step sat centered under the logo. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
2d44ad59be |
End deferred first boot on the finished progress bar
Clearing it for a "Starting Omarchy..." card only flashed another screen before SDDM took over. The cursor now stays hidden through the handoff and comes back only on the failure path, where the retry prompt needs it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
354c2f0060 |
Wait for the terminal resize before the first screensaver effect
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
4cc14933a4 | Use sudo for terminal update inhibition | ||
|
|
f228c4d390 |
Stop checking for commands the package set guarantees
gum and ttfx ship in omarchy-base.packages and setfont comes with kbd, so none of them needs a presence check — and every setfont call already tolerates a failure anyway. btrfs-progs is in omarchy-other.packages and a reset genuinely cannot proceed without it, so that one keeps its guard and moves to the helper. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
4e31b61af0 |
Swap terminaltexteffects for ttfx (#6670)
* Swap terminaltexteffects for ttfx ttfx is a Rust port of terminaltexteffects that renders byte-identical frames as a single dependency-free binary. Same option names, defaults, and exit codes, so every invocation here is unchanged apart from the command name. The screensaver runs at --frame-rate 120 with --random-effect. On a fullscreen canvas Python cannot hold that for the heavier effects (beams: 14.1 ms/frame against an 8.3 ms budget, so ~71fps); ttfx renders the same effect at 564fps. Startup drops from ~107 ms to ~1 ms, and the base image no longer needs Python for the screensaver. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Need a migration --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
7644b56d4e |
Extract the setup form shared with the ISO installer (#6669)
The keyboard layout list, the account and hostname validation rules, and the gum prompts that ask for them all existed twice: once in the ISO configurator's user step, once in first-boot owner setup. Nothing kept the copies honest, and they had already drifted — a layout removed on one side moved English (US) onto a page boundary on the other, burying the default at the bottom of a screen of layouts. install/provisioning/setup-form.sh is now the only copy. The PKGBUILD's existing `cp -a install` ships it to /usr/share/omarchy/install/provisioning/, and the ISO build vendors that very file out of the runtime package it bundles, so an install and the first boot that finishes it cannot offer different layouts or accept different usernames. Cancel handling is unified along the way, which is what made the prompts shareable at all. Every prompt reports 0 (answered), 1 (Esc — unwind to the start of the form), or 130 (Ctrl+C — a side channel each caller defines). Previously Esc and Ctrl+C were indistinguishable here: both re-asked the same field, so there was no way back to an earlier answer. Ctrl+C now offers a confirmed reboot instead. It cannot be a SIGINT trap — gum reads Ctrl+C as a byte in raw mode, so the shell never receives the signal — so it hangs off the exit status. Status capture is written as `x=$(gum ...) && status=0 || status=$?` because this script runs under `set -e`, where a cancelled prompt is a failing assignment that would kill setup before the status could be read. English (US) also leads the layout list now, ahead of the other English variants. gum choose paginates in --height-sized pages and jumps to the page holding --selected, so an alphabetical default landed wherever the list length happened to put it. Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
0a8359072c |
Show install-style progress through first-boot account setup (#6631)
* Add OEM first-boot setup and factory reset An OEM-mode ISO install (or omarchy-reset-computer) leaves the machine in OEM state: fully installed, no user, /var/lib/omarchy/oem/pending armed. On the next boot omarchy-oem-setup.service runs the configurator's user form on tty1, creates the user with the groups system setup recorded, finalizes it offline from the stashed Node tarball, re-keys LUKS from the throwaway install passphrase to the user's password, and hands off to SDDM. omarchy-reset-computer returns a machine to that state: it swaps the running root for a fresh clone of the @factory snapshot the ISO takes at install time, scrubs machine identity and prior users, and stages omarchy-factory-wipe to drop the old root and recreate @home/@log on the next boot. Machines installed before @factory existed get a degraded reset (current system kept, users and state wiped) with that caveat surfaced in the confirmation. omarchy-setup-system/-hardware gain --oem to run without an install user; the group-granting install scripts now record their groups in /var/lib/omarchy/oem/groups and only call usermod when the user exists. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Harden OEM setup: correct cryptsetup key-file usage, retry on failure cryptsetup reads --test-passphrase/--key-file inputs byte-for-byte, so feed passphrases through process substitution consistently instead of positional args or stdin (which has different newline semantics). Run each first-boot setup attempt as its own process so a failure offers a retry instead of stranding the machine at a user-less login screen — bash ignores errexit inside `while !` conditions, a child process does not. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Always grant wheel sudo in OEM first-boot setup Detecting an existing %wheel grant by grepping sudoers is error-prone: omarchy ships narrow '%wheel ALL=(ALL) NOPASSWD: <command>' rules (e.g. asdcontrol) that match the naive pattern, which left the OEM-created user matching sudoers entries but unable to run anything. Write the drop-in unconditionally — a duplicate of an existing full grant is harmless. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Fix LUKS re-key device resolution and OEM state readability archinstall's encrypted installs put cryptdevice=PARTUUID=... on the kernel cmdline, not UUID=, so the first-boot re-key never found its device and silently skipped — leaving the throwaway auto-unlock keyfile in place, i.e. the disk effectively unencrypted. Parse every cryptdevice= source spec form and make any re-key failure abort the attempt loudly: a retry prompt beats a machine that quietly boots without a passphrase forever. The OEM state directory also has to be world-readable (its one secret, luks-key, stays 0600): user finalization reads the stashed Node tarball as the new user, and the 0700 directory forced it onto the network fallback. Step markers now land in /var/log/omarchy-oem-setup.log for debuggability. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Purge stale machine-id boot entries when resetting or re-keying limine-entry-tool keys its limine.conf OS entries by machine-id. A factory reset gives the machine a fresh identity, so the previous system's entry survived every rebuild, sorted first, and made Limine stop at a Blake2b hash-mismatch warning once the UKI was rebuilt. Start limine.conf over from the shipped template (and drop foreign machine-id history directories on the ESP) before any post-reset rebuild: in the staged chroot rebuild, in the first-boot LUKS re-key, and — for unencrypted resets, where nothing else rebuilds — in a dedicated first-boot refresh when foreign entries are found. The staged rebuild also verifies every UKI hash referenced by limine.conf against the file on the ESP before the subvolume swap, and the running system's limine-snapper-sync is runtime-masked during staging so it cannot rewrite the config behind the rebuild. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Harden reset and first-boot setup failure paths Review findings from codex and Copilot: - Generate throwaway passphrases without a trailing head stage: under pipefail, SIGPIPE from the infinite tr failed the substitution and errexit aborted every encrypted reset before it could stage anything. - Stage the fallible parts of a degraded reset (LUKS re-key, boot rebuild) before arming the wipe, so a staging failure leaves the machine untouched instead of scheduling a wipe for a reset that never finished. - Gate first-boot setup on the factory wipe having succeeded (ConditionPathExists=!wipe-pending plus an in-script guard): creating the new user on a half-wiped system would hand their data to the wipe retry. - Abort the wipe (keeping its retry marker) when deleting the old root or recreating @home/@log fails, and abort resets that cannot remove a prior account — a surviving account keeps its password and wheel membership. - Resume a partially-created account on setup retry instead of rejecting the username the failed attempt just created. - Only purge machine-id directories the old limine.conf actually referenced; a shared ESP may hold other installations' boot artifacts. - Recreate the hibernation swapfile (nested subvolume, so never captured by the factory snapshot) inside the factory root before its UKI rebuild, so a reset machine keeps disk-backed swap and a valid resume offset. - Source base-test.sh in the OEM groups test per test conventions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Recreate the hibernation swapfile even when resume drop-ins survive omarchy-hibernation-setup short-circuits as 'already set up' when the resume mkinitcpio drop-in exists — which it always does in a factory root, while the swapfile itself never survives the snapshot (nested subvolume). Drop the marker when the swapfile is gone so setup reconfigures from scratch, and verify the swapfile actually exists before proceeding with the reset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Second review pass: encrypted-config coverage, factory-baseline sanitization, recoverable rekey Codex xhigh round 2: - Detect the LUKS backing device by walking the root's device tree, not only the cmdline cryptdevice=; reset/first-boot now re-key roots reached via rd.luks/crypttab too, instead of silently leaving the seller's slots valid. - Sanitize the retained @factory baseline (accounts, /etc/shadow, machine identity) during a full reset: the new wheel user could otherwise mount it to recover the seller's data, and a second reset would restore the account. - Re-key the disk recoverably: rebuild the no-auto-unlock UKI before killing the throwaway slot or destroying the staged key, and restore the keyfile if that rebuild fails, so a retry with a different password can never leave the disk locked to the first attempt's password. - Roll back a degraded reset's live-root auto-unlock material if its boot rebuild fails, instead of leaving it for a later rebuild to embed. - Treat a missing current-machine limine entry as stale so a retry after a failed rebuild repairs the config instead of clearing OEM state over it. - Erase fingerprint enrollments (/var/lib/fprint) in degraded wipes. - Remove the resume-offset drop-in too when recreating the factory swapfile, so the rebuilt UKI gets a correct offset. - Pin first-boot retries to the account the first attempt created. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Expose factory reset in the Setup menu Add a 'Reset Computer' entry under Setup (Omarchy's Settings menu, where OS factory resets conventionally live), guarded to btrfs roots and launched in a floating terminal. omarchy-reset-computer now self-elevates via sudo so the menu entry needs no sudo prefix, forwarding the caller's gum theme env as env arguments so styling survives an env_reset sudoers. The typed 'reset' confirmation and the sudo password prompt remain as the guards against accidental triggering. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Defer keyboard selection to first boot for OEM installs The OEM first-boot setup now runs a keyboard step before the user form, mirroring the ISO configurator: it loads the chosen layout on the live VT so the password (and the LUKS re-key that follows) are typed under it, and persists it with systemd-firstboot so the installed system gets both the console KEYMAP and the XKB layout Hyprland reads — exactly what a normal install writes. Layouts localectl doesn't know keep the default, same as the installer. This lets the OEM operator set nothing user-specific: the machine's owner picks their keyboard alongside their account at first boot. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Rename factory-reset commands to omarchy-system-factory-reset[-finish] omarchy-reset-computer -> omarchy-system-factory-reset omarchy-factory-wipe -> omarchy-system-factory-reset-finish (and its systemd unit, log path, and temp mount to match) Pure rename: every reference — the Setup menu action, the first-boot finish service the reset stages and enables, the oem-setup ordering/gating, comments, and the menu test — moves together, with no behavior change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Rename OEM vocabulary to provisioning (runtime) Commands unify under the provisioning family: omarchy-oem-setup → omarchy-provision-owner omarchy-finalize-user → omarchy-provision-user omarchy-first-run → omarchy-provision-first-run And the deferred-provisioning state/vocabulary replaces 'OEM': /var/lib/omarchy/oem/ → /var/lib/omarchy/provisioning/ /etc/omarchy/oem.key → /etc/omarchy/provisioning.key install/oem/ → install/provisioning/ OMARCHY_SETUP_CONTEXT=oem-firstboot → provision-owner omarchy-setup-system/-hardware --oem → --defer-provisioning All callers (provision-first-run→provision-user, autostart, factory-reset staging the provisioning units, the group-recording scripts) and comments move together. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Drop remaining OEM mentions from the provisioning groups test Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Show install-style progress through first-boot account setup The owner provisioning flow dropped to plain status lines after the confirm form, went dark for the minutes finalize-user takes, and ended with a two-second spinner. Give it the same treatment as the ISO install dashboard: the logo header with a live progress bar and rotating tips while the account is created, finalized, re-keyed, and the boot entries refreshed, then the same tte celebration — ending in a Start Omarchy Now button that hands off to SDDM, since first boot continues into the session rather than rebooting. The bar is the dashboard's engine in miniature: monotonic per-mille position from an asymptotic time floor per phase, with finalize-user's run_logged scripts in the log as the work signal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Match the first-boot console font to the ISO installer The ISO installer runs on a low-resolution pre-KMS console, where the default 8x16 console font looks large. By the time omarchy-provision-owner runs, the installed system has reached full KMS resolution, where that same 8x16 font is physically tiny — so first-boot owner provisioning looked a lot smaller than the installer it continues. Scale the console font up on high-resolution framebuffers so the two read at the same size: latarcyrheb-sun32 (16x32) at >=1600px tall, sun12x22 at >=1150px, and the default left untouched below that (already installer-sized). Both fonts ship with kbd, so there's no new dependency, and it's a no-op off a real VT. Co-Authored-By: Claude <noreply@anthropic.com> * Make first-boot font resolution-adaptive; widen the encrypting band Two fixes to the first-boot provisioning screen surfaced on a real high-resolution display. Font: the earlier fixed thresholds could pick a 16px-wide font on a ~1280px-wide console — 80 columns, one short of the 81-column logo — so the logo wrapped and the layout looked misaligned. Replace the thresholds with a resolution-adaptive choice: pick the kbd font whose row count is closest to the ISO installer's ~48-row feel, but never one wide enough to drop below 90 columns, so the logo can never wrap. Low-resolution consoles land on the default font (a no-op), matching the installer. Progress: the LUKS re-key (a full UKI rebuild, the slowest step of an encrypted first boot) had only an 8%-wide band, so the bar looked stuck near the top while it worked. Make the bands adaptive — when a re-key is pending, finalize yields most of its room to a wide, steadily-moving re-key band; unencrypted installs keep finalize as the dominant step. Co-Authored-By: Claude <noreply@anthropic.com> * Add a Welcome greeter before first-boot setup Deferred-provisioning first boot dropped the new owner straight onto the keyboard picker. Open with a greeter instead — the same frame the setup ends on: static logo, a centered "Welcome to Omarchy", and a single "Start setup" button. No logo animation; it's the starting line, not the celebration. Shown once in main(), before the keyboard step, so retries don't repeat it. Co-Authored-By: Claude <noreply@anthropic.com> * Center the greeter and show the Omarchy tagline Vertically center the greeter block (logo, tagline, button) on the console like the boot logo, and replace "Welcome to Omarchy" with the tagline "Beautiful, Modern & Opinionated Linux by DHH". Co-Authored-By: Claude <noreply@anthropic.com> * Animate the greeter logo with a skippable ColorShift Run a looping tte ColorShift over the centered logo and replace the button with a "Press Return to Start Setup" hint. The effect reads from /dev/null so it never swallows the Return a foreground read waits on, and --reuse-canvas is anchored one row below the logo so it repaints exactly the rows drawn above. Return skips ahead into setup at any time. Co-Authored-By: Claude <noreply@anthropic.com> * Theme the greeter ColorShift to the Omarchy palette Sweep the logo ColorShift through the Tokyo Night accent colors (green, cyan, blue, purple, pink, orange) instead of tte's default rainbow, settling toward the Omarchy green. Co-Authored-By: Claude <noreply@anthropic.com> * Fix greeter ColorShift: green base, no flash, clean handoff - Use indexed ANSI colors (green 2 + cyan 6 accent), since the framebuffer console can't render tte's truecolor and crushed it to a muddy lavender. The result is a green-based shift with a cyan accent, settling on green. - Run one long tte invocation (--cycles 1000) instead of restarting every couple cycles, removing the flash at each loop. - Restore the tty with `stty sane` after killing the effect (tte leaves it raw/no-echo, which silently killed the following gum prompts) and clear the screen so the leftover frame doesn't linger under the keyboard step. Co-Authored-By: Claude <noreply@anthropic.com> * Kill the greeter animation cleanly so the form starts fresh The ColorShift ran inside a `while` subshell that was backgrounded and killed by its subshell PID — which orphaned the tte child, leaving it painting the logo over the keyboard step (the screen never cleared and the form was garbled). Run tte directly so the tracked PID is tte's own, and killing it actually stops the animation before the screen is cleared. Co-Authored-By: Claude <noreply@anthropic.com> * Don't let the killed animation abort provisioning under set -e wait on the tte PID reports its kill signal (143). Under set -euo pipefail that nonzero status aborted greeter_screen — and the whole service — right after Return, dropping first boot straight to the login screen instead of the keyboard step. Tolerate it with `|| true`. Co-Authored-By: Claude <noreply@anthropic.com> * Wait for the terminal size to settle before drawing the greeter A terminal emulator — or sudo's pty — reports a stale 24x80 for a few hundred milliseconds after the process starts, before its real winsize is set. The greeter measured immediately and fell into the 80x24 fallback, rendering small in the top-left instead of centered (the real first-boot console, already settled, was unaffected). Wait for stty to report a stable size at least as wide as the logo before measuring. Co-Authored-By: Claude <noreply@anthropic.com> * Fall back to the default font when the greeter console is too narrow scale_console_font sizes the console font from /sys/class/graphics/fb0, but virtio-gpu (notably virtio-vga-gl) can report a resolution that the console then settles below — leaving a font wide enough that an 81-column logo no longer fits (e.g. sun32 at a settled 1280px is 80 columns). The logo wrapped and hugged the top-left, with the animation tiling over it. After the greeter measures the settled size, if it is still narrower than the logo, drop to the default (narrowest) console font and re-measure so the logo always fits and centers. Verified by forcing an 80-column console: the fallback recovers it to 160 columns, centered, and provisioning completes. Co-Authored-By: Claude <noreply@anthropic.com> * Redraw the greeter on console resize instead of measuring once The first-boot greeter measured the console once, painted the logo and launched the tte animation, then blocked on Return. On a fresh deferred-provisioning boot under virtio-gpu the VT comes up in a transitional ~80x25 mode and only widens to the real resolution a second or more later, once KMS takes over (or, on virtio-vga-gl, the SDL window's size lands). The old settle-wait accepted that transient (two matching 100ms samples was enough), so the greeter committed to an 80-column geometry. When the VT then resized, Linux scrolled the stranded frame into the top-left and reset the DEC saved cursor tte paints from with --reuse-canvas — the small, top-left, tiled/garbled logo. The earlier "fall back to default8x16 when cols<81" fix couldn't help: if the console genuinely offers 80 columns, re-applying the narrowest font still leaves 80. Treat a resize as a redraw trigger instead. greeter_screen now: - waits for a real quiet period (console signature = VT size + framebuffer identity/size held steady ~1.5s) before the first paint; - sizes the font empirically — apply each candidate, read the columns fbcon actually returns, keep the one nearest ~48 rows that still clears the 81-column logo — rather than trusting fb0/virtual_size, which under virgl can report a size the text console never reaches; - paints from a nested _greeter_draw and, while waiting for Return, watches SIGWINCH and the console signature; on any change it kills tte, settles, re-fits the font, and repaints — so a resize arriving five seconds in looks the same as one that never happened; - draws each logo row at an explicit column and falls back to a centered text-only greeter (no logo, no animation) when the console is narrower than the logo, so a still-transient mode never wraps it into mush; - runs tte at canvas-width cols-1 to stay off the autowrap column. Verified the resize path in a tmux pane (a resizable pty): narrow first paint falls back to centered text, and each later resize repaints a correctly centered logo, with a clean exit on Return. Co-Authored-By: Claude <noreply@anthropic.com> * Ask the owner's timezone at first boot and hand off straight to Omarchy Three changes to the deferred first-boot setup: - Timezone: deferred provisioning skips the installer's user step entirely (it defers user creation to first boot), but the first-boot form only re-asked username/password/name/email — the timezone picker was never carried over, so every deferred machine silently kept archinstall's UTC default and the owner was never asked. Add the timezone step to the first-boot user form (geo-guessed default via tzupdate, same as the ISO installer's user step), show it on the confirmation screen, and apply it during provisioning with timedatectl. - Rename the progress-screen title from "Setting up your account" to "Setting up your machine": first boot provisions the whole machine, not just an account. - Drop the timed "Installed Omarchy in Xm Ys" celebration screen and the "Start Omarchy Now" button from first boot. That send-off belongs to a direct install; here the oneshot service just hands straight off to SDDM (Before=display-manager.service), which autologins on encrypted installs. A brief "Starting Omarchy..." covers the handoff. Co-Authored-By: Claude <noreply@anthropic.com> * Autologin only the first deferred boot on unencrypted installs The owner authenticates in the first-boot form, so setup hands straight into the desktop instead of asking again at SDDM. Encrypted installs keep autologin permanently (the LUKS prompt is the auth boundary); unencrypted installs autologin just this once and a self-removing service deletes the drop-in after the desktop is up, so later boots use the normal SDDM login and the disk isn't left permanently open. Co-Authored-By: Claude <noreply@anthropic.com> * Ask the owner's hostname at first boot too Deferred provisioning no longer bakes a hostname into the install, so add the hostname to the first-boot user form (same letters/digits/dashes validation as the ISO installer's user step, defaulting to "omarchy" on empty), show it on the confirmation screen, and apply it with hostnamectl during provisioning — alongside the timezone step. Co-Authored-By: Claude <noreply@anthropic.com> * Let the greeter logo appear from the animation, not a static pre-render The greeter drew the logo statically in green and then started the tte ColorShift over the same rows, so the logo visibly flashed as tte's first frame repainted it. ColorShift shows the full logo on frame one (it's a color effect, not a type-in), so let tte paint the logo itself: skip the static render when tte is available (keep it only as the no-tte fallback). The logo now simply appears, already animating, with no flash. Co-Authored-By: Claude <noreply@anthropic.com> * Drop the greeter color animation; show the logo in solid green The greeter "flash" was tte's ColorShift crushing on the framebuffer console: tte emits 24-bit truecolor, the console only has 16 flat colors, and consecutive frames' greens snap to different buckets (green/bright-green/cyan/ gray) — a frame-to-frame judder. A smooth color fade is impossible on the console (no blending), so the animation can't be made clean there. Show the logo in solid green (indexed color 2, which renders stably) with no animation. The resize-redraw resilience stays; there's just no tte to tear down now. Co-Authored-By: Claude <noreply@anthropic.com> * Fix first-boot review findings: autologin-once ordering, offline timezone Review of the deferred first-boot flow surfaced two real, user-facing bugs: - Autologin fired twice on unencrypted installs. The one-shot cleanup unit was ordered After=display-manager and enabled via a graphical.target.wants symlink + daemon-reload during the first boot — but graphical.target's job for that boot is already computed, so systemd never pulled the new unit in. It only ran on the *second* boot (which also autologged in) and removed the drop-in there. Order it Before=display-manager instead (and drop the sleep fudge): this boot autologins, the next boot's fresh transaction runs the cleanup before SDDM reads its config, so that boot shows the normal login. Exactly one autologin, deterministic, no race. - Offline first boot aborted setup. `geo_guessed_timezone=$(tzupdate -p)` is a plain assignment under `set -e`, and tzupdate exits non-zero with no network — the common case for a fresh machine — killing the attempt before the offline gum-filter fallback. Guard it with `|| geo_guessed_timezone=""`. Also: configure_timezone no longer symlinks /etc/localtime to a nonexistent zone file on a bad zone (guards on the zoneinfo file existing); scale_console_font's stty-size fallback emits a trailing newline so `read` can't trip `set -e`; and drop two stty-sane calls that only existed to recover from tte's raw mode (tte is gone). Co-Authored-By: Claude <noreply@anthropic.com> * Seed placeholder hostname/timezone in deferred install, overwrite at first boot Simpler than the empty-string approach: instead of writing hostname=""/timezone="" and having the orchestrator fall back, the deferred install now seeds neutral valid defaults (hostname=omarchy, timezone=UTC) and the first-boot wizard overwrites both. Identical end state, one decision in one place, and no reliance on archinstall accepting empty config values. Runtime comments updated; the configure_* functions are unchanged (they still overwrite whatever was seeded). Co-Authored-By: Claude <noreply@anthropic.com> * Bring back the greeter ColorShift animation Reverts the "drop the color animation" change — the framebuffer's truecolor crush gives the ColorShift a quick flash, but that's acceptable; removing the effect entirely was overreach. Restores the static green logo + looping tte ColorShift overlay (green base, cyan accent, settling on green), keeping the resize-redraw resilience and every other fix intact. Co-Authored-By: Claude <noreply@anthropic.com> * Hide the omarchy-provision-* commands from the listing These run from services and install hooks (first-boot provisioning, per-user finalize, first-login) — never something a user invokes directly. Mark them omarchy:hidden=true and drop the group/examples that implied a user-facing route. The binaries still work when called directly by their callers. Co-Authored-By: Claude <noreply@anthropic.com> * Hide the factory-reset first-boot worker from the listing omarchy-system-factory-reset-finish runs from a first-boot service after a reset — never invoked by hand — so hide it like the provision workers. omarchy-system-factory-reset itself stays visible (Setup > Reset Computer). Co-Authored-By: Claude <noreply@anthropic.com> * Address final-review findings: LUKS fail-open, set -e aborts, drop-to-console Codex xhigh final pass surfaced several real issues; the contained ones: - LUKS re-key could fail open (security). If the user's slot couldn't be identified, or luksDump/luksKillSlot failed, the code shredded the staged key anyway while the throwaway/seller slots stayed valid — leaving the disk unlockable by the install passphrase forever. Now it's all-or-nothing: require the user's slot, enumerate and kill every other slot, and only retire the staged key once all kills succeed; otherwise fail loudly and keep it for retry. - Greeter animation cleanup: `kill "$anim"` was unguarded, so if tte had already exited (crash or resize race) it returned non-zero and `set -e` aborted setup, dropping to SDDM with no user. Guard it with `|| true`. - reset_limine_config: `old_ids=$(grep ... | ...)` on an entry-less limine.conf (left by a failed rebuild) exits 1 under pipefail and aborted the retry. Guard with `|| true` so a rebuild failure stays recoverable. - "Drop to console" on a failed setup exited to nothing usable (no user, root locked, tty1 getty conflicted). Exec a root shell on tty1 instead; SDDM starts when it exits. Co-Authored-By: Claude <noreply@anthropic.com> * Drop Bosnian and Khmer from the keyboard picker Neither has a console keymap (loadkeys ba / loadkeys khmer both fail), so picking them showed the choice as confirmed but silently left the system on the default US layout. Remove them from the first-boot picker rather than offer a layout that can't apply. The orchestrator keeps its defensive unsupported-keymap handling for install-time robustness. Co-Authored-By: Claude <noreply@anthropic.com> * Finish the omarchy-first-run rename in the docs Two doc references to omarchy-first-run were missed when the script was renamed to omarchy-provision-first-run; update them to match. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
6fa4f78ee1 |
Add deferred first-boot provisioning and factory reset (#6621)
* Add OEM first-boot setup and factory reset An OEM-mode ISO install (or omarchy-reset-computer) leaves the machine in OEM state: fully installed, no user, /var/lib/omarchy/oem/pending armed. On the next boot omarchy-oem-setup.service runs the configurator's user form on tty1, creates the user with the groups system setup recorded, finalizes it offline from the stashed Node tarball, re-keys LUKS from the throwaway install passphrase to the user's password, and hands off to SDDM. omarchy-reset-computer returns a machine to that state: it swaps the running root for a fresh clone of the @factory snapshot the ISO takes at install time, scrubs machine identity and prior users, and stages omarchy-factory-wipe to drop the old root and recreate @home/@log on the next boot. Machines installed before @factory existed get a degraded reset (current system kept, users and state wiped) with that caveat surfaced in the confirmation. omarchy-setup-system/-hardware gain --oem to run without an install user; the group-granting install scripts now record their groups in /var/lib/omarchy/oem/groups and only call usermod when the user exists. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Harden OEM setup: correct cryptsetup key-file usage, retry on failure cryptsetup reads --test-passphrase/--key-file inputs byte-for-byte, so feed passphrases through process substitution consistently instead of positional args or stdin (which has different newline semantics). Run each first-boot setup attempt as its own process so a failure offers a retry instead of stranding the machine at a user-less login screen — bash ignores errexit inside `while !` conditions, a child process does not. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Always grant wheel sudo in OEM first-boot setup Detecting an existing %wheel grant by grepping sudoers is error-prone: omarchy ships narrow '%wheel ALL=(ALL) NOPASSWD: <command>' rules (e.g. asdcontrol) that match the naive pattern, which left the OEM-created user matching sudoers entries but unable to run anything. Write the drop-in unconditionally — a duplicate of an existing full grant is harmless. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Fix LUKS re-key device resolution and OEM state readability archinstall's encrypted installs put cryptdevice=PARTUUID=... on the kernel cmdline, not UUID=, so the first-boot re-key never found its device and silently skipped — leaving the throwaway auto-unlock keyfile in place, i.e. the disk effectively unencrypted. Parse every cryptdevice= source spec form and make any re-key failure abort the attempt loudly: a retry prompt beats a machine that quietly boots without a passphrase forever. The OEM state directory also has to be world-readable (its one secret, luks-key, stays 0600): user finalization reads the stashed Node tarball as the new user, and the 0700 directory forced it onto the network fallback. Step markers now land in /var/log/omarchy-oem-setup.log for debuggability. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Purge stale machine-id boot entries when resetting or re-keying limine-entry-tool keys its limine.conf OS entries by machine-id. A factory reset gives the machine a fresh identity, so the previous system's entry survived every rebuild, sorted first, and made Limine stop at a Blake2b hash-mismatch warning once the UKI was rebuilt. Start limine.conf over from the shipped template (and drop foreign machine-id history directories on the ESP) before any post-reset rebuild: in the staged chroot rebuild, in the first-boot LUKS re-key, and — for unencrypted resets, where nothing else rebuilds — in a dedicated first-boot refresh when foreign entries are found. The staged rebuild also verifies every UKI hash referenced by limine.conf against the file on the ESP before the subvolume swap, and the running system's limine-snapper-sync is runtime-masked during staging so it cannot rewrite the config behind the rebuild. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Harden reset and first-boot setup failure paths Review findings from codex and Copilot: - Generate throwaway passphrases without a trailing head stage: under pipefail, SIGPIPE from the infinite tr failed the substitution and errexit aborted every encrypted reset before it could stage anything. - Stage the fallible parts of a degraded reset (LUKS re-key, boot rebuild) before arming the wipe, so a staging failure leaves the machine untouched instead of scheduling a wipe for a reset that never finished. - Gate first-boot setup on the factory wipe having succeeded (ConditionPathExists=!wipe-pending plus an in-script guard): creating the new user on a half-wiped system would hand their data to the wipe retry. - Abort the wipe (keeping its retry marker) when deleting the old root or recreating @home/@log fails, and abort resets that cannot remove a prior account — a surviving account keeps its password and wheel membership. - Resume a partially-created account on setup retry instead of rejecting the username the failed attempt just created. - Only purge machine-id directories the old limine.conf actually referenced; a shared ESP may hold other installations' boot artifacts. - Recreate the hibernation swapfile (nested subvolume, so never captured by the factory snapshot) inside the factory root before its UKI rebuild, so a reset machine keeps disk-backed swap and a valid resume offset. - Source base-test.sh in the OEM groups test per test conventions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Recreate the hibernation swapfile even when resume drop-ins survive omarchy-hibernation-setup short-circuits as 'already set up' when the resume mkinitcpio drop-in exists — which it always does in a factory root, while the swapfile itself never survives the snapshot (nested subvolume). Drop the marker when the swapfile is gone so setup reconfigures from scratch, and verify the swapfile actually exists before proceeding with the reset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Second review pass: encrypted-config coverage, factory-baseline sanitization, recoverable rekey Codex xhigh round 2: - Detect the LUKS backing device by walking the root's device tree, not only the cmdline cryptdevice=; reset/first-boot now re-key roots reached via rd.luks/crypttab too, instead of silently leaving the seller's slots valid. - Sanitize the retained @factory baseline (accounts, /etc/shadow, machine identity) during a full reset: the new wheel user could otherwise mount it to recover the seller's data, and a second reset would restore the account. - Re-key the disk recoverably: rebuild the no-auto-unlock UKI before killing the throwaway slot or destroying the staged key, and restore the keyfile if that rebuild fails, so a retry with a different password can never leave the disk locked to the first attempt's password. - Roll back a degraded reset's live-root auto-unlock material if its boot rebuild fails, instead of leaving it for a later rebuild to embed. - Treat a missing current-machine limine entry as stale so a retry after a failed rebuild repairs the config instead of clearing OEM state over it. - Erase fingerprint enrollments (/var/lib/fprint) in degraded wipes. - Remove the resume-offset drop-in too when recreating the factory swapfile, so the rebuilt UKI gets a correct offset. - Pin first-boot retries to the account the first attempt created. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Expose factory reset in the Setup menu Add a 'Reset Computer' entry under Setup (Omarchy's Settings menu, where OS factory resets conventionally live), guarded to btrfs roots and launched in a floating terminal. omarchy-reset-computer now self-elevates via sudo so the menu entry needs no sudo prefix, forwarding the caller's gum theme env as env arguments so styling survives an env_reset sudoers. The typed 'reset' confirmation and the sudo password prompt remain as the guards against accidental triggering. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Defer keyboard selection to first boot for OEM installs The OEM first-boot setup now runs a keyboard step before the user form, mirroring the ISO configurator: it loads the chosen layout on the live VT so the password (and the LUKS re-key that follows) are typed under it, and persists it with systemd-firstboot so the installed system gets both the console KEYMAP and the XKB layout Hyprland reads — exactly what a normal install writes. Layouts localectl doesn't know keep the default, same as the installer. This lets the OEM operator set nothing user-specific: the machine's owner picks their keyboard alongside their account at first boot. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Rename factory-reset commands to omarchy-system-factory-reset[-finish] omarchy-reset-computer -> omarchy-system-factory-reset omarchy-factory-wipe -> omarchy-system-factory-reset-finish (and its systemd unit, log path, and temp mount to match) Pure rename: every reference — the Setup menu action, the first-boot finish service the reset stages and enables, the oem-setup ordering/gating, comments, and the menu test — moves together, with no behavior change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Rename OEM vocabulary to provisioning (runtime) Commands unify under the provisioning family: omarchy-oem-setup → omarchy-provision-owner omarchy-finalize-user → omarchy-provision-user omarchy-first-run → omarchy-provision-first-run And the deferred-provisioning state/vocabulary replaces 'OEM': /var/lib/omarchy/oem/ → /var/lib/omarchy/provisioning/ /etc/omarchy/oem.key → /etc/omarchy/provisioning.key install/oem/ → install/provisioning/ OMARCHY_SETUP_CONTEXT=oem-firstboot → provision-owner omarchy-setup-system/-hardware --oem → --defer-provisioning All callers (provision-first-run→provision-user, autostart, factory-reset staging the provisioning units, the group-recording scripts) and comments move together. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Drop remaining OEM mentions from the provisioning groups test Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Finish the omarchy-first-run rename in the docs Two doc references to omarchy-first-run were missed when the script was renamed to omarchy-provision-first-run; update them to match. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
9b03f15b4f |
Detect Elan match-on-chip fingerprint readers again (#6578)
* Detect Elan match-on-chip fingerprint readers again Elan readers report "ELAN:ARM-M4" as their product string, so the *fingerprint* and *biometric* checks miss them. Elan's 04f3 is also left out of the vendor list on purpose, because Elan makes touchscreens too. Both checks fail, so the machine looks like it has no reader. Add "elan:arm-m4" to the product string check. The comment above the vendor list already says the excluded vendors should still match there, so this makes that true. The vendor list and its has_kernel_driver guard are unchanged, and touchscreens still cannot cause a false positive. The string is a family name, not one device. libfprint uses it for 04f3:0c9c and 04f3:0ca7 as well as 04f3:0ca8. Tested on an HP EliteBook X G2i with 04f3:0ca8. * Point the Elan comment at the vendor list above it Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Configure PAM only after a fingerprint enrolls and verifies Detection proves a reader is present, not that libfprint can drive it. Elan MOC sensors outside the elanmoc table pass the gate and then fail to enroll, which left pam_fprintd in the sudo and polkit stacks with no print to match. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: David Heinemeier Hansson <david@hey.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
e1d0c4e0a8 |
Ship the keyboard layout widget on the bar and make clicking it work (#6659)
* Hide the keyboard layout widget on a single-layout install There is nothing to read or switch when only one layout is configured, so the label is noise on the bar most people have. Hide it until the keyboard reports more than one, and keep showing it on a Hyprland that doesn't report the list at all rather than hiding the widget everywhere. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Put the keyboard layout widget on the bar by default The widget hides itself unless the active keyboard has more than one layout, so shipping it costs a single-layout machine nothing and saves everyone else from finding it in the plugin list. Sit it just right of the clock, and add it to existing bars the way the agents widget was added, leaving a curated bar and a disabled widget alone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Cycle the layout with the hyprctl command that exists switchxkblayout is a hyprctl command, not a dispatcher, so sending it over the dispatch socket only produced a Lua syntax error and clicking the widget did nothing. Run it instead, against the keyboard the label was read from. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Add an idempotent bar add command Nothing put a widget on the bar without going through the running shell: plugin enable and bar move both forward to it over IPC, which a migration cannot rely on. Add writes the config file the way position and transparent already do, and leaves a widget that is already on the bar where the user put it, so callers can ask for it repeatedly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Put the keyboard layout widget on bars through the bar CLI The hand-written jq was a normalizer, a presence check and a splice for what is now one command that carries all three. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Keep bar add from writing a bar the shell was not reading The shell takes a user shell.json only when it parses, says version 1, and carries a bar layout, and does not deep-merge; anything else leaves the shipped defaults on screen. Reading and writing the user file regardless turned a config holding nothing but an idle timeout into a bar holding nothing but the new widget, and made an unparsable one abort the migration chain on every update. Work against whichever layout is actually in effect, seeding the defaults before placing a widget they do not already carry. A malformed hand-installed manifest fails the whole plugin catalog, which was enough to refuse a first-party widget, so treat an unreadable catalog as no answer rather than a no. Leave a widget listed in disabledPlugins off the bar instead of writing a layout entry the registry refuses to load, and re-check presence inside the mutation so two adds cannot both miss it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Read a widget's default bar section in one place cmd_defaults spelled out the same "defaultSection, or center when it is missing or not a section" rule that the add path already asks for by name. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Rename bar add to bar put 'omarchy plugin add' installs a plugin and 'omarchy bar add' placed one that was already installed, which is too much meaning for one verb. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Place a newly added bar widget with bar put plugin add reached the bar through plugin enable, which forwards to the running shell, so it first had to poll until the shell noticed the clone and then failed outright when no shell was there to ask. Putting a widget on the bar is a config edit, so do that directly and leave plugin enable to the plugins that need registering rather than placing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Put bar widgets through the shell instead of the config file Placing a widget existed twice: once in PluginRegistry, which the shell uses and owns the config it holds in memory, and once as jq against shell.json. The second was there so migrations could run without a shell, which they do not need to: the Quattro upgrade hands over the shipped shell.json before it runs any, and every other path runs inside a session with a shell up. Ask the shell, and say so and carry on when there is none to ask. putBarWidget enables only what is not already on the bar, which is what a caller that cannot know whether it ran before needs, and is the one thing the existing enable path would not do. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
dd61d4a75b |
Ship herdr alongside tmux (#6406)
* Ship herdr with a config that mirrors our tmux setup Installs herdr through the mise shim, ships the matching config as an Omarchy default, and adds the usual refresh/restart pair. The keybindings map tmux sessions to workspaces, windows to tabs, and keep both the prefix and direct bindings from config/tmux/tmux.conf. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Add herdr versions of the tmux dev layout functions hdl, hds, hdlm, and hsl drive herdr through its socket API instead of tmux. hsl tiles into a real grid since herdr has no select-layout tiled. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Namespace the herdr layout helpers so they stay out of the shell Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Create hdlm's tabs in its own workspace instead of the focused one herdr tab create follows the focused workspace without --workspace, so switching workspaces while hdlm loops scatters the new tabs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Lay hsl's grid out in visual order Splitting the first column repeatedly inserted each new column between it and the previous one, so uneven counts put the spare row in a middle column instead of the last. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Report herdr config reload failures instead of swallowing them Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Hide herdr's pane scrollbars to match tmux Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Escape queued herdr layout commands * Install herdr from the omarchy-herdr package instead of mise * Use native herdr resize keybindings for tmux-style pane resizing * Rename the omarchy-herdr package to herdr --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
2a0c7371a5 |
Claude collector: attribute pi usage by provider, not api prefix (#6655)
Pi/omp sessions kept falling into the Claude record when the api field merely started with 'anthropic'. Kimi and other providers that speak the anthropic-messages protocol (kimi-coding) were therefore charged against Claude Code, showing k3 buckets under a Claude tab even for a user without a Claude login. Match the codex collector's provider-only attribution: only sessions whose provider is exactly 'anthropic' count toward Claude usage. Add a test proving a kimi-coding session sharing the anthropic-messages api does not land in the Claude record. Co-authored-by: Luca <luca@itwasarch> |
||
|
|
e4d85bd037 |
Keep concurrent usage collectors off one shared temp file (#6654)
Two Claude collectors running at once both wrote the cache through a temp path derived from the target, so the second replace found the file already moved away and crashed the update with a FileNotFoundError. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
f8c235a5e4 |
Read /boot as root when looking for the Omarchy UKI (#6653)
* Find the Omarchy UKI as root when setting up direct boot /boot is mounted with dmask=0077 on encrypted installs, so the unprivileged find returned nothing and direct boot always reported that no UKI was present. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Check for the legacy UKI as root when refreshing limine The unprivileged file tests were always false on encrypted installs, so the stale <machine-id>_linux.efi was never cleaned up. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
1ded25fd45 |
Make a dead lock client diagnosable and recoverable (#6630)
* Persist the Omarchy shell log across sessions Quickshell only logs to its instance runtime dir on tmpfs, so when the shell dies the idle/lock event trail is gone after a reboot (#6628). Launch the shell through omarchy-launch-shell, which pipes stdout/stderr into the journal under the omarchy-shell tag — bounded, timestamped, and persistent — and surface that log in omarchy-debug-idle. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Recover a locked session whose lock client died When the shell dies while the session is locked, Hyprland's failsafe keeps the session locked with no lock client left, and omarchy-restart-shell refused to run in exactly that state, leaving reboot as the only way back in (#6628). Gate the refusal on the lock service actually holding (or acquiring) the lock rather than on the session's LOCK state — a dead shell and a crash-handler relaunch that holds no lock both fail that check — then restart the shell, re-acquire the session lock, and wait for it to report secure, the same secure-poll omarchy-system-sleep-lock uses, so the user can authenticate out of the failsafe. Enable Hyprland's allow_session_lock_restore so the compositor accepts the replacement lock client. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
5a58f79876 |
Keep clicking a notification working after a shell restart (#6636)
* Keep clicking a notification working after a shell restart Notification actions lived only in the sending process: `-a` appended `-A default=default`, so notify-send blocked on a D-Bus ActionInvoked signal and the caller ran the command when it arrived. Nothing about that reached disk, so a restored popup had no action to run and its sender stayed blocked forever. Replace `-a` with `--exec <command>`, carried as an `omarchy-exec` hint into the snapshot's `exec` role. It travels through the popup files and history, and the shell runs it on click, so restored toasts behave exactly like live ones and the sender exits immediately. That drops the scaffolding whose only job was keeping a blocked sender alive: the first-run invitations lose their `--show` re-entry and two transient units each, omarchy-migrate-notify loses its transient service, and the screenshot, recording, download, and taildrop toasts lose their wrapper subshells. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Keep a failed toast from failing the work it announces Moving these sends out of their backgrounded subshells put a fallible command on the foreground path, where the `&` used to swallow its exit status. A notification outage — including the shell restart this branch targets — now propagates: - taildrop's receiver dies under `set -e` mid-delivery - omarchy-capture-screenshot reports failure for a screenshot it already saved - a completed download exits before scheduling its thumbnail cleanup, leaking the mktemp file Announcing is best-effort in all three: the work is already done by the time the toast goes out. Also drop the first-run sleep that spaced out the welcome and Wi-Fi toasts. It compensated for the background notify-send processes this branch removes; each send now returns only once the server has taken the toast, so sending in order is enough to stack them newest-on-top. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Stop tying the preview cleanup to the toast's expiry The shell loads a notification thumbnail into memory when the toast appears and never re-reads the file, so the preview only has to outlive that load. Deriving the cleanup delay from the expiry was false precision, and it turned -t into a variable for no reason: -t is already the helper's expiry setting. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
ab367b9477 |
Stop mise wrappers from waiting out the release cooldown
The wrappers install and upgrade their tool on first run, so the cooldown held new versions back for days. Refresh the stubs on existing installs too, since the generator change alone only reaches fresh installs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
76117fb8ba |
Take mise tool updates without waiting out the release cooldown
mise withholds releases younger than its cooldown, so omarchy update left tools behind for days. The mup alias already bypassed it by hand. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
366b789be1 |
Revert "Nicer with an extra CR here"
This reverts commit
|
||
|
|
a3aa3c9e82 | Nicer with an extra CR here | ||
|
|
48c17bb644 | mise already gives the CR needed | ||
|
|
412f6acb74 | Don't need the extra CR | ||
|
|
a85880385f | Make this note of where they're usable | ||
|
|
0f1e0ced36 |
Remove the omarchy-update-perform compatibility wrapper
Nothing calls it anymore; new code calls omarchy-update directly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
76dc120ccb |
Fit the About window to its rendered content (#6627)
* Fit the About window to its rendered content The About fastfetch layout needs more columns than the shared 875x600 float provides, and the terminal's grid often only reaches its final size after fastfetch has printed, leaving the output wrapped over the logo or clipped at the initial 80-column grid (#6465). Give About a dedicated org.omarchy.about app id so launch-or-focus can actually match it, render through a loop that repaints on window size or branding changes, and measure the rendered content to fit the window around it with even padding, whatever the terminal font or About logo. Fixes #6465 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Spacing --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
47fa3ce3a5 | Match style from other updates | ||
|
|
318bf2c43a |
Keep the Quattro upgrade from aborting silently into an unsafe state (#6617)
The script is fetched from the branch but calls into the installed /usr/share/omarchy tree, which can lag it. A packaged build without bin/omarchy-done aborted apply_user_transition under set -e two thirds of the way through: NetworkManager was already enabled, iwd was not yet disabled, and nothing was printed, so the run read as finished. The completion markers are now written directly instead of through omarchy-done, and the two remaining unguarded packaged commands warn rather than abort. Retiring iwd moves up next to the NetworkManager enable it depends on, so no failure in between can leave both enabled. An aborted run now says so instead of returning to the prompt on a green progress line. Fixes #6575 Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
5e5a6e8c89 | stop omarchy-mise-install from overwriting symlink targets (#6619) | ||
|
|
007d6fcd7d |
Use the gmux backlight instead of the Touch Bar on T2 Macs (#6597)
* Match display backlight candidates against real globs [[ ]] does not do pathname expansion, so amdgpu_bl* and acpi_video* only ever tested for files with a literal asterisk in the name. Every machine without intel_backlight silently fell through to the alphabetical first entry, which picks acpi_video0 over amdgpu_bl0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Use the gmux backlight instead of the Touch Bar on T2 Macs /sys/class/backlight on a T2 Mac holds appletb_backlight and gmux_backlight. Neither was a candidate, so the alphabetical fallback picked the Touch Bar and brightness keys dimmed it instead of the display. Add gmux_backlight and never fall back to the Touch Bar, which is not a display panel on any Mac. gmux ranks above the GPU backlights because apple-gmux only registers its device when the kernel has already selected it for the machine, and on dual-GPU Macs the GPU's own PWM stops driving the panel as soon as that GPU suspends. Fixes #6558 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
f76d058a6d |
Force a database refresh before installing keyrings during the Quattro upgrade (#6615)
The upgrade repoints the mirrorlist and the [omarchy] server, then ran pacman -Sy. A plain -Sy keeps the legacy database whenever the new server's copy isn't newer, so the checksums stay stale and every re-download of a rebuilt package aborts as corrupted. Fixes #6576 Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
77cf58ccfe |
Add Fireworks balance usage panel (#6488)
* Add a Fireworks balance collector and teach the agents panel prepaid ledgers The omarchy-agent-usage-fireworks collector reads serverless token usage from the Fireworks billing API, grouped by day and model for the last 30 days, and reshapes it into the shared record contract. Fireworks does not expose its prepaid ledger through the documented API, so the record carries an estimated balance instead of rate limits: credits configured in ~/.config/omarchy/agents/fireworks.json minus rated account costs since the funding date. Credentials come from FIREWORKS_API_KEY/FIREWORKS_ACCOUNT_ID, the auth.ini that firectl set-api-key writes, or — last, so an explicit login wins — the key opencode stores for its fireworks-ai provider. The panel gains two generic capabilities any agent record can use: a balance object draws a BALANCE section — remaining credit, a fuel-gauge meter that drains toward empty and lights the bar alarm below 10%, and funded-versus-spent detail — and hasPromptStats: false keeps prompt and session counts out of today's tooltip for agents whose billing API only ever reports tokens, on this machine and through synced snapshots. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Feed Claude and Codex usage from pi, omp, and opencode sessions A subscription burned entirely through another coding agent leaves no native Claude Code transcripts and no Codex session files, so the panel showed nothing for it. pi and omp write compatible JSONL sessions, and opencode records per-message provider, model, and token usage in its message database; the claude and codex collectors now scan all three — filtered to Anthropic and OpenAI providers respectively — and merge those numbers into their local stats. Fireworks stays out on purpose: its billing API already sees that traffic server-side, and a local scan would count the same tokens twice. The collector tests pin XDG_DATA_HOME so a developer's real opencode history cannot leak into fixture runs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
b85ae70ebd |
Stop pipefail from turning grep -q SIGPIPE exits into false negatives (#6614)
* Stop pipefail from turning grep -q SIGPIPE exits into false negatives grep -q exits at the first match, and when the producer is still writing it dies with SIGPIPE. Under pipefail that 141 becomes the pipeline's status, so hardware checks like lspci | grep -q read as "not found" on exactly the machines they target. The T2 defaults migration hit this and silently skipped real T2 Macs (#6608). Redirect grep to /dev/null instead of -q wherever a pipeline feeds grep in a pipefail context, so grep reads all input and the producer never gets killed. The install-time T2 checks aren't run under pipefail today but are switched too, since they're the same detection line the issue calls out. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Re-run the T2 defaults migration its broken hardware check skipped The SIGPIPE bug marked 1785944594 as applied without doing anything on affected T2 Macs. The original migration is idempotent, so a fresh migration can just source it now that the guard is fixed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Address Copilot review: fix OCR grep pipeline and prove the T2 repair screen_contains piped tesseract into grep -Fqi under the acceptance suite's pipefail, the same SIGPIPE false negative the rest of the branch fixes. The T2 test's lspci stub now keeps writing past the pipe buffer after the match so every scenario exercises the SIGPIPE case, and a new case runs the rerun migration against fixtures a bitten install would have. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
2521b11fdd |
Add a disk speed test under a new Trigger > Tests menu (#6607)
* Extract the speed test gauge cluster into a shared SpeedTestOverlay The dial cluster -- scrim, ignition sweep, self-ranging dials, run-again button -- moves from the network speed test panel into qs.Ui with the labels, unit, title, scale stops, and layer namespace as parameters, so other measurements can wear the same cluster. The network panel keeps its process handling and becomes a thin dressing of the overlay. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Add a disk speed test and move speed tests under Trigger > Tests omarchy-disk-speedtest streams live write and read MB/s once a second by sampling the backing block device's kernel I/O counters while dd workers generate the traffic, the same way the network test samples the interface counters. The stress data is an incompressible urandom chunk staged in RAM, written with fdatasync per pass and fadvise drop-behind: O_DIRECT silently falls back to the page cache on btrfs, and zeros never reach a compressed filesystem at all. Scratch files are created exclusively per invocation and removed even when a dismissal interrupts the run mid-phase. The omarchy.disk-speedtest panel dresses the shared SpeedTestOverlay with write and read dials in MB/s, titled with the hardware model of the disk under test. The menu grows a Trigger > Tests submenu holding the new Disk Speed Test and the Network Speed Test, which moves there from Setup > Network. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Make the disk speed test reproducible, direct, and read-first Successive runs could swing 40% because the settled figure was just the last one-second sample of a single buffered dd stream, taken while btrfs copy-on-write churned the extent allocator on every rewrite pass and the fadvise cache-eviction dance stayed advisory. The test files are now marked NOCOW, which is what makes O_DIRECT truly direct on btrfs -- with checksums on it silently falls back to the page cache -- and lets every rewrite land in place. Four parallel workers per phase give the device a queue depth it can stretch out on, and the figure the dial settles on is the steady-state average over the whole phase with the first warm-up second excluded, not whatever rate the final second happened to catch. Together this tightens successive runs from +/-40% to a few percent of each other, at the device's actual spec throughput. The read phase now runs first, staged against freshly written files, with the read dial on the left. Workers also only loop while the main script lives, so a dismissal that loses the kill race can no longer leave an orphan hammering the disk forever, and any worker dying before the deadline fails the run instead of passing off partial figures. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Drop the menu aliases from the speed test entries Aliases are reserved for established alternate names users already type, kept for compatibility -- not something new entries pick up by default. Note that in the menu definition header and AGENTS.md so the next entry doesn't repeat it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Group dial readouts with thousands separators A gen5 disk reads five digits; 11,450 scans, 11450 doesn't. Uses the locale's grouping separator. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Trim redundant overlay props and unused imports from the speed test panels The network panel restated the overlay's default unit and scale stops, and both panels carried imports and an omarchyPath property nothing uses. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Publish the specific speed test error whichever handler fires last Process exit and stderr stream-finished have no guaranteed order, so a failure that beat the collector showed the generic message forever even when the command emitted an actionable one; the collector now replaces it once the text lands. Also stop clearing the error on every stdout line: only a new run should do that, or buffered output delivered after a failed exit erases the failure message. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Arm the disk speed test cleanup before any scratch file exists A preflight failure -- tmpfs target, missing device statistics, not enough free space -- exited between mktemp and the trap, leaking the scratch files. Cleanup also now unlinks before stopping the workers and sweeps once more after, so even a cleanup cut short by an impatient SIGKILL leaves no names behind and a final worker pass cannot recreate one. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
3bfea9b840 |
Fail loudly when a pre-update snapshot isn't actually created (#6580)
* Fail the snapshot when Snapper is installed but has no configs omarchy-snapshot create loops over the configs snapper reports. With none, the loop body never runs, so it prints "Create system snapshot" and exits 0 without capturing anything. Every update then reports a snapshot it never took, and the absence only surfaces when a rollback is needed and the snapshot list turns out to be empty. * Say so when the update proceeds without a snapshot The update ignores exit 127 so a system without snapper updates quietly. Any other snapshot failure was being swallowed by the same expression, which let the update continue with no indication that it was now unprotected. Keep continuing, but say it out loud. * Point the snapshot repair hint at how the installer runs it Also hold the green header until a snapshot will actually be attempted, so the no-config failure doesn't open with a success banner. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Continue the quattro upgrade when the pre-upgrade snapshot fails The upgrade runs under set -e, so the new non-zero exit from an unconfigured Snapper would have aborted a re-run at the snapshot step instead of proceeding like omarchy-update does. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: David Heinemeier Hansson <david@hey.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
9d5c6e25e7 |
Keep root= in the kernel cmdline when upgrading to Quattro (#6579)
* Keep root= in the kernel cmdline when upgrading to Quattro The packaged drop-in /etc/limine-entry-tool.d/omarchy-defaults.conf sets KERNEL_CMDLINE[default] with the += operator. limine-entry-tool.conf documents what that costs: "+= appends parameters to an existing cmdline ... Ignores /etc/kernel/cmdline and /proc/cmdline". As soon as the drop-in lands, the tool stops auto-detecting the cmdline. Fresh installs are unaffected, because the ISO writes /etc/default/limine from default/limine/default.conf with @@CMDLINE@@ substituted. The upgrade path never created that file. A pre-quattro install that relied on the auto-detected root= therefore ends up with a cmdline that has no root= at all, in both limine.conf entries and in the cmdline embedded in the UKIs. The next boot fails with "ERROR: Failed to mount '' on real root" and drops to an emergency shell, where the error gives no hint that the cmdline is the cause. Capture the boot-critical parameters from /proc/cmdline before the reboot, while the still-correct cmdline of the running kernel is readable, and write them to /etc/default/limine, which is loaded last so += keeps the drop-in parameters instead of replacing them. Copy root=, rootflags, rootfstype, resume, resume_offset, the cryptdevice and rd.luks keys and rw/ro verbatim rather than reconstructing them, so LUKS and hibernation setups survive too. Re-running the upgrade on an already-broken system has no root= left to copy, so fall back to deriving it from the mounted root, including the subvolume on btrfs. Any config layer that already pins root= is treated as authoritative and left untouched. * Anchor the cmdline guard and harden the repair path The early-return guard searched for the bare string root=, which matches the commented example limine-entry-tool.conf ships at line 53: #KERNEL_CMDLINE[default]+=rw root=UUID=... That file is present on every stock machine, so the guard always fired and the function never wrote anything. Match assignments instead, and check /etc/kernel/cmdline separately since it holds bare parameters rather than shell assignments. Three fixes on the repair path: Assigning boot_params discarded every parameter the collection loop had just captured, so cryptdevice, cryptkey, resume and ro were dropped, and rw was forced over a captured ro. Prepend the derived root= instead, and only add rw when the booted cmdline stated no mount mode. On an encrypted root, findmnt reports the unlocked mapper device, whose UUID says nothing about which container to unlock. Emitting it produced a cmdline that still could not boot while satisfying the final check, so the user rebooted into the same emergency shell believing it was repaired. Warn and write nothing in that case. The allowlist gained rd.luks.key, rd.luks.crypttab, rd.md.uuid, rd.dm.uuid, rootwait, rootdelay and dm-mod.create. Verification now also reads the .cmdline section of each UKI. With omarchy-uki.conf among the drop-ins that embedded copy is what actually boots, so a green limine.conf alone did not prove the machine would come up. * Filter guard paths and narrow the dm-crypt and UKI checks The guard passed /etc/default/limine to grep unconditionally, and that file is absent on exactly the machines this targets. A missing operand makes grep exit 2 without -q, so a drop-in pinning a real root= went undetected and the function appended a second one, overriding the explicit setup it promises to leave alone. Rather than relying on -q returning 0 despite the error, which is a GNU grep special case and not true of every implementation, filter the paths first and only grep the ones that exist. The exit status is then unambiguous. The dm-crypt check gated on the /dev/mapper/* prefix, which also matches plain LVM, dm-raid and multipath. Those roots need no unlock parameters and were repairable before, so the prefix test denied them a working root=UUID= and told them they were encrypted. Gate on the device mapper target type instead. root_filesystem_encrypted() is not reused here on purpose: it treats every /dev/mapper/* path and any non-empty /etc/crypttab as an encrypted root, which suits its own call site but would reintroduce the same false positive. UKI verification now runs through as_root, since a restrictive ESP fmask would otherwise make find return nothing and the check pass in silence, and is scoped to the omarchy_linux*.efi images limine-entry-tool generates so a shared ESP or a stub without a .cmdline section cannot raise a false "do not reboot" warning. The allowlist gained rd.lvm.lv and rd.lvm.vg. * Strip the subvolume before resolving the root device type findmnt appends the subvolume for btrfs mounts, so the source read back for an encrypted btrfs root is /dev/mapper/cryptroot[/@]. lsblk cannot resolve that path, the device type came back empty, and the crypt gate never fired. The function then wrote root=UUID= with no unlock parameters, limine.conf ended up carrying a root= so the final check stayed quiet, and the machine still booted to an emergency shell. That is the layout Omarchy installs when encryption is picked, so the gate missed exactly the roots it exists for. The previous /dev/mapper/* prefix test matched the bracketed form by accident. Moving to the device mapper target type is still the right call, it just needs the unbracketed source, which findmnt --nofsroot provides. Also give root_type an explicit empty default. It is assigned inside a branch and read outside it, and set -u treats a declared-but-unassigned local as unbound, so a findmnt that cannot answer would abort the upgrade with the quattro packages already installed and everything from configure_snapper_policy onward skipped. * Look for the crypt layer across the whole device stack lsblk -no TYPE reports only the target's own type. On the standard full-disk encryption layout, LUKS container -> LVM PV -> root LV, that type is lvm and the crypt layer sits in the parents, so the gate never fired: the function wrote root=UUID= with no unlock parameters, the final check found a root= and stayed quiet, and the machine still booted to an emergency shell. Walk the parents with lsblk -s and look for a crypt layer anywhere in the chain. That keeps LVM, dm-raid and multipath roots on the repair path, since they carry no crypt layer and root=UUID= is enough once mkinitcpio assembles them. root_type is replaced by root_stacks_crypt, which says what is actually being tested and drops the LVM-versus-crypt caveat the old target-type check needed. Also drop a vacuous test assertion: piping a bracketed literal through grep -qv '\[' selects nothing, so the branch was unreachable and the case passed whatever the script did. The --nofsroot assertion above it is what holds that fix. * Keep the crypt gate off a pipeline exit status Capture the device stack and match it from a here-string rather than piping lsblk into grep -q. Under pipefail a short-circuiting grep can leave the producer with SIGPIPE and turn the pipeline into 141, which reads as "no crypt layer" and disarms the gate silently. lsblk writes its whole table in one go, so this is out of reach in practice, but nothing about the gate should depend on how much output a helper happens to buffer. Also correct a stale test comment that described the target-type check the previous revision used, four lines above the comment explaining why that check was insufficient. * Harden the kernel cmdline preservation against false root= pins The /etc/kernel/cmdline early return trusted a file limine-entry-tool ignores once a += drop-in sets KERNEL_CMDLINE[default], leaving exactly the targeted machines unbootable. The pin guard now reads only the *.conf layers the tool loads, only the default key, and tokenizes the assignment value so quoted decoys and volatile-root= cannot pin. /proc/cmdline is tokenized quote-aware so dm-mod.create="..." survives verbatim, the root= verification is token-anchored, and an unverified cmdline now blocks the reboot instead of only warning. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Ask limine-entry-tool for the effective cmdline instead of parsing its configs --get-cmdline default answers whether root= survives the tool's own config merge, replacing the glob, grep and quote-aware tokenizer walk over the config layers, and the quote-aware /proc/cmdline parsing reverts to plain word splitting. The verification and the reboot gate stay: they are what catches anything the simpler paths miss. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: David Heinemeier Hansson <david@hey.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
bb8d2f2cb3 |
Split agent usage into data files and rename the plugin to omarchy.agents (#6603)
* Add agent usage collectors that write display-ready data files
One omarchy-agent-usage-scan-<agent> collector per AI coding agent prints a
complete display-ready usage record — identity, tier, status, rate limits,
and today/week/all-time stats. omarchy-agent-usage-update runs every
collector it finds and writes the records atomically to
~/.local/state/omarchy/agents/usage/, so anything that displays usage only
ever reads JSON from there.
The Claude collector absorbs what the shell previously did in-process:
transcript scanning, the stats-cache/history fallback, credentials parsing,
and the OAuth limits probe, now with a probe throttle and last-good limits
kept across network failures. The Codex collector is the existing scanner
reshaped to the shared record contract.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Redo the model-usage plugin as omarchy.agents watching usage data files
The panel is now strictly a display. It discovers the JSON records that
omarchy-agent-usage-update maintains under
~/.local/state/omarchy/agents/usage/, watches them for changes, and draws
whatever appears — so adding an agent means shipping a collector, never
touching the panel. Marks resolve by convention (assets/<id>.svg with an
optional -light twin), the limits meters read a generic limits array, and
the per-provider QML adapters and in-plugin scanner scripts are gone.
Cross-device sync aggregation stays in the shell and keeps the snapshot
field names older versions wrote, so mixed-version fleets still merge in
both directions.
With the provider fan-out gone, the widget takes its real name: the plugin
id becomes omarchy.agents. A migration renames it wherever a user's config
mentions it — layout entries keep their settings and position, a disabled
widget stays disabled — then primes the data files once and drops the old
scanner cache. The migration test also drops a stale assertion that expected
migrations to restart the shell themselves, which
|
||
|
|
6ee243cc37 |
Split the end-user omarchy skill into topic guides (#6602)
* Split the end-user omarchy skill into topic guides Move default/omarchy-skill to default/agents/skills/omarchy and break the monolithic SKILL.md into on-demand topic files for Hyprland config, shell plugins, theming, and hooks. Update the skill symlink wiring, relink existing installs through a migration, and correct claims that had drifted from the implementation: plugin hot-reload, terminal reload, menu customization, refresh scopes, theme overlays, background locations, hook timing, and the packaged (not git-managed) system directory. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Add capture and contributing guides to the omarchy skill Cover screenshots, screen recording, OCR text capture, and LocalSend or Taildrop sharing, plus how to route bug reports, suggestions, and support questions upstream with diagnostics and captures of the problem attached. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Scope Hyprland reload guidance to the Lua config files hyprsunset.conf and xdph.conf are read by separate processes, so hyprctl neither applies nor validates them. Document restarting hyprsunset after editing its config, including in the night light example. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
018f881840 |
Extract the Wi-Fi QR share card into its own omarchy.wifiqr panel plugin (#6598)
* Extract the Wi-Fi QR share card into its own omarchy.wifiqr panel plugin omarchy-network-qr now leads with an iface/security/ssid meta line, so a bare summon self-detects the connection and the plugin owns the whole share flow. The network panel loses its overlay lifecycle: with no centered card left inside it, the shadowed open/close collapses back to the stock panel behavior, and the QR button just summons the plugin -- which a clone or third-party plugin can replace, like the speed test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Keep canceled QR and password runs from leaking into their replacements Copilot review: the cancellation guards dropped in onExited while the canceled run's collectors were still allowed to fire, so a stale stderr could shadow a successful regeneration and a stale password could be revealed under a new network's card. The guards now stay up until the next run launches, good output settles any earlier error, and a bare re-summon no longer inherits the previous card's SSID. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
bc75b03114 |
Show plugin ids as subtext in the plugin picker menus
Select-menu options gain an optional third field rendered under the label, filtered alongside it, and returned with the selection. The plugin picker uses it to show every plugin's id and act on the id the selection hands back, replacing the duplicate-name label suffix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
fd1034f71b | Ship NordVPN directly from OPR | ||
|
|
65541c7b4f | Remove obsolete weather status poller (#6555) | ||
|
|
b538dd545a |
Persist integer GDK_SCALE when monitor scale is fractional
GTK only honors whole-number GDK_SCALE values, so persisting 1.6 or 1.25 verbatim left GTK apps without a usable scale. Round to the nearest whole factor when writing monitors.lua. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
caeffdc27b |
fix: add bg/fg aliases for theme color resolution (#6546)
* fix: add bg/fg aliases for theme color resolution Themes define bg/fg but the template system expects background/foreground. The fallback chain only checked color0/color7, leaving background/foreground empty for themes using bg/fg naming. * Complete legacy theme palette compatibility --------- Co-authored-by: David Heinemeier Hansson <david@hey.com> |
||
|
|
40f92eabdf |
Launch apps in their own scope instead of the compositor's cgroup (#6541)
* Launch apps in their own scope instead of the compositor's cgroup
The launcher ran desktop entries through gtk-launch, so the app inherited
quickshell's cgroup, which belongs to wayland-wm@hyprland.desktop.service.
A kernel OOM kill there fails the compositor unit and tears down the whole
session, dropping the user at SDDM with every window lost. A single runaway
app took the desktop down three times in one afternoon.
Route launches through uwsm-app so each app gets its own scope under
app-graphical.slice. A runaway app now fails its own scope and the session
keeps running.
The post-install launches had the same inheritance bug in a milder form,
where the app landed in the installer terminal's scope and died with it.
|
||
|
|
3636c76e96 | Rely on the session PATH for agent launches | ||
|
|
f293e9df26 | Open agents after setting the default | ||
|
|
a7cc924a10 | Show agent installation progress in a terminal | ||
|
|
2324851da1 | Fall back to OpenCode in agent launcher |