v1.2.0: fix packaged-app launch crash, global Night Shift toggle, schedule-aware overrides - #11
Merged
Merged
Conversation
Every distributed build to date (v1.0.0 through the signed v1.1.2) crashes at launch on any machine except the dev machine, verified by running the released DMGs directly: Fatal error: could not load resource bundle Two stacked bugs: the SwiftPM package was still named NightShiftToggle, so the resource bundle was NightShiftToggle_ShiftChange.bundle while create-dmg.sh looked for ShiftChange_ShiftChange.bundle — and the script's `find .build/release` couldn't descend into the symlinked release directory anyway, so the copy was silently skipped regardless. Without the bundle, Bundle.module hits fatalError during applicationDidFinishLaunching. Dev machines were masked by the binary's baked-in fallback path to the local .build checkout. Changes: - Package name NightShiftToggle → ShiftChange (bundle becomes ShiftChange_ShiftChange.bundle) - Sources/NightShiftToggle/ → Sources/ShiftChange/, NightShiftToggleApp.swift → ShiftChangeApp.swift - create-dmg.sh: resolve the bundle by direct path and hard-fail if missing instead of silently shipping a broken app - release.yml: update the VERSION path trigger and version check to the renamed directory (releases would stop triggering otherwise) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…anup - Choosing "Minimize to Menu Bar" in the quit confirmation no longer leaves focus monitoring permanently stopped: quitApp and applicationShouldTerminate no longer stop the monitor eagerly; teardown happens only in applicationWillTerminate - FocusMonitor.deinit no longer mutates @published state during deallocation (removes the observer and restores directly) - CBlueLightBridge: dedupe the status-fetch boilerplate into fetchStatus:, check the getBlueLightStatus: return value, and unify the log prefix to [ShiftChange] - README: remove stray artifact tags at end of file Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two related additions to the override state machine: 1. Menu bar "Turn On/Off Night Shift" item. Uses CBBlueLightClient setEnabled: via the client protocol — the exact call behind the System Settings toggle, so with a schedule configured the OS itself handles "until tomorrow / until sunset". While an excluded app has focus the toggle only updates the restore intent (display untouched), so per-app switching keeps working regardless of global state. 2. The bridge now registers CBBlueLightClient's status notification block (delivered on the main queue; the block takes no parameters and re-queries status rather than trusting the private struct layout). If the schedule or the user turns Night Shift on while an excluded app is focused, it is immediately re-disabled and folded into the restore intent — the display no longer warms mid-session in color-critical apps. Previously this went unnoticed until the next app switch. Supporting changes: - BlueLightControlling gains setStatusChangeHandler so the state machine stays fully testable; FakeBlueLightClient fires the handler synchronously on self-caused changes (stricter than production) to catch re-entrancy bugs - disableForExcludedApp/restoreIfNeeded update state before calling setEnabled, making the state machine safe against synchronous notification delivery - Menu refreshes on open (NSMenuDelegate) and on external changes; status line shows On/Off instead of "Following schedule" - Six new unit tests covering the toggle and external-change paths Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- release.yml: push the updated cask to the live tap repo (adamdexter/homebrew-shiftchange) when the TAP_PUSH_TOKEN secret is configured; warn loudly when it isn't. The tap was stuck at v1.0.0 because nothing ever updated it. - create-dmg.sh: honor SHIFTCHANGE_SCRATCH_PATH for the swift build (iCloud-synced checkouts corrupt .build mid-build; default unchanged) - CLAUDE.md: renamed paths, resource-bundle naming warning, external status changes + global toggle sections, expanded regression checklist, tap-repo documentation, iCloud build gotcha - README: global toggle + schedule-aware feature bullets, renamed VERSION path - Bump version to 1.2.0 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The release workflow triggers on the VERSION file change to main (signed + notarized via the existing secrets). Before merging, run the manual regression checklist in CLAUDE.md on real hardware — especially the new cases (menu toggle, schedule firing while an excluded app is focused).
Critical fix: every shipped build crashes on launch
v1.0.0–v1.1.2 (including the signed/notarized v1.1.2) crash instantly on any machine except the dev machine — verified by downloading and running the released DMGs:
Two stacked bugs: the SwiftPM package was still named
NightShiftToggle, so the resource bundle didn't match whatcreate-dmg.shexpected — and the script'sfindcouldn't descend the.build/releasesymlink anyway, silently skipping the copy. Dev machines were masked by a baked-in fallback path to the local checkout. The package rename fixes the name;create-dmg.shnow resolves the bundle by direct path and hard-fails if missing. Verified end-to-end: built the DMG, launched the packaged app.Features
Fixes & infrastructure
FocusMonitor.deinitno longer mutates@Publishedstate during deallocation[ShiftChange]log prefixadamdexter/homebrew-shiftchange) when aTAP_PUSH_TOKENsecret exists — the tap has been stuck at v1.0.0 because nothing updated itcreate-dmg.sh:SHIFTCHANGE_SCRATCH_PATHoverride for iCloud-synced checkouts (documented in CLAUDE.md)Post-merge
TAP_PUSH_TOKENsecret (PAT with write access to the tap repo) so brew users get v1.2.0 — otherwise sync the tap manually.claude/v1.2.0-ci-checkbranch (CI-only run from before the workflow-scope fix).🤖 Generated with Claude Code