Make the Copy URL extension reliable across install and upgrade

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.
This commit is contained in:
David Heinemeier Hansson
2026-07-17 16:28:18 -07:00
parent 182330465a
commit 28d853402e
7 changed files with 135 additions and 27 deletions
+23 -3
View File
@@ -1716,6 +1716,11 @@ CHROMIUM_FLAGS_PATCH_PY
done
}
# True if any Chromium-family browser that stores the Copy URL shortcut is running.
browser_is_running() {
pgrep -x 'chromium|chrome|brave|msedge|vivaldi-bin|vivaldi|opera|helium' >/dev/null 2>&1
}
repair_chromium_copy_url_shortcuts() {
local profile_root preferences
local -a profile_roots=(
@@ -1730,6 +1735,7 @@ repair_chromium_copy_url_shortcuts() {
"$HOME/.config/opera"
"$HOME/.config/helium"
)
local -a pending=()
for profile_root in "${profile_roots[@]}"; do
[[ -d $profile_root ]] || continue
@@ -1737,8 +1743,23 @@ repair_chromium_copy_url_shortcuts() {
for preferences in "$profile_root"/*/Preferences; do
[[ -f $preferences ]] || continue
grep -qF 'bocglpkldciamkbmlphanhkfnhpmnbma' "$preferences" || continue
pending+=("$preferences")
done
done
python3 - "$preferences" "$preferences.omarchy-upgrade-to-quattro.$BACKUP_SUFFIX.bak" <<'CHROMIUM_SHORTCUTS_PATCH_PY'
(( ${#pending[@]} )) || return 0
# A running browser holds Preferences in memory and rewrites it on exit,
# which would revert this repair. Ask the user to close it first.
if browser_is_running && (( ! yes )) && [[ -r /dev/tty ]]; then
if ! gum confirm "Close all browser windows before the Copy URL shortcut is repaired, then continue"; then
echo "Skipped Copy URL shortcut repair; re-run after closing your browser." >&2
return 0
fi
fi
for preferences in "${pending[@]}"; do
python3 - "$preferences" "$preferences.omarchy-upgrade-to-quattro.$BACKUP_SUFFIX.bak" <<'CHROMIUM_SHORTCUTS_PATCH_PY'
import json
import shutil
import sys
@@ -1768,7 +1789,6 @@ if changed:
shutil.copy2(path, backup_path)
path.write_text(json.dumps(preferences, separators=(",", ":")))
CHROMIUM_SHORTCUTS_PATCH_PY
done
done
}
@@ -1935,7 +1955,7 @@ repair_sleep_lock_unit_override
install_bash_startup
unset rel file backup retired_config_files always_copy_config_files uwsm_env known_config_default_hashes_by_key
unset -f file_sha256 known_config_default_hashes default_hash_paths is_known_default_hash backup_config_file migrate_uwsm_env_customizations is_retired_config_file copy_config_default copy_missing_config_defaults refresh_known_config_defaults mark_removed_preinstalls_from_legacy_bindings copy_always_config_defaults repair_chromium_copy_url_extension_flags repair_chromium_copy_url_shortcuts repair_sleep_lock_unit_override is_known_bashrc_default install_bash_startup
unset -f file_sha256 known_config_default_hashes default_hash_paths is_known_default_hash backup_config_file migrate_uwsm_env_customizations is_retired_config_file copy_config_default copy_missing_config_defaults refresh_known_config_defaults mark_removed_preinstalls_from_legacy_bindings copy_always_config_defaults repair_chromium_copy_url_extension_flags browser_is_running repair_chromium_copy_url_shortcuts repair_sleep_lock_unit_override is_known_bashrc_default install_bash_startup
mkdir -p "$HOME/.agents/skills" "$HOME/.claude/skills" "$HOME/.codex/skills" "$HOME/.pi/agent/skills"
if [[ -d $root/default/omarchy-skill ]]; then