flowchart TD
A["User clicks tour card in Onboarding Panel"] --> B["panel.dispatch start-tour"]
B --> C["TourEngine.handle start-tour"]
C --> D{"sandbox.detectConflict"}
D -- "none" --> E["start 200ms timer"]
D -- "exists-clean" --> F["reuse existing sandbox"]
D -- "exists-modified" --> G["post tour-confirm-reset-sandbox"]
G --> H["await inbound confirmation"]
H --> E
E --> I["scaffold.scaffold workspacePath"]
E --> J["timer fires, post tour-preparing-sandbox"]
I --> K["scaffold resolves, cancel timer"]
F --> K
K --> L["progress.load folderUri, tourId"]
L --> M["client.listTours, pick TourDto"]
M --> N["render first step or resume step"]
N --> O["post tour-step"]
O --> P{"step.kind"}
P -- "read" --> Q["panel shows Next button"]
P -- "action" --> R["client.watchStep tourId, stepId"]
Q --> S["inbound tour-next-step"]
R --> T["server fires onStepCompleted"]
S --> U["progress.save with new step pointer"]
T --> U
U --> V{"more steps?"}
V -- "yes" --> N
V -- "no" --> W["progress.save finished=true"]
W --> X["completed.markCompleted tourId"]
X --> Y{"tour has final_handoff step"}
Y -- "yes" --> Z["post tour-final-handoff-prompt"]
Y -- "no" --> AA["post tour-finished"]
Z --> AB["inbound tour-final-handoff-confirmed"]
AB --> AC["commands.execute turbine.datasources.newDatasource"]
AC --> AD["END"]
AA --> ADsequenceDiagram
actor User
participant Panel as OnboardingViewProvider
participant Engine as TourEngine
participant Client as TurbineClient
participant Scaffold as SandboxScaffold
User->>Panel: click tour card
Panel->>Engine: handle start-tour tourId folderUri
Engine->>Scaffold: detectConflict workspacePath
Scaffold-->>Engine: none
Engine->>Engine: schedule 200ms hint timer
Engine->>Scaffold: scaffold workspacePath
Note right of Engine: race between scaffold and 200ms
Engine->>Panel: post tour-preparing-sandbox after 200ms
Panel->>User: render Preparing sandbox hint
Scaffold-->>Engine: SandboxPath
Engine->>Engine: cancel hint timer
Engine->>Client: listTours
Client-->>Engine: ListToursResult
Engine->>Engine: progress load folderUri tourId
Engine->>Panel: post tour-step index 0
Panel->>User: render step 0
User->>Panel: click Next or trigger predicate
Panel->>Engine: handle tour-next-step
Engine->>Client: watchStep when action step
Client-->>Engine: onStepCompleted notification
Engine->>Engine: progress save record
Engine->>Panel: post tour-step index 1
Note over Engine,Panel: loop until all steps done
Engine->>Engine: completed markCompleted tourId
Engine->>Panel: post tour-final-handoff-prompt
User->>Panel: confirm
Panel->>Engine: handle tour-final-handoff-confirmed
Engine->>Panel: commands execute turbine.datasources.newDatasource
classDiagram
class TourEngine {
+handle(message) Promise~void~
+resume(folderUri, tourId) Promise~void~
+dispose() void
}
class TurbineClient {
<<existing>>
+listTours() Promise~ListToursResult~
+watchStep(params) Promise~void~
+unwatchStep() Promise~void~
+runStep(params) Promise~RunStepResultDto~
+onStepCompleted(handler) Disposable
}
class SandboxScaffold {
<<existing>>
+exists(workspacePath) Promise~boolean~
+scaffold(workspacePath) Promise~SandboxPath~
+reset(workspacePath) Promise~void~
+detectConflict(workspacePath) Promise~ConflictKind~
}
class TourPanelChannel {
<<Interface>>
+post(message) void
}
class TourProgressStore {
<<Interface>>
+load(folderUri, tourId) Promise~TourProgressRecord~
+save(record) Promise~void~
}
class CompletedToursStore {
<<Interface>>
+list() readonly_string_array
+markCompleted(tourId) Promise~void~
}
class TourCommandSink {
<<Interface>>
+execute(command, args) Promise~unknown~
}
class OnboardingViewProvider {
<<existing>>
+resolveWebviewView(view) void
+show() Promise~void~
+postToWebview(message) void
}
class LspTourProgressStore {
+load(folderUri, tourId) Promise~TourProgressRecord~
+save(record) Promise~void~
}
TourEngine --> TurbineClient : uses
TourEngine --> SandboxScaffold : uses
TourEngine --> TourPanelChannel : posts
TourEngine --> TourProgressStore : persists
TourEngine --> CompletedToursStore : marks
TourEngine --> TourCommandSink : final-handoff
OnboardingViewProvider --> TourEngine : routes start-tour
OnboardingViewProvider ..|> TourPanelChannel : implements via postToWebview
LspTourProgressStore ..|> TourProgressStore : implements
LspTourProgressStore --> TurbineClient : sendRequest