flowchart TD
  Start([User opens VS Code workspace]) --> Phase{EditorPhase}
  Phase -->|no-folder / needs-uv / starting / awaiting / needs-server| EntryBlock["Entry view: blocker card<br/>(Open Folder / Install uv / Retry)"]
  EntryBlock -->|user resolves blocker| Phase
  Phase -->|lsp-phase: needs-pyproject / needs-turbine| EntryInstall["Entry view: setup card<br/>(install choices)"]
  EntryInstall -->|installs complete| Phase
  Phase -->|lsp-phase: ready-tour-pending or ready| EntryReady["Entry view: 'Start Onboarding' button"]
  EntryReady -->|click Start Onboarding| StartCmd["execute turbine.onboarding.startTour"]
  StartCmd --> Focus["focus turbine.onboardingTour view"]
  Focus --> WelcomeOrPicker{machineWideCompleted empty?}
  WelcomeOrPicker -->|yes| Welcome["Welcome panel"]
  WelcomeOrPicker -->|no| Picker["Tour Picker"]
  Welcome -->|Start Onboarding click| Picker
  Picker -->|Pick tour| PostStart["post start-tour"]
  PostStart --> Engine["TourEngine.handle"]
  Engine -->|sandbox missing/dirty conflict| ResetConfirm["resetConfirm screen"]
  ResetConfirm -->|Reset and continue| PostResetConfirm["post tour-confirm-reset-sandbox-confirmed"]
  ResetConfirm -->|Back| Picker
  PostResetConfirm --> Engine
  Engine -->|scaffold > 200ms| Preparing["preparing screen"]
  Engine -->|tour-step| Step["step screen"]
  Preparing --> Step
  Step -->|Next click or LSP step-completed| PostNext["post tour-next-step"]
  PostNext --> Engine
  Step -->|Back to picker (local)| Picker
  Step -->|tour-error| ErrorScreen["error screen"]
  ErrorScreen -->|Back to picker| Picker
  Engine -->|tour-final-handoff-prompt| FinalHandoff["final-handoff screen"]
  FinalHandoff -->|Confirm| PostFinal["post tour-final-handoff-confirmed"]
  PostFinal --> NewDS["execute turbine.datasources.newDatasource"]
  Engine -->|tour-finished| TourComplete["TourComplete screen"]
  TourComplete -->|Continue| Picker
  TourComplete -->|all 5 done| FinalComplete["FinalComplete screen"]
  FinalComplete -->|Revisit tours| Picker
  Picker -->|Reset onboarding from kebab| ResetCmd["execute turbine.onboarding.reset"]
  ResetCmd --> Phase
sequenceDiagram
  actor User
  participant EntryView as EntryView (turbine.onboarding)
  participant TourView as TourView (turbine.onboardingTour)
  participant Comp as OnboardingComposition
  participant Engine as TourEngine
  participant Phase as PhaseClient

  User->>EntryView: click Start Onboarding
  EntryView->>Comp: command turbine.onboarding.startTour
  Comp->>TourView: show and focus view
  TourView->>TourView: render Welcome or Picker
  Comp-->>TourView: post phase-data with tours and completed set

  User->>TourView: pick tour t1
  TourView->>Engine: handle start-tour t1 folderUri
  Engine->>Engine: scaffold sandbox if needed
  Engine->>TourView: post tour-step index 0
  TourView->>TourView: render step screen

  User->>TourView: click Next
  TourView->>Engine: handle tour-next-step t1
  Engine->>TourView: post tour-step-completed and tour-step index 1
  TourView->>TourView: re-render step

  User->>TourView: click Next on last step
  TourView->>Engine: handle tour-next-step t1
  Engine->>Engine: persist progress and mark completed
  Engine->>TourView: post tour-finished
  Engine->>Comp: panelChannel sees tour-finished
  Comp->>EntryView: refreshFromExternal
  Comp->>TourView: refreshFromExternal posts new phase-data
  TourView->>TourView: render TourComplete

  User->>TourView: click Reset onboarding from kebab
  TourView->>Comp: command turbine.onboarding.reset
  Comp->>Phase: reset workspaceFolderUri
  Phase-->>Comp: ack
  Comp->>EntryView: refreshFromExternal
  Comp->>TourView: refreshFromExternal
classDiagram
  class OnboardingViewProvider {
    -OnboardingViewDeps deps
    -WebviewView currentView
    -string renderedKey
    +resolveWebviewView(view) void
    +show() Promise~void~
    +refreshFromExternal() void
    +dispose() void
  }

  class OnboardingTourViewProvider {
    -OnboardingTourViewDeps deps
    -WebviewView currentView
    -string renderedKey
    +resolveWebviewView(view) void
    +postToWebview(message) void
    +refreshFromExternal() void
    +show() Promise~void~
    +dispose() void
  }

  class OnboardingComposition {
    +EditorPhaseService phaseService
    +ActiveOnboardingFolder activeFolder
    +OnboardingViewProvider viewProvider
    +OnboardingTourViewProvider tourViewProvider
    +TourEngineHost tourHost
    +OnboardingStatusBar statusBar
    +start() Promise~void~
    +show() Promise~void~
    +showTour() Promise~void~
    +resetActive(scaffold) Promise~void~
    +dispose() void
  }

  class TourEngine {
    +handle(message) Promise~void~
    +dispose() void
  }

  class PhaseClient {
    +current PhaseDto
    +installCommands(params) Promise~InstallCommandsResult~
    +dismiss(params) Promise~void~
    +reset(params) Promise~void~
    +dispose() void
  }

  class TourPanelChannel {
    <<interface>>
    +post(message) void
  }

  OnboardingComposition o-- OnboardingViewProvider
  OnboardingComposition o-- OnboardingTourViewProvider
  OnboardingComposition o-- TourEngine
  OnboardingComposition ..> PhaseClient
  OnboardingTourViewProvider ..> TourEngine : forwards inbound
  TourEngine ..> TourPanelChannel : posts outbound
  OnboardingComposition ..> TourPanelChannel : routes to TourView