Repository navigation
LOCAL: update SwapLabs macOS builds in place with a verified self-signed installer - #16
Conversation
|
Review complete. 🟠 1 high 💬 Inline comments (1)
Reviewed commit: b5e0e67 |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b5e0e67969
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Review complete. 🟡 2 medium 💬 Inline comments (2)
Reviewed commit: 2b75969 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2b759695e8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Review complete. 🟡 1 medium 💬 Inline comments (1)
Reviewed commit: 1f63026 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1f630262c7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ned installer Squirrel.Mac refuses a bundle without upstream's Developer ID requirement, so a SwapLabs build on macOS now updates through Orca's own installer. The pinned tag's Ed25519-signed manifest is verified against the compiled-in ORCA_SWAPLABS_UPDATE_PUBLIC_KEY, the zip against its size and sha512, and the unpacked bundle with codesign --deep --strict, its Info.plist identity and version, and the running app's designated requirement, before a static /bin/sh helper swaps the bundles after quit, relaunches, and rolls back when no health marker appears within 90 s. The next launch reports the outcome. The engine speaks electron-updater's events and surface, so the updater state machine, cards, buttons, nudges and the quit-and-install sequence are unchanged. Without the key, or on any other platform or source, nothing changes except that a fork build's own next macOS build is now a manual download (D4) rather than a Squirrel install that would fail. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…failures PR #16 review round 1. - Run the update download through a stream pipeline so a full or unwritable disk rejects the download (retryable, partial file removed) instead of an unhandled write-stream error crashing the main process. - Cut off manifest and signature reads at their byte caps while the body streams, instead of buffering the whole response before checking. - Relaunch the previous bundle when the helper fails before or during the swap (staged bundle missing, no rollback folder, either rename refused), so a failed update never leaves Orca closed; the supervisor case still only reports. - Refuse "Check for local build" before its file dialog while the self-updater is active: the loopback latest-mac.yml feed cannot pass the signed-manifest check, and a local build never carries the release identity. - Name the injected Electron net.fetch dependency `fetchAsset` so the global-fetch audit no longer sees a bare fetch call; production wiring is unchanged (net.fetch in mac-self-update-activation.ts). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… rollback from breaking the mac self-updater PR #16 review round 2. - Revalidate the offer when a download finishes staging: a check that completed meanwhile and found another build now fails the download as `offer-superseded` (retryable, pointing at the newer release page) and discards the staging directory, instead of leaving the replaced build staged for Restart. A failed check or one that finds the same build discards nothing. - Compare builds by version and sha512, so a release cut again under the same version also drops the bundle staged from the earlier cut. - Listen for the helper child's `error` event. Node reports a refused spawn (EAGAIN, EMFILE, EACCES, ENOENT) as a pid-less child whose error fires a tick later; unheard it was an uncaught exception in the main process. The cause is recorded as `mac_self_update_helper_spawn_error`. - Stop the helper with `rollback-dir-failed` and relaunch the untouched app when the previous rollback cannot be removed: `mv` onto the surviving directory nested the installed bundle inside it, so a later rollback restored a directory with no executable at the bundle path. - Document that the small-asset deadline covers the body as well as the headers, and pin how a body cut off by it is reported. Electron's net.fetch errors the body when its signal aborts, so no timer was added. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1f63026 to
e32e345
Compare
|
Review complete. 🟠 1 high 💬 Inline comments (1)
🧹 Nitpicks (2) — 🟢 2 low
Reviewed commit: e32e345 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e32e345f9a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…and its refusals honest Helper (real /bin/sh tests, each failing on the old script): - every restore of the previous bundle runs only into an empty app slot; a move-aside that leaves the slot occupied reports rollback-blocked and relaunches the occupant instead of nesting the good bundle inside it, and a restore that fails into an empty slot reports rollback-failed - the staged move is skipped, and the previous bundle restored, when something reoccupied the slot between the two renames - the unhealthy build is stopped with TERM then KILL and the helper waits for it to be gone before it swaps and relaunches, so the relaunch cannot hand off to a process that still owns the single-instance lock - outcomes are reported before the relaunch, so the relaunched app finds them Updater state machine: - a download the engine refused as superseded no longer ends in an error card whose Retry could be dead; the engine rejects without an error event and the download handler answers with a fresh user-initiated check that re-offers the newer build, in both event orderings - a pinned jump the engine refuses keeps its manual-install page, retry verdict and release source when the check's rejection repeats the error event's status - reading the previous launch's failure for the updater card no longer writes the health marker, so a 15 s crash-loop setup fallback cannot certify a build whose window never showed - the staged bundle's version check fails closed on an unparseable or empty CFBundleShortVersionString Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Review complete. 🟡 2 medium 💬 Inline comments (2)
Reviewed commit: 501a015 |
|
Rebased onto Helper rollback can no longer nest a bundle inside another (
A superseded download re-offers the newer build instead of a dead Retry (
Pinned refusals keep their presentation ( Launch failure lookup is read-only ( Bundle version check fails closed ( Gates: 🤖 Generated with Claude Code |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 501a015c50
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ses and keep a settled check's retry verdict The readiness preflight read a SwapLabs self-update manifest whole before anything about it was checked, so an oversized asset could exhaust the main process before the installer's own 64 KiB cap ever ran. It now streams the manifest through the shared bounded reader under that same cap and answers 'not-ready' the moment the limit is passed, cancelling the body. The dev picker listed a fork release as installable on the strength of its manifest alone. The installer fetches the zip, the manifest and its signature, so a release caught between uploads (or with one asset removed by hand) became a row that 404s on selection. The picker now requires all three, from one shared asset list, and the preflight's stale upload-order comment is gone. sendSettledCheckStatus rebuilt an error status from its message, dropping a retry verdict that had no manual-install page beside it. sendErrorStatus now takes the presentation itself, every settled error hands its own through, and the repeat guard compares the verdict too. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Review complete. No issues found — approved ✅. Adds a SwapLabs-fork macOS self-update pipeline (signed-manifest Ed25519 verification, size-capped verified download, staged bundle validation, launch-outcome reporting) wired into the existing updater state machine, plus cross-source install-mode rules and tests. Reviewed commit: 046d645 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 046d645fb7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…k while the new build lives and probe beside the app before staging Review round 5 on the macOS self-updater. - Release list: on a build Orca's own installer updates, a release is listed only when the slice's zip, manifest and signature are attached. The platform rule (`latest-mac.yml`) used to be accepted as an alternative, so a release carrying it with an incomplete slice was offered and then failed the manifest preflight on selection. - Helper: the rollback now checks that the new build is off the process table after SIGTERM and SIGKILL. One that survives still holds the single-instance lock, so the helper leaves both bundles in place, relaunches nothing and records `new-app-still-running`. The check runs for a build that could not be launched as well as one that never reported healthy. - Engine: the writability probe runs before the staging folder is touched and is made in the folder holding the app, where the swap renames. A parent a non-admin user cannot write is refused as `app-location-unwritable` (not retryable, release page attached) instead of a raw EACCES from `mkdir`. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Review complete. 🟡 2 medium 💬 Inline comments (2)
🧹 Nitpicks (1) — 🟢 1 low
Reviewed commit: 348d5a3 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 348d5a301c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
A newer Tenki review found issues on this pull request.
… list by the installer in use and retry the health marker Review round 6 on the macOS self-updater. - Supervised `orca serve`: the helper used to exit right after the swap when the supervisor owned the relaunch, so a replacement that crashed or never sent `orca:serve-ready` stayed installed with the previous build in the rollback folder and the supervisor exited. The helper now reports `swapped` and keeps its health watch: the serving runtime writes the marker from `printServeReady` (the window path's 20 s fallback no longer certifies a headless launch), a `failed` phase in the serve handoff ends the wait at once (`supervisor-rejected`), the serve command line is matched when stopping the new build, and the rollback is restored without relaunching. The handoff records that Orca's own installer performed the swap, and on that record the supervisor waits for the previous build to come back and starts it instead of exiting. - Release list: `getMacSelfUpdateSourceFor` applies the manifest contract to the running source only, and the picker's default listing keys on the installer that is in use (`getMacSelfUpdateInstallerSourceFor`): the slice's zip, manifest and signature when Orca's own installer can act for this build, otherwise the DMG a hand install needs. An ad-hoc build and any other source's releases used to be filtered by assets the installer would never fetch for them. - Launch outcome: a refused health-marker write is retried every 5 s within the helper's window instead of being swallowed once and cached. - Local builds: the staged-bundle refusal now runs after the in-flight guards, so a click mid-check or mid-download is ignored as before rather than replacing the card and restoring the release feed under the running attempt. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Review complete. 🟡 3 medium 💬 Inline comments (2)
📍 Outside the diff (1)
🧹 Nitpicks (2) — 🟢 2 low
Reviewed commit: 4dbfe35 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4dbfe35776
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Expand to see previous review
Adds a signed, self-hosted macOS self-update flow (Ed25519-verified manifest, streamed download, bundle swap helper) plus a serve-update handoff supervisor, with mostly solid security foundations but a few supervisor and staging race gaps.
…lth from the window alone and pin the staging race Review round 7 on the macOS self-updater. - Supervised `orca serve` (user decision): the installer no longer activates in a process the serve supervisor started (`getMacSelfUpdateSupport` reports `supervised-serve`, once, as a lifecycle diagnostic), so such a host keeps the manual update path a fork build had before. Round 6's supervisor integration goes with it: the supervisor, the shared handoff record (`installer` field), `requestServeUpdateHandoff`, `printServeReady` and their tests are back at swaplabs/main, and the helper has no serve branches (no handoff argument, no `swapped`/`supervisor-rejected` outcomes, no `--serve` process match, no relaunch-less mode); it always relaunches and health-checks. Serve support is a possible follow-up. - Health signal: the first window's `ready-to-show` is the only thing that writes the health marker (`runOnlyAfterFirstWindowShown`); the 20 s fallback timer used to certify a renderer that hung or crashed before it, so the helper kept an unusable build and pruned its rollback. - Staging race: a check that supersedes the offer while `ditto` is still extracting leaves the staging directory to that download, which discards it as superseded; a test holds the extract to pin that. - CI: #15's manifest verifier test tampered with a signature by replacing its first character with a fixed letter, which one fresh key pair in 64 already starts with; the tamper now always changes it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Review complete. 🟡 1 medium 💬 Inline comments (1)
Reviewed commit: 5690d15 |
…elf-update-app Brings in the 2026-09-28 upstream sync (#19) and the devvms pin wake-up (#20). No textual conflicts. The base moved the unit-test shards to arm64 hosts, which the feed and readiness suites did not survive; the following commit pins the slice they model. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… quarantine strip across the bundle The unit-test shards now run on arm64 Linux, where `getUpdateManifestName` names `latest-linux-arm64.yml`; the feed, readiness, asset-readiness and release-builds suites mock the x64 manifest and installer names, so 36 cases failed on the ARM runners while passing on x64 hosts. A `setHostSliceForTest` fixture pins `process.arch` (and platform, where a case sets one) for the slice each file models and restores the host's own values after every test. `stripQuarantine` read the quarantine attribute back from the bundle directory alone, so a partial `xattr -r -d` that cleared the root and left `Contents/MacOS/<exe>` flagged passed the check and Gatekeeper blocked the relaunch. The verdict is now the recursive `xattr -r` listing: a non-zero exit refuses the bundle as unconfirmed, and any file still naming the attribute refuses it with that path. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Review complete. 🟡 2 medium 💬 Inline comments (2)
Reviewed commit: 9c189a1 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9c189a1abb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…he update helper gave up on `probeReleaseManifest` took every asset a fork's self-update manifest named, so a manifest whose `file` was an absolute URL had background checks HEAD that address before any signature was verified. The probe now requests only the slice's fixed zip and signature under the release, and a manifest naming any other file is not ready, as the installer would refuse it. When the helper cannot restore the previous build it relaunches the new one, so the build reporting a completed launch can be one that missed the helper's health deadline. That launch is still a completed update, but its record now carries the helper's verdict at warning level instead of reading like a healthy one. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Review complete. 🟡 1 medium 📍 Outside the diff (1)
🧹 Nitpicks (1) — 🟢 1 low
Implements a SwapLabs-forked macOS self-update flow (signature-verified staged bundle swap with rollback) plus updater feed/build-selection changes; review found one medium race in pinned-build checks and one low-severity error-classification mislabel. Reviewed commit: a2d83d8 |
ELI5
Orca on a Mac normally updates itself through Apple's Squirrel mechanism, which only accepts a new copy of the app that carries the same Apple Developer ID signature as the running one. SwapLabs builds are signed with our own certificate, so Squirrel would refuse every SwapLabs update and the "Download" button could only send people to a page to install a DMG by hand.
This change gives SwapLabs macOS builds their own installer inside Orca. When a new SwapLabs release appears, Orca downloads it, checks it very carefully (a signed description of the file, the file's size and checksum, and the new app's code signature and identity), and then, when you press "Restart to update", a tiny helper swaps the old app for the new one, relaunches it, and puts the old one back if the new one does not show a working window within 90 seconds.
What Changed
Before: on a SwapLabs macOS build, Settings → Updates showed "Open download page (SwapLabs)" for the fork's own next build. Background checks found nothing installable (the fork publishes no
latest-mac.yml).After (only when every condition below holds): routine checks, wake/focus checks, the menu check, the nudge campaign and the Updates button all work as on Linux: "Download 1.4.197-swaplabs.… (SwapLabs)" → progress → "Restart to update" (or install on next quit) → the app quits, is replaced, and relaunches into the new build. A refused or failed update shows an error in the update card with a link to the release page; a rollback is reported by the build that came back.
Conditions: macOS, a packaged SwapLabs build (
…-swaplabs.<stamp>), compiled with the newORCA_SWAPLABS_UPDATE_PUBLIC_KEYdefine (the raw 32-byte Ed25519 public key; validated at build likeORCA_RELEASE_SOURCES), a running bundle whose designated requirement is identity-bound (a self-signed certificate, not an ad-hoccdhash), and a process that is not a supervisedorca serve. Otherwise nothing changes, except thatrequiresManualInstallnow correctly says "manual" for a fork build's own next build on macOS (decision D4), where it used to promise an in-app install Squirrel would have refused.Supervised
orca serveis out of scope (user decision, review round 7): a process the serve supervisor started keeps the manual update path a fork build had before (the DMG is listed, the buttons say "Open download page"), and records one lifecycle diagnostic (updater_mac_self_update_inactive, reasonsupervised-serve) saying why. The helper's swap, relaunch and health watch are written for the desktop app, where a window is the health signal, while the supervisor restarts a serve on its own terms; teaching the two to cooperate is a possible follow-up PR. The supervisor, the serve handoff record andprintServeReadyare untouched by this PR. An unsupervised headless serve defers downloads and installs as it always has.Mechanism:
src/main/updater/mac-self-update/adds an update engine with the same surface and events as electron-updater'sAppUpdater(UpdateEngine), andgetAutoUpdater()picks it over electron-updater when the conditions hold. Every existing handler, guard, the pinned/cross-source flow,requiresManualInstall, the mac installer-ready gate and the exit watchdog run unchanged; the engine's ownupdate-downloadedis the installer-ready signal that Squirrel's native event used to be.swaplabs-update-mac-<arch>.json+.sigin place oflatest-mac.yml). The engine fetches manifest and signature (64 KiB / 1 KiB caps) and refuses unless, in order: Ed25519 signature over the exact bytes; strict parse;source,arch,bundleIdmatch; version belongs to the source and is newer (routine) or exactly the pinned target;designatedRequirementSha256equals the running bundle's.ditto -x -kinto.<App>-update-staging/beside the bundle (same volume, so the swap is a rename),codesign --verify --deep --strict,CFBundleIdentifier,CFBundleShortVersionString, designated requirement equal to the running app's, then stripscom.apple.quarantine. Any failure removes staging and the zip and carries the tag's release page asmanualInstallUrl. An unwritable app location is refused before the download. The staging directory belongs to the download for as long as it runs: a check that supersedes the offer mid-extract leaves it alone, and the download discards it itself as superseded.install-state.jsonand starts a detached/bin/sh -chelper. The script is a fixed string; every path and number is an argv entry. It waits for the pid to exit, moves the bundle to.<App>-update-rollback/, moves the staged bundle in, relaunches with/usr/bin/open, and waits up to 90 s for the health marker the new app writes once its first window can paint (ready-to-show), and on no other signal: no fallback timer, so a renderer that hangs or crashes before it is never certified. Without the marker it stops the new build, restores the rollback and relaunches the old build.updater_mac_self_update_completed/_failedwith the helper's one-word outcome, shows a rollback in the update card, discards a never-installed bundle, prunes the rollback a few minutes after a healthy launch.Spawns go through
src/shared/child-processonly. Docs:docs/reference/swaplabs-fork-builds.mdgains a "macOS self-updates" section with the asset contract, activation rules (including the supervised-serve exclusion) and the unverified list.Also in this PR:
config/scripts/swaplabs-mac-update-manifest.test.mjs(from #15) tampered with a signature by replacing its first character with a fixed letter, which about one fresh key pair in 64 already starts with; that run then saw no mismatch and failed. The tamper now always changes the character.Why
Plan §13 (user decisions 2026-09-25): self-signed certificate, Ed25519-signed manifest, same UX as upstream. Alternatives considered:
/bin/shprogram with argv-only inputs has no interpolation surface and no interpreter beyondmv,ps,killandopen.Security model: the compiled-in public key is the root of trust (a shell export cannot re-key it); nothing from a release is parsed before its signature verifies; nothing downloaded is executed before
codesign --deep --strictpasses; the only programs run are Apple's own under/usr; the helper cannot be steered by content; signing is never weakened.Linked Issue
Fixes # — fork-only work under plan §13 (Phase 5B); the pipeline side is #15.
Visual Proof
N/A — the Updates section, card and copy are unchanged; only which builds are offered in-app changes, and only on a real signed Mac build.
Testing
Linux (minidev), all passing:
pnpm tcpnpm test src/main/updater src/main/updater.mac-self-update.test.ts src/main/updater.headless-serve-install.test.ts src/cli/runtime/launch.test.ts src/main/serve-update-handoff.test.ts src/main/serve-update-handoff.app-environment.test.ts src/main/startup/desktop-startup-ordering.test.ts src/main/startup/first-window-deferral.test.ts src/main/update-install-exit-watchdog.test.tsand theconfig/scripts/swaplabs-*/verify-swaplabs-packagingsuites, the child-process import boundary and both fetch call-site auditsORCA_CODE_QUALITY_BASE=refs/remotes/swaplabs/swaplabs/main pnpm run check:code-quality:changed— passed;oxlint,oxfmt --check,pnpm run audit:anti-slop,pnpm run check:max-lines-ratchet— passedNew suites: manifest verification (good signature, tampered bytes, foreign key, wrong source/arch/bundle id/identity, downgrade, pinned mismatch, malformed fields), verified download (size/hash mismatch removal, progress), bundle verification and quarantine (mocked
runProcess), helper argv and a real/bin/shrun of the script over a temp tree (swap + healthy, rollback on missing marker, missing staged bundle, blocked or failed restores, a new build that ignores SIGTERM or survives SIGKILL), install-state and launch-outcome, the first-window deferral (a window-only task never runs on a timer), activation (inactive under a supervised serve, with one diagnostic), the engine end to end with fakes (including a check that supersedes the offer mid-extract), and the updater integration (routine check → available → download → downloaded → Restart spawns the helper and arms the exit watchdog; refusal surfacesmanualInstallUrl/retryable: false;listSourcesin-app once active; electron-updater path unchanged when unsupported).UNVERIFIED on a real Mac (no macOS host in this session): TCC grants surviving the swap with the self-signed identity; Gatekeeper on relaunch after the quarantine strip for a non-notarized bundle; renaming the bundle under a still-running terminal daemon;
openrelaunching promptly after the previous instance's exit;codesign/PlistBuddyoutput shapes on current macOS.AI Disclosure
Claude Fable 5.1 (Claude Code) wrote this change under the coordinator's plan.
Review
Agent skill upstream boundary
docs/reference/agent-skill-sharing-upstream-boundary.mdand copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.Notes
Security: see the model above. Cross-platform: the engine is created only on darwin; Linux/Windows and upstream builds keep electron-updater. Remote SSH: the status shape is unchanged (
manualInstallUrl/retryablewere already optional); a paired SwapLabs macOS host updates through the same path viaupdater.*RPC, unless it is a supervised serve, which stays manual. Mobile: untouched. Backwards compatibility: a build compiled without the key behaves as before, minus the incorrect in-app promise.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)🤖 Generated with Claude Code