From e546fee9aa3ed15739c8fc5b7eaa1c5f235cee7b Mon Sep 17 00:00:00 2001 From: Eduardo Date: Fri, 2 Oct 2026 18:55:19 +0900 Subject: [PATCH] Clarify the first-run package update invitation --- guest/README.md | 9 ++ .../first-run-update-notification.patch | 16 ++++ guest/spec.json | 14 +++ guest/tests/fixtures/first-run-wifi.sh | 30 +++++++ .../test_first_run_update_notification.py | 86 +++++++++++++++++++ guest/tests/verify.py | 1 + 6 files changed, 156 insertions(+) create mode 100644 guest/patches/omarchy/first-run-update-notification.patch create mode 100644 guest/tests/fixtures/first-run-wifi.sh create mode 100644 guest/tests/test_first_run_update_notification.py diff --git a/guest/README.md b/guest/README.md index bd2fd94d..2d55a15a 100644 --- a/guest/README.md +++ b/guest/README.md @@ -112,6 +112,15 @@ direct-boot kernel and matching headers are held, while the packaged repository. A separate migration channel is required before those Try-Omarchy-specific revisions can advance on an existing disk without reset. +New guests show a normal-priority first-login **Update packages and finish setup** +invitation: "Update supported Linux packages and discover optional features such +as dictation." It launches the Omarchy updater once networking is ready, without +claiming that updates are available or that the pinned runtime and boot files +can advance. The reviewed `first-run-update-notification` patch changes only +that invitation when the Try Omarchy build spec is present. Wi-Fi setup, welcome +and other notifications, the update indicator, and user-initiated update commands +remain available. + The kernel reboot check recognizes package-owned `modules.builtin` metadata as well as `vmlinuz` under `/usr/lib/modules//`. Arch Linux ARM does not place `vmlinuz` there, so requiring that file alone produces a false kernel-update diff --git a/guest/patches/omarchy/first-run-update-notification.patch b/guest/patches/omarchy/first-run-update-notification.patch new file mode 100644 index 00000000..5345cd94 --- /dev/null +++ b/guest/patches/omarchy/first-run-update-notification.patch @@ -0,0 +1,16 @@ +diff --git a/install/user/first-run/wifi.sh b/install/user/first-run/wifi.sh +--- a/install/user/first-run/wifi.sh ++++ b/install/user/first-run/wifi.sh +@@ -1,4 +1,12 @@ + notify_update() { ++ # Try Omarchy's updater handles supported packages and optional first-run setup. ++ if [[ -f /usr/share/try-omarchy/build-spec.json ]]; then ++ omarchy-notification-send -u normal -g  "Update packages and finish setup" \ ++ "Update supported Linux packages and discover optional features such as dictation." \ ++ --exec omarchy-launch-floating-terminal-with-presentation omarchy-update ++ return 0 ++ fi ++ + omarchy-notification-send -u critical -g  "Update System" "Click to update the system." \ + --exec omarchy-launch-floating-terminal-with-presentation omarchy-update + } diff --git a/guest/spec.json b/guest/spec.json index c575571e..8038b9b8 100644 --- a/guest/spec.json +++ b/guest/spec.json @@ -383,6 +383,20 @@ } ] }, + { + "id": "first-run-update-notification", + "description": "Clarify the first-login invitation for supported package updates and optional setup in the pinned Try Omarchy guest.", + "reference": "https://github.com/basecamp/omarchy/blob/c668141e9c42b13c80c9ca4ea108e11708c5e8a5/install/user/first-run/wifi.sh", + "patch": "patches/omarchy/first-run-update-notification.patch", + "patchSha256": "05d95049f1a6dd3efaa59c429d6922835e1c54b1d3b0286db30378f60eb7847f", + "targets": [ + { + "path": "install/user/first-run/wifi.sh", + "beforeSha256": "4cc2621157be1efe6d449d1daa7b28d588e4a8e46127de493da03749af1ae5a7", + "afterSha256": "cbbffcfd2685c0b9853ee144a7acba64dfa9340cc65a3d144a925055810f0f66" + } + ] + }, { "id": "pkg-add-aarch64-unavailable", "description": "Refuse known aarch64-unavailable packages from omarchy-pkg-add with the shared message.", diff --git a/guest/tests/fixtures/first-run-wifi.sh b/guest/tests/fixtures/first-run-wifi.sh new file mode 100644 index 00000000..3b2af23a --- /dev/null +++ b/guest/tests/fixtures/first-run-wifi.sh @@ -0,0 +1,30 @@ +notify_update() { + omarchy-notification-send -u critical -g  "Update System" "Click to update the system." \ + --exec omarchy-launch-floating-terminal-with-presentation omarchy-update +} + +notify_wifi() { + omarchy-notification-send -u critical -g 󰖩 "Setup Wi-Fi" "Click to configure the wireless network." \ + --exec omarchy-shell shell toggle omarchy.network +} + +announce_network() { + # Ethernet is still negotiating DHCP when the session starts, so probing + # right away calls a working machine offline. NetworkManager reports startup + # complete once it has tried every connection it could auto-activate, which + # is the first moment the answer means anything. + nm-online -q -s -t 30 + + # -x takes that answer as it stands rather than waiting out the timeout, so + # a laptop with nothing to connect to gets prompted immediately. + if ! nm-online -q -x -t 30; then + notify_wifi + # Nothing to update against until a link lands, so hold that prompt. + nm-online -q -t 3600 || return + fi + + notify_update +} + +# Detached, so a slow or absent connection never holds up the rest of first run. +announce_network & diff --git a/guest/tests/test_first_run_update_notification.py b/guest/tests/test_first_run_update_notification.py new file mode 100644 index 00000000..0e8ee782 --- /dev/null +++ b/guest/tests/test_first_run_update_notification.py @@ -0,0 +1,86 @@ +from __future__ import annotations + +import importlib.util +import json +import os +from pathlib import Path +import subprocess +import tempfile +import unittest + + +GUEST = Path(__file__).resolve().parents[1] +MODULE = importlib.util.spec_from_file_location( + "backports", GUEST / "scripts/apply-omarchy-backports.py" +) +backports = importlib.util.module_from_spec(MODULE) +MODULE.loader.exec_module(backports) + + +class FirstRunUpdateNotificationTests(unittest.TestCase): + def run_first_run(self, *, try_omarchy=True, online=True, reconnect=True): + with tempfile.TemporaryDirectory() as temporary: + root = Path(temporary) + spec = json.loads((GUEST / "spec.json").read_text()) + backport = next(b for b in spec["authenticity"]["backports"] + if b["id"] == "first-run-update-notification") + omarchy = root / "usr/share/omarchy" + command = omarchy / backport["targets"][0]["path"] + command.parent.mkdir(parents=True) + command.write_bytes((GUEST / "tests/fixtures/first-run-wifi.sh").read_bytes()) + backports.apply_backport(GUEST, root, omarchy, backport) + marker = root / "build-spec.json" + if try_omarchy: + marker.touch() + # Execute the complete first-run script, redirecting only its guest + # identity check and stubbing network and desktop side effects. + script = command.read_text().replace( + "/usr/share/try-omarchy/build-spec.json", str(marker) + ) + stubs = ''' +nm-online() { + case "$*" in + *"-s"*) return 0 ;; + *"-x"*) return "$OFFLINE" ;; + *) return "$NO_RECONNECT" ;; + esac +} +omarchy-notification-send() { printf '%s\n' "$*"; } +''' + result = subprocess.run( + ["bash", "-c", stubs + script + "\nwait\n"], + env={**os.environ, "OFFLINE": str(int(not online)), + "NO_RECONNECT": str(int(not reconnect))}, + text=True, capture_output=True, check=True, timeout=5, + ) + return result.stdout + + def test_online_guest_invites_package_updates_and_optional_setup(self): + self.assertEqual( + self.run_first_run(), + "-u normal -g  Update packages and finish setup " + "Update supported Linux packages and discover optional features such as dictation. " + "--exec omarchy-launch-floating-terminal-with-presentation omarchy-update\n", + ) + + def test_wifi_invitation_survives_reconnection(self): + output = self.run_first_run(online=False) + self.assertIn("Setup Wi-Fi", output) + self.assertIn("omarchy-shell shell toggle omarchy.network", output) + self.assertIn("Update packages and finish setup", output) + self.assertNotIn("Update System", output) + + def test_offline_guest_still_invites_wifi_setup(self): + output = self.run_first_run(online=False, reconnect=False) + self.assertIn("Setup Wi-Fi", output) + self.assertNotIn("Update packages and finish setup", output) + self.assertNotIn("Update System", output) + + def test_non_try_omarchy_keeps_upstream_invitation(self): + output = self.run_first_run(try_omarchy=False) + self.assertIn("Update System", output) + self.assertIn("omarchy-launch-floating-terminal-with-presentation omarchy-update", output) + + +if __name__ == "__main__": + unittest.main() diff --git a/guest/tests/verify.py b/guest/tests/verify.py index f2462a5b..41c67da4 100755 --- a/guest/tests/verify.py +++ b/guest/tests/verify.py @@ -186,6 +186,7 @@ def main() -> None: "notification-screen-privacy", "update-free-space-message", "update-restart-arm-kernel", + "first-run-update-notification", "pkg-add-aarch64-unavailable", "pkg-aur-add-aarch64-unavailable", "dropbox-aarch64-unavailable",