What's Changed
- docs: render page eyebrow at route level, drop dead in-body spans by @nathanialhenniges in #356
- ci(nightly): name nightly release by its build commit hash by @nathanialhenniges in #355
- chore(actions): Bump dorny/paths-filter from 4.0.1 to 4.0.2 in the actions-minor-and-patch group by @dependabot[bot] in #350
- chore(actions): Bump actions/cache from 5.0.5 to 6.1.0 by @dependabot[bot] in #348
- chore(actions): Bump actions/checkout from 6.0.3 to 7.0.0 by @dependabot[bot] in #347
- fix(whats-new): only auto-open on feature releases by @nathanialhenniges in #357
- fix(docs): AA/AAA contrast, mobile hardening, de-AI copy, docs polish by @nathanialhenniges in #353
- fix(sparkle): embed release notes inline so version history renders by @nathanialhenniges in #359
- docs: correct download + on-disk size claims by @nathanialhenniges in #358
- Landing: drop proof band, sharpen nav, fix download SEO by @nathanialhenniges in #360
- docs: retire FEATURE_IDEAS.md in favor of Jira by @nathanialhenniges in #361
- feat(song-requests): opt-in approval screening for the request queue (WW-27) by @nathanialhenniges in #362
- feat(twitch): custom bot commands with variables, permissions, aliases by @nathanialhenniges in #363
- docs: sync README/docs to current source, bump to 2.1.0 by @nathanialhenniges in #364
- refactor(core): split AppConstants into per-namespace files by @nathanialhenniges in #365
- refactor(discord): extract presence builder + IPC from DiscordRPCService by @nathanialhenniges in #366
- refactor(twitch): split TwitchChatService actor across seam files by @nathanialhenniges in #367
- ci: block new SwiftLint violations via baseline; gitignore + weekly full-suite by @nathanialhenniges in #368
- ci: run full suite unskipped on macos-26; remove weekly canary by @nathanialhenniges in #369
- docs: add AGENTS.md by @nathanialhenniges in #370
- chore: clean up code comments + fix docs Glass theme override by @nathanialhenniges in #371
- fix(crash): guard Int(Double) traps + Logger raising FileHandle calls (Tier 1) by @nathanialhenniges in #372
- fix(concurrency): notification/socket/task races + leaks (Tier 2) by @nathanialhenniges in #376
- perf: cut steady-state CPU, IPC, and broadcast churn (Tier 3) by @nathanialhenniges in #374
- refactor: dead view helpers + stale doc fixes (Tier 4) by @nathanialhenniges in #375
- feat: fair-share round-robin song request ordering (WW-44) by @nathanialhenniges in #377
- feat: sub/VIP song request priority (WW-43) by @nathanialhenniges in #378
- feat(streamdeck): bidirectional WebSocket control API (WW-36 Phase A) by @nathanialhenniges in #379
- fix(stability): resolve verified crashes, lockups, and data races by @nathanialhenniges in #381
- feat(widget): add Vinyl and Classic overlay layouts by @nathanialhenniges in #380
- refactor: dedup cleanup pass (20 safe extractions, behavior-preserving) by @nathanialhenniges in #382
- refactor: deferred dedup backlog (M3, M5-defaults, L5, L19, L22) by @nathanialhenniges in #383
- chore: canonicalize Swift file headers, gate them in CI, resync docs by @nathanialhenniges in #384
- fix(settings): fixed sidebar width + unify remaining toggles by @nathanialhenniges in #385
- chore(docs): remove dead proof-band/stat/download CSS by @nathanialhenniges in #386
- docs: drop Unbounded for Instrument Sans, fix Twitch chat preview gap by @nathanialhenniges in #387
- perf: minimize OBS overlay and runtime resource use by @nathanialhenniges in #389
- feat(widget): add opt-in overlay queue ticker (WW-42) by @nathanialhenniges in #390
- fix(music): stop relaunching Music.app by addressing it via pid by @nathanialhenniges in #392
- Fix dev app and test identity isolation by @nathanialhenniges in #391
- Fix Discord presence and Twitch command testing by @nathanialhenniges in #394
- Replace WolfWave canonical wolf mark by @nathanialhenniges in #393
- Adopt the Side EQ WolfWave logo by @nathanialhenniges in #395
- fix(ci): share one build-number counter across stable and nightly by @nathanialhenniges in #396
- Stream Deck plugin (WW-45 Phase B), queue_state.held, and the 2.1.0 release-notes sweep by @nathanialhenniges in #397
- docs: restructure and sync docs site with current codebase by @nathanialhenniges in #399
- Stream Deck icons and packaging, docs footer commit hash, FAQ accordion fix by @nathanialhenniges in #400
- docs: sync repo documentation with the current codebase by @nathanialhenniges in #401
- feat(design-system): add the missing tokens.schema.json by @nathanialhenniges in #402
- feat(design-system): enforce tokens.schema.json instead of leaving it advisory by @nathanialhenniges in #403
- docs: address review feedback on the token schema gate by @nathanialhenniges in #404
- docs(todo): mark the native test suite done by @nathanialhenniges in #405
- feat(branding): give Debug builds their own app icon by @nathanialhenniges in #406
- docs: warn that each worktree has its own DerivedData by @nathanialhenniges in #407
- Harden music requests, vote-skip, and history by @nathanialhenniges in #410
- Separate WebSocket overlay and control credentials by @nathanialhenniges in #411
- Harden Discord IPC ownership and deadlines by @nathanialhenniges in #412
- chore(actions): bump the actions-minor-and-patch group across 1 directory with 2 updates by @dependabot[bot] in #398
- Pin and centralize SwiftLint CI by @nathanialhenniges in #413
- Harden WebSocket connection and credential lifecycle by @nathanialhenniges in #414
- Make Twitch account and paid-event flows transactional by @nathanialhenniges in #415
- Make settings import and factory reset transactional by @nathanialhenniges in #416
- test: keep only meaningful boundary coverage by @nathanialhenniges in #418
- fix(docs): remove broken widget route by @nathanialhenniges in #419
- test(streamdeck): verify real wire contracts by @nathanialhenniges in #420
- Refactor unused playback and core abstractions by @nathanialhenniges in #408
- Fix settings, notification, cache, and link audit findings by @nathanialhenniges in #409
- Make blocklist round-trip test semantic by @nathanialhenniges in #422
- Compare persisted backup models semantically by @nathanialhenniges in #423
- docs(changelog): cover the settings-import hardening merges by @nathanialhenniges in #424
- fix(song-requests): make "Open in Music" reveal the playlist by @nathanialhenniges in #425
- fix(music): restore Apple Music control and the now-playing card (both broken by #410) by @nathanialhenniges in #426
- fix(twitch): end redemption containment when no account can resolve it by @nathanialhenniges in #427
- test(history): fix flaky clear-during-load play-log assertion by @nathanialhenniges in #429
- fix(song-requests): validate the playlist Music actually plays from by @nathanialhenniges in #430
- refactor(song-requests): remove the DEBUG playback hatch and make SongRequestItem.song non-optional by @nathanialhenniges in #428
- fix(tests): stop the hosted test bundle editing the dev app's real settings by @nathanialhenniges in #431
- fix(settings): stop a corrupted saved value from crashing the Settings window by @nathanialhenniges in #435
- fix(tests): bind loopback test servers to an OS-assigned port by @nathanialhenniges in #434
- fix(settings): sweep the remaining pickers onto the sanitized bindings by @nathanialhenniges in #433
- test(warnings): take the test target from 206 build warnings to zero by @nathanialhenniges in #436
- fix(tests): stop KeychainServiceTests flaking on a shared Keychain backend by @nathanialhenniges in #438
- test(warnings): silence the last 7 unused-result warnings by @nathanialhenniges in #439
Full Changelog: v2.0.1...v2.1.0