From 1caa2c98f0def2e17a5c5ca9b4d9cfc6c281105b Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Fri, 23 Oct 2026 13:23:08 -0700 Subject: [PATCH] Detach install.sh's app relaunch so it survives byre's restart --- AGENTS.md | 4 ++-- mac/install.sh | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 702677c..62efc99 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,9 +14,9 @@ A deploy is a release that isn't uploaded: the same notarized disk image, instal 1. Before anything else, write the release notes for everything on main since the last release tag (`git describe --tags --abbrev=0` names it), for a byre user in the "Releasing" shape (`## New` and `## Fixed`, each a bullet with a bold short name and what it does or what now works; no `## Install`). Read `git diff ..HEAD`, not just the commit subjects, and leave out changes no user sees. Once the installs start, nothing may sit between one step and the next, so the notes are done by then. 2. Run `mac/deploy.sh`. It runs `mac/package.sh` (the build, both notarizations and the disk image, as for a release, into `mac/.build/release//`), builds the iPhone app with `mac/phone.sh` and uploads it to TestFlight (`docs/iphone.md`), and copies the disk image and `mac/install.sh` to `~/byre-deploy/byre.dmg` and `~/byre-deploy/install.sh`. That copy stays there for installing by hand on Macs that aren't connected. It installs nothing. -3. Sort the client Macs `list_clients` shows (leaving out the iPhone) by whether they run a byre server of their own: one does when `launchctl print gui/$(id -u)/run.fc.byre` exits 0 there (`client_bash`). Then, without asking first, update every one that runs no server, all in parallel (one batch of tool calls): upload `~/byre-deploy/byre.dmg` and `~/byre-deploy/install.sh` to the same paths there (`client_upload`), then run `~/byre-deploy/install.sh ~/byre-deploy/byre.dmg` there through `client_bash`. It installs, prints the build number and the commit, then quits the app if it is running and reopens it on the new build, which ends the `client_bash` call as the client disconnects while the script carries on. Don't wait for these Macs to reconnect: after a protocol change the new app can't reach the old servers, so each one stays broken until the servers are updated. They must be updated before any server restarts, since an old client may be unable to reach a new server to be updated. +3. Sort the client Macs `list_clients` shows (leaving out the iPhone) by whether they run a byre server of their own: one does when `launchctl print gui/$(id -u)/run.fc.byre` exits 0 there (`client_bash`). Then, without asking first, update every one that runs no server, all in parallel (one batch of tool calls): upload `~/byre-deploy/byre.dmg` and `~/byre-deploy/install.sh` to the same paths there (`client_upload`), then run `~/byre-deploy/install.sh ~/byre-deploy/byre.dmg` there through `client_bash`. It installs, prints the build number and the commit, and returns; a detached job it leaves behind then quits the app if it is running and reopens it on the new build, so the client disconnects a moment later. Don't wait for these Macs to reconnect: after a protocol change the new app can't reach the old servers, so each one stays broken until the servers are updated. They must be updated before any server restarts, since an old client may be unable to reach a new server to be updated. 4. Immediately after, update every client Mac that runs a server the same way, in parallel. Its server sees its executable replaced and restarts on the new build. -5. Immediately after that, install on the Mac you run on with `mac/install.sh ~/byre-deploy/byre.dmg`. The service runs `/Applications/Byre.app/Contents/Helpers/byre`; within 5 seconds it sees that file replaced and exits, and launchd starts the new server and `byre-hands`. Everything is signed with Developer ID, so the macOS privacy grants (Screen Recording, Accessibility, Automation) survive. `install.sh` relaunches its app if it is running, and leaves it closed if not. +5. Immediately after that, install on the Mac you run on with `mac/install.sh ~/byre-deploy/byre.dmg`. The service runs `/Applications/Byre.app/Contents/Helpers/byre`; within 5 seconds it sees that file replaced and exits, and launchd starts the new server and `byre-hands`. Everything is signed with Developer ID, so the macOS privacy grants (Screen Recording, Accessibility, Automation) survive. `install.sh` relaunches its app if it is running, and leaves it closed if not; the relaunch runs in its own process group, so it survives byre killing the `bash` call when the server exits. 6. Confirm it came up: read the tail of `~/Library/Logs/byre.log`, and `GET /api/tailnet` at the loopback address (`byre check` prints it as `loopback`), whose `state` must be `Running`. Check that `list_clients` shows every updated Mac back on the new build and commit. Report the new build number first (`plutil -extract CFBundleVersion raw /Applications/Byre.app/Contents/Info.plist` prints it; it is the Unix time of the build, and the iPhone build uploaded to TestFlight has its own, a few minutes later), then what you deployed and what you checked, and end with the release notes from step 1. Deploying means building with `mac/deploy.sh` on the Mac you run on. Never stand in for it by running `mac/package.sh` yourself, not even to build once for several Macs. Every Mac, this one included, gets the disk image `mac/deploy.sh` left in `~/byre-deploy/`. diff --git a/mac/install.sh b/mac/install.sh index 27b64eb..4e71817 100755 --- a/mac/install.sh +++ b/mac/install.sh @@ -12,9 +12,13 @@ plutil -extract CFBundleVersion raw /Applications/Byre.app/Contents/Info.plist plutil -extract ByreCommit raw /Applications/Byre.app/Contents/Info.plist app='^/Applications/Byre.app/Contents/MacOS/Byre$' if pgrep -q -a -f "$app"; then - osascript -e 'tell application id "run.fc.byre.mac" to quit' - while pgrep -q -a -f "$app"; do - sleep 0.2 - done - open /Applications/Byre.app + # Job control puts the relaunch in its own process group, out of reach when byre kills this script's group on restart. + set -m + ( + osascript -e 'tell application id "run.fc.byre.mac" to quit' + while pgrep -q -a -f "$app"; do + sleep 0.2 + done + open /Applications/Byre.app + ) /dev/null 2>&1 & fi