#89: new AppDelegate.startupSurfacesMode enum (.minimal/.diagnostic). Debug defaults .diagnostic; Release defaults .minimal. openStartupSurfacesIfDiagnostic() runs at tail of bootHealthTask (skipped under XCTest or when wizard is open). Status panel top-right + Dev Overlay bottom-right of NSScreen.main.visibleFrame. DevOverlay opens to Logs tab.
#88: BannerContent.inputMonitoringDenied is now nonDismissible: true. New HUDBannerCoordinator.dismiss(id:) clears a banner programmatically without writing dismissedThisLaunch. AppDelegate.reprobeInputMonitoring fires on NSApplication.didBecomeActiveNotification; rebinds the global hotkey on re-grant. Uses IOHIDCheckAccess (query-only, no prompt) per CLAUDE.md guidance. 3 new coordinator tests.
#87: WizardState.pttHotkey persisted under Jarvis.pttHotkey (independent of summon hotkey). Ships unbound per CLAUDE.md hotkey hygiene. AppDelegate.rebindPTTFromState() called from installVoice, foreground TCC re-grant, Settings Save/Clear. SettingsView extended with PTT hotkey section. Audio-graph isolation: NSEvent monitors only, no audio-graph surgery — safe alongside fix/voice-crit-v0.1. 3 new WizardState tests.
DevOverlay 14 + Voice 26 tests pass; all 17 grep boundary gates green (incl. single-writer-hudstate + no-modal-presentation).
Phase A3 of AUDIT-AND-FIX-PLAN.md. Replaces the SwiftUI `Settings { Text("Settings — coming soon.") }` placeholder and the menu-bar Settings… → wizard stopgap (commits c7242ed + c75ea9b) with a real `SettingsView` hosted in an `NSWindow`.
Architecture mirrors `OnboardingWizardController`:
Setup… → `OnboardingWizardController` (sequential first-run flow, terminal Save)
Settings… → `SettingsWindowController` (freeform panel, every row independently editable)
Both surfaces share the same `WizardState`, so canonical truth lives in
one place:
• API key → Keychain (`Keychain.set(.anthropic, …)`)
• Input Monitoring → IOHIDCheckAccess (queried on each refresh)
• Global hotkey → UserDefaults `Jarvis.hotkey`
Edits in either surface write through to those stores, so re-opening the
other surface reflects the change immediately. Window discipline matches
the wizard: a single reusable `NSWindow`; clicking Settings… repeatedly
brings the existing window forward and `state.refresh()`-es rather than
stacking new windows.
Hotkey-edit hot-reload: `SettingsView.onHotkeyChanged` flows to
`AppDelegate.openSettings`'s closure, which calls `bindHotkeyFromWizard`
(reused from the wizard path). The new shortcut takes effect immediately
without a relaunch.
Files added:
• App/Settings/SettingsView.swift (was already in tree as untracked WIP;
296 LOC, three sections: API key / Permissions / Hotkey)
• App/Settings/SettingsWindowController.swift (new, 70 LOC; window
lifecycle + dependency injection)
Files modified:
• App/AppDelegate.swift — `settingsWindowController` property,
instantiation alongside `wizardController`, new `openSettings()`
private helper, menu wiring change
(`settingsAction: { ... openSettings() }` instead of `openWizard`).
• App/JarvisApp.swift — replaced the "coming soon" Text body of the
SwiftUI `Settings` scene with `EmptyView()`. The scene exists only
to satisfy the `App` protocol's Scene requirement; with
LSUIElement=YES the auto-generated app-menu Settings… is never
user-visible. AppDelegate manages the real Settings panel via
`SettingsWindowController`.
• App/MenuBar/MenuBarContextMenu.swift — comment update describing
the new Settings… semantics (no longer points at the wizard).
• Jarvis.xcodeproj/project.pbxproj — added Settings/ PBXGroup with
the two new files, PBXBuildFile entries for both, and group
reference under the App PBXGroup's children. Sources phase
references both build files. UUIDs generated via `uuidgen`.
Verification:
• `scripts/check-app-builds.sh`: PASS — App target compiles cleanly
with the new Settings/ group and new files.
• SwiftUI/AppKit hosting: `NSHostingController(rootView: SettingsView)`
matches the existing wizard host pattern.
• No new test regressions expected (no tests touch Settings yet —
test coverage is a Phase D-Phase-3 / Phase E line item).
Refs: .planning/AUDIT-AND-FIX-PLAN.md Phase A3, Phase C2 ("resolved by
Phase A3"). Closes the C2 finding; F-A1-01 (HUD rings static) and
F-A2-01 (stale `JarvisBusWorld` test) remain open in
.planning/AUDIT-FINDINGS.md.