* Accept either name for the lock authentication command
omarchy-setup-lock was renamed to omarchy-apply-lock in 536fcd5c, but
the upgrade calls into whatever the channel just installed, and every
released package still ships the old name. The rename only moves in
lockstep for the ISO, which installs the runtime from the mirror it
ships with; the upgrade has no such guarantee, so it aborted every run
with "omarchy-apply-lock is unavailable" right before the point of no
return.
Prefer the new name and fall back to the old one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Leave the Omarchy 3 session alone until the reboot
The upgrade tried to start Quickshell in the live session, and only
stopped waybar/walker/elephant if that worked. Every branch of it could
fail, so it needed a warning for each, and those warnings were the first
thing users read at the end of an upgrade that had otherwise succeeded.
The reboot is the cutover. Swapping the UI out underneath a running
session buys nothing, so drop the attempt and both functions with it.
The Omarchy 3 bar, launcher, and notifications keep working until the
reboot, which is what happened anyway whenever the start failed.
Also warn up front when the live Hyprland session cannot be reached, and
drop the package_mode label that was set on both branches of the
dev-package check and never read.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Shim the legacy Hyprland defaults from the backup, not from GitHub
populate_legacy_hypr_defaults tried a sparse git clone of master, then a
curl of the master tarball, and only if both failed the backup taken a
few lines earlier. That backup is the checkout the running session is
sourcing right now: it is the correct content, it is already on disk,
and it needs no network in the middle of an upgrade. master is a guess
that is wrong for any machine not on master.
Try the backup first and drop the git clone, which fetched the same
thing as the tarball by a longer route. The network path stays for the
case that has no backup, where the legacy root was already a symlink.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Clear the Hyprland error bar the upgrade leaves behind
The two settings were applied through both the keyword and the Lua API,
in four calls on the way out and three on the way in, split differently
each time. Fold that into one helper that takes the value.
The error bar needed more than suppression. An explicit hyprctl reload
re-reads the config from disk, which resets both keywords before it
reports what it found, so suppression cannot survive one; anything that
reloaded during the swap left the bar on screen. Hyprland then keeps it
up until a later clean reload, which this script deliberately never
performs, so it was still there when the upgrade finished. Clear the
overlay on the way out, once the shims have made the legacy config
resolve again.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Run the packaged firewall config instead of a copy of it
configure_snapper_policy and configure_lock_authentication already call
into the installed tree; apply_firewall_defaults reimplemented
install/config/firewall.sh inline instead, and had already drifted from
it. The packaged script also installs the ufw-docker rules, so upgraded
machines came up without the Docker firewall protections a fresh install
gets.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Stop the Voxtype toggle migration reloading a mid-swap session
This is the reload behind the "source= globbing error" bar users see
during a Quattro upgrade. The upgrade runs the packaged migrations
against a still-running Omarchy 3 session, and this one ends with
hyprctl reload. That re-parses a legacy config whose theme source= has
nothing to resolve to yet, so Hyprland paints an error bar and keeps it
up until a later clean reload the upgrade deliberately never performs.
It was still on screen when the upgrade finished.
The upgrade already exports OMARCHY_UPGRADE_TO_QUATTRO_LIVE for exactly
this, and 1782002156 honors it. Do the same here. Nothing in that
session reads the toggle being removed; the reboot applies it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Assert the retired session entry points stay gone
The ordering check would still pass if either came back, while the
comment above it claims they cannot. Name them.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Upgrade onto the channel the machine is already on
The upgrade always defaulted to stable, so an rc machine taking it
landed on production packages from the stable repo. rc callers worked
around that by passing --channel rc, which then forced every caller
onto rc, stable machines included.
Read the channel off the mirrorlist the way omarchy-version-channel
does and follow it: stable machines get omarchy and omarchy-settings
from stable, and rc or edge machines get omarchy-dev and
omarchy-settings-dev from edge, which is what --dev already selects.
An explicit --channel or --dev still wins, and an unrecognized
mirrorlist still falls back to stable.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Keep rc machines on the rc mirror when taking dev packages
--dev forced the edge channel, so an rc machine following its own
channel was moved onto the edge Arch mirror as well. The constraint is
narrower than that: the dev packages are only published to the edge
package repo, which the rc and edge channels both already point at.
Only stable is incompatible.
Reject --dev only for stable, and default to edge just when no channel
was chosen. rc machines now upgrade against rc-mirror with the dev
packages out of the edge repo, which is where Quattro lives until it
ships.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
setup is where a user goes to configure something: direct boot, security
keys, hibernation. These three are not that. omarchy-apply-system is the
ISO's entry point in the target chroot, omarchy-apply-hardware is what it
calls for device quirks, and omarchy-apply-lock is called by
install/config/lockscreen-pam.sh.
apply is the verb they already used to describe themselves, and it carries
the contract: declared state under install/ converged onto the machine,
idempotent, safe to repeat.
The group gets no GROUP_DESCRIPTIONS entry on purpose. That table drives the
top-level group list on its own, so an entry would put apply back in front of
users even with every command in it hidden, the way provision already stays
out. A test covers it.
The ISO installs the runtime from the mirror it ships with, so it moves to
the new names in lockstep and no compatibility route is needed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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>
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>
* 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>
* 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>
* 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>
* 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>
pacman checks file conflicts during transaction prepare, so the --overwrite
entry added alongside /etc/systemd/zram-generator.conf never got to run: the
copy of omarchy-update-system-pkgs driving the upgrade is the one already on
disk. Every machine carrying archinstall's copy aborted the transaction.
zram-generator.conf(5) reserves /etc for the local admin and has vendors ship
snippets under /usr/lib/systemd/zram-generator.conf.d/, where drop-ins outrank
the main config file. Nothing collides, and the tuning wins whether or not
archinstall's file is still around.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LjeyQZsNBxqyYy9z8KaKm7
It was the user override file for the first Quickshell bar, back when the
bar layered it over bar-defaults.json. Unifying everything into
shell.json left an empty file that installs and the quattro upgrade kept
faithfully copying around.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Omarchy installed zram-generator but never shipped a config for it, so the
only zram tuning any machine had was whatever the ISO wrote once, and the VM
sysctls were untouched kernel defaults aimed at spinning disks.
The generator's own default caps the device at 4G, which on a large machine
sends reclaim to the hibernation swapfile far earlier than it needs to go.
Ship min(ram / 2, 8192) instead, matching what Fedora settles on, and state
the priority explicitly since it has to sit above the pri=0 that
omarchy-hibernation-setup gives the disk swapfile.
The four sysctls follow from swap being RAM rather than a disk. swappiness
above 100 says evicting an anonymous page beats dropping a page-cache page
that would have to be read back, which is true once swap is compressed
memory. page-cluster drops to one page per fault because the default of 8
buys readahead for a seek zram doesn't have and pays a decompression for
each page. Zeroing watermark_boost_factor stops fragmentation from producing
reclaim bursts while memory is still free, and raising watermark_scale_factor
gives kswapd room to reclaim in the background instead of letting allocations
stall in direct reclaim. The last two are what actually addresses the stutter
people notice and misread as swap being used too eagerly: proactive swapping
to zram is the cure, and synchronous direct reclaim is the disease.
Every ISO-installed machine already has an unowned zram-generator.conf, which
pacman would refuse to overwrite, so both upgrade paths need it listed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Suppression was enabled only after cleanup_legacy_user_paths had already
moved ~/.local/share/omarchy aside, so the live session could auto-reload
during the swap window and pop "source= globbing error: found no match"
for every legacy hyprland.conf source line. Enable suppression as the
first step of the upgrade sequence instead; the EXIT trap still restores
it if the upgrade dies early.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Extract run_as_user_omarchy and run_as_user_wayland_session helpers to
replace ten hand-rolled run_as_user env blocks
- Declare the retired user-unit list once instead of three times
- Use git ls-files --others to find user-added theme backgrounds instead
of diffing against the tracked list by hand
- Stop rewriting the SDDM 10-theme/10-wayland confs the omarchy package
already installs, and drop the duplicate [Theme] section from
99-omarchy-login.conf
- Drop the legacy-path rewrite in the theme hyprland.conf shim; the user
transition already rewrote those references
- Remove dead code: the unreachable channel re-validation, the declare -F
guard in cleanup_on_exit, and the unset block at the end of the
user-transition script
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The user-transition script is fed to bash on stdin, so the browser-close
gum confirm read the script itself: it auto-declined and swallowed the
remaining script text, leaving bash to fail on a mid-construct syntax
error. The outer confirm and reboot prompts had the same exposure when
the script runs via curl | bash. Read all three from /dev/tty.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Copy URL shortcut repair checked the outer script's yes variable,
which never reached the user-transition heredoc's bash process, so the
upgrade died with "yes: unbound variable" under set -u whenever a
browser was running with the old extension id in its Preferences.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
omarchy-restart-shell now kills by config dir via quickshell kill and
relaunches with --no-duplicate, polling kill until every instance is
gone since kill returns without waiting and -n silently exits if one
remains. The locked-session refusal reads Hyprland monitor state alone,
which covers a hung shell holding the lock; the redundant shell IPC
probe, availability guards, and omarchy-shell path indirection are gone.
Shell IPC calls now time out (2s default, OMARCHY_SHELL_IPC_TIMEOUT to
override) so probing an unresponsive shell fails fast instead of
hanging the caller.
omarchy-hyprland-launch checks dispatch output for "ok" rather than the
exit code, which is 0 even on Lua errors, so a failed dispatch falls
through to the bash -lc fallback instead of silently launching nothing.
The Quattro upgrade cutover delegates to omarchy-restart-shell instead
of carrying its own copy of the lock check, pkill, and readiness loop.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Existing quattro installs get sof-firmware, the Mesa Vulkan drivers,
the tmux terminal-features and pane-binding fixes, and the XPS 13 text
scaling via migration, while Omarchy 4 upgraders get the same hardware
support and scaling through omarchy-upgrade-to-quattro.
The Vulkan driver backfill adapts da46ad85 from master.
Co-authored-by: Sai Sridhar <tarrasridhar1154@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Copy URL extension was intermittently failing to copy anything, and
its notification looked oversized with no icon. Several distinct problems:
- The MV3 service worker was pinned to stale cached code. Chromium caches
the worker script for a --load-extension command-line extension and does
NOT re-register it when the file changes in place — not on restart, not on
a manifest version bump, not even after a clean shutdown. So updated code
never took effect: the old worker kept calling chrome.scripting.executeScript,
which throws once the scripting permission is gone, and the copy silently
failed. Renaming the worker to a versioned filename (background-2.js) is a
new script URL, which forces a fresh registration for everyone — new
installs and existing installs alike. Rename it again on any future worker
change (see the note at the top of background-2.js).
- Clipboard writes now go through an offscreen document (MV3's sanctioned
path) using a textarea + execCommand('copy'), replacing executeScript +
navigator.clipboard. This works on chrome:// pages and needs no scripting
permission. execCommand is used deliberately: navigator.clipboard.writeText
rejects in an unfocused offscreen document.
- Add a toolbar action (chrome.action.onClicked) so the extension is
clickable, not keyboard-only — it was greyed out in the extensions menu
with nothing to invoke.
- Slim the "URL copied" notification: lead the summary with a glyph so the
omarchy notification shell collapses it to a single-line toast with an
icon, instead of an oversized card with a blank icon slot.
- Guard the Quattro shortcut-repair migration: it edits Chromium Preferences
to move the Alt+Shift+L binding to the new extension id, but a running
browser rewrites Preferences on exit and reverts the edit. Prompt (via gum)
to close the browser first, only when a browser is running and there is
actually a stale binding to repair.
The trailing slash from the themes/*/ glob put a double slash in the
path comparison, so stock backgrounds never matched git ls-files output
and were all moved into ~/.config/omarchy/backgrounds.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
With dotglob set, * already matches dotfiles, so the extra dot patterns
made the second ln -s fail and silently skip the legacy hypr shim.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Legacy repos cached omarchy packages under the same name and version as
quattro rebuilds with different bytes, so pacman aborted --noconfirm
transactions with checksum errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>