Commit Graph
2 Commits
Author SHA1 Message Date
james.maes 795c3bf5c9 feat(app): v0.1 UX surfaces — startup panels + InputMonitoring banner + PTT (#87, #88, #89, #156)
#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).
2026-05-13 06:32:16 -05:00
james.maes 7043b3bd6e feat(settings): real Settings panel — single window, freeform editing of API key + Input Monitoring + hotkey
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.
2026-05-02 19:39:30 -05:00