Skip to content

fix: stop settings hang caused by blocking XPC call on main thread#252

Open
vegerot wants to merge 5 commits intoJerryZLiu:mainfrom
vegerot:pr252
Open

fix: stop settings hang caused by blocking XPC call on main thread#252
vegerot wants to merge 5 commits intoJerryZLiu:mainfrom
vegerot:pr252

Conversation

@vegerot
Copy link
Copy Markdown
Contributor

@vegerot vegerot commented Apr 9, 2026

SMAppService.mainApp.status makes a synchronous XPC call to smd that
can block for 5+ seconds. The async version was already written and used
in init/bootstrapDefaultPreference, but onAppear was calling the sync
refreshStatus() instead. Switch to refreshStatusAsync() so the XPC call
runs off the main actor.

Confirmed via sample: 100% of samples during the hang were blocked in
mach_msg2_trap inside SMAppService's XPC pipe.


Stack created with Sapling. Best reviewed with ReviewStack.

vegerot and others added 4 commits April 9, 2026 11:32
- Extract shared prompt templates into LLMPromptTemplates (GeminiPromptPreferences.swift)
- Add VideoPromptPreferences/VideoPromptOverrides/VideoPromptSections types,
  replacing GeminiPromptPreferences/GeminiPromptOverrides/GeminiPromptSections
- Centralize transcript JSON decoding and observation conversion in
  LLMTranscriptUtilities (TimeParsing.swift) for reuse across providers
- Refactor GeminiDirectProvider to use LLMPromptTemplates and LLMTranscriptUtilities
- Refactor TestConnectionView to accept a provider parameter with
  finishFailure/finishSuccess helpers for clean multi-provider support
- Fix OnboardingLLMSelectionView card-width calculation to be dynamic
  based on card count rather than hard-coded divisor of 3
- Update SettingsProvidersTabView and ProvidersSettingsViewModel to use
  new VideoPrompt* types

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Ensures every AnalyticsService event is sent to PostHog, printed to stdout, and emitted via Apple Unified Logging.
SMAppService.mainApp.status makes a synchronous XPC call to smd that
can block for 5+ seconds. The async version was already written and used
in init/bootstrapDefaultPreference, but onAppear was calling the sync
refreshStatus() instead. Switch to refreshStatusAsync() so the XPC call
runs off the main actor.

Confirmed via `sample`: 100% of samples during the hang were blocked in
mach_msg2_trap inside SMAppService's XPC pipe.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to prevent the Settings screen from hanging by moving a potentially-blocking SMAppService.mainApp.status XPC call off the main thread, while also bundling several broader refactors/features around LLM prompting/parsing, analytics logging, and Sparkle update behavior.

Changes:

  • Avoids Settings UI hangs by invoking LaunchAtLoginManager.refreshStatusAsync() from SettingsView instead of the synchronous refresh.
  • Adds an “Automatic app updates” setting and threads that preference into Sparkle’s silent user driver behavior.
  • Refactors LLM prompt/schema plumbing (shared prompt templates + JSON schemas) and centralizes transcript/timeline parsing/validation utilities.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
Dayflow/Dayflow/Views/UI/SettingsView.swift Switches Settings onAppear to call async launch-at-login status refresh.
Dayflow/Dayflow/System/LaunchAtLoginManager.swift Makes refreshStatusAsync() callable by the Settings view.
Dayflow/Dayflow/Views/UI/Settings/SettingsOtherTabView.swift Adds UI toggle for automatic updates.
Dayflow/Dayflow/Views/UI/Settings/OtherSettingsViewModel.swift Persists automatic update preference + updates Sparkle user driver accordingly.
Dayflow/Dayflow/System/UpdaterManager.swift Initializes Sparkle user driver state from UserDefaults; adjusts termination behavior around update flows.
Dayflow/Dayflow/System/SilentUserDriver.swift Adds shouldAutoUpdateAndRestart and uses it to decide whether to install/skip updates.
Dayflow/Dayflow/System/AnalyticsService.swift Adds local analytics logging alongside PostHog capture.
Dayflow/Dayflow/Views/Onboarding/TestConnectionView.swift Generalizes connection testing to be provider-aware (currently Gemini-only behavior).
Dayflow/Dayflow/Views/UI/Settings/SettingsProvidersTabView.swift Passes provider into the test connection view for Gemini.
Dayflow/Dayflow/Views/UI/Settings/ProvidersSettingsViewModel.swift Switches Gemini prompt override persistence to shared “VideoPrompt” preferences types.
Dayflow/Dayflow/Views/Onboarding/OnboardingLLMSelectionView.swift Fixes card width calculation to avoid divide-by-zero with dynamic card counts.
Dayflow/Dayflow/Core/Analysis/TimeParsing.swift Adds shared timestamp parsing, timeline validation, and transcript decoding utilities for LLM workflows.
Dayflow/Dayflow/Core/AI/LLMSchema.swift Introduces JSON schema strings for transcript + activity card outputs.
Dayflow/Dayflow/Core/AI/GeminiPromptPreferences.swift Renames prompt override types and adds shared prompt template helpers.
Dayflow/Dayflow/Core/AI/GeminiDirectProvider.swift Moves prompts/schema handling and transcript parsing to shared utilities; adds schema-based response config.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants