-
Notifications
You must be signed in to change notification settings - Fork 88
feat: Implement welcome onboarding flow for first-time users #1001
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Captures design decisions from brainstorming session: - Flow triggers after folder trust dialog - Dynamic provider list from ProviderManager - Delegates to existing OAuth/auth infrastructure - Optional profile save at completion - First-run flag stored in config file
Detailed 13-task plan covering: - Welcome config service for first-run detection - useWelcomeOnboarding hook for state management - 6 step components (Welcome, Provider, Auth, etc.) - Integration into AppContainer and DefaultAppLayout
Add first-run welcome wizard that guides new users through: - Provider selection from available providers - Authentication method choice (OAuth or API key) - OAuth authentication flow - Optional profile save for quick restoration Components created: - WelcomeDialog: main orchestrator with step routing - WelcomeStep: initial welcome with setup/skip choice - ProviderSelectStep: provider picker with display names - AuthMethodStep: OAuth vs API key selection - AuthenticationStep: OAuth flow and API key input - CompletionStep: success message with optional profile save - SkipExitStep: skip confirmation message Integration: - Added welcomeConfig.ts for persistence in ~/.llxprt/ - Added useWelcomeOnboarding hook for state management - Integrated into AppContainer after folder trust - Added to DialogManager for rendering
Add ModelSelectStep component allowing users to select their preferred model after choosing a provider. Updated onboarding flow to 5 steps: 1. Choose Provider 2. Choose Model (NEW) 3. Choose Auth Method 4. Authenticate 5. Save Profile Models are fetched when provider is selected and persisted via setActiveModel.
Add defensive null guards in WelcomeDialog to prevent runtime crashes from invalid state transitions. Introduce ModelsLoadStatus tracking for detailed model loading feedback: loading, success, error, and empty states. Show contextual error messages and allow users to escape from error conditions.
WalkthroughIntroduces a complete welcome onboarding flow for first-run CLI users with persistent config storage, multi-step UI components (welcome, provider selection, authentication, completion), a state management hook orchestrating the flow, and integration into the app container and dialog manager. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant WelcomeDialog
participant useWelcomeOnboarding as Hook: useWelcomeOnboarding
participant AuthService as Auth Service
participant Config as Welcome Config
User->>WelcomeDialog: App starts (first-run)
WelcomeDialog->>useWelcomeOnboarding: Initialize hook
useWelcomeOnboarding->>Config: Load welcome state
Config-->>useWelcomeOnboarding: welcomeCompleted = false
useWelcomeOnboarding-->>WelcomeDialog: Show Welcome step
User->>WelcomeDialog: Select "Setup"
WelcomeDialog->>useWelcomeOnboarding: startSetup()
useWelcomeOnboarding->>useWelcomeOnboarding: Load available providers
useWelcomeOnboarding-->>WelcomeDialog: Show Provider Select step
User->>WelcomeDialog: Select provider
WelcomeDialog->>useWelcomeOnboarding: selectProvider(providerId)
useWelcomeOnboarding->>useWelcomeOnboarding: Load models for provider
useWelcomeOnboarding-->>WelcomeDialog: Show Model Select step
User->>WelcomeDialog: Select model
WelcomeDialog->>useWelcomeOnboarding: selectModel(modelId)
useWelcomeOnboarding-->>WelcomeDialog: Show Auth Method step
User->>WelcomeDialog: Select auth method (OAuth or API Key)
WelcomeDialog->>useWelcomeOnboarding: selectAuthMethod(method)
useWelcomeOnboarding-->>WelcomeDialog: Show Authentication step
alt OAuth Flow
User->>WelcomeDialog: Initiate OAuth
WelcomeDialog->>AuthService: triggerAuth(provider, 'oauth')
AuthService-->>AuthService: Open browser for OAuth
AuthService-->>WelcomeDialog: Auth complete
WelcomeDialog->>useWelcomeOnboarding: onAuthComplete()
else API Key Flow
User->>WelcomeDialog: Enter API Key
WelcomeDialog->>AuthService: triggerAuth(provider, 'api_key', apiKey)
AuthService-->>WelcomeDialog: Validate and set key
WelcomeDialog->>useWelcomeOnboarding: onAuthComplete()
end
useWelcomeOnboarding-->>WelcomeDialog: Show Completion step
User->>WelcomeDialog: Save profile (optional)
WelcomeDialog->>useWelcomeOnboarding: saveProfile(profileName)
useWelcomeOnboarding->>Config: Save profile config
Config-->>useWelcomeOnboarding: Success
User->>WelcomeDialog: Dismiss
WelcomeDialog->>useWelcomeOnboarding: dismiss()
useWelcomeOnboarding->>Config: Mark welcome completed
Config-->>useWelcomeOnboarding: Persisted
useWelcomeOnboarding-->>WelcomeDialog: Close dialog
WelcomeDialog-->>User: App proceeds to normal flow
Estimated code review effort🎯 4 (Complex) | ⏱️ ~55 minutes The review spans multiple integration layers: a new persistence module with file I/O, a complex state-management hook with provider/model discovery and auth orchestration, six specialized UI components and a main dialog orchestrator, and integration across three key app files. While individual components follow patterns, the heterogeneous mix of auth logic, keyboard handling, form validation, state transitions, and file operations requires careful scrutiny across boundaries. Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (2 passed)
✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (5)
packages/cli/src/ui/components/WelcomeOnboarding/AuthenticationStep.tsx (1)
92-106: OAuth effect may re-trigger on dependency changes causing duplicate auth attempts.The
authStartedflag guards against re-triggering, but it's not included as a dependency in the effect (it is, actually). However, ifonCompleteoronErrorcallbacks change identity between renders (e.g., if not memoized in parent), this could cause unnecessary re-renders of the effect, thoughauthStartedshould still prevent duplicate calls.The current implementation is correct with the
authStartedguard. However, consider moving the Promise handling to avoid the.then()/.catch()pattern which doesn't handle the case where the component unmounts mid-auth:🔎 Suggested improvement with cleanup
// Start OAuth flow automatically useEffect(() => { + let cancelled = false; if (method === 'oauth' && !authStarted) { setAuthStarted(true); setIsAuthenticating(true); triggerAuth(provider, 'oauth') .then(() => { + if (cancelled) return; onComplete(); }) .catch((error: unknown) => { + if (cancelled) return; setIsAuthenticating(false); onError(error instanceof Error ? error.message : String(error)); }); } + return () => { + cancelled = true; + }; }, [method, provider, triggerAuth, onComplete, onError, authStarted]);packages/cli/src/ui/hooks/useWelcomeOnboarding.ts (3)
78-78: Unusedsettingsparameter.The
settingsparameter is destructured as_settingsbut never used in the hook. Either remove it fromUseWelcomeOnboardingOptionsinterface and the hook signature, or document why it's needed for future use.🔎 If settings is not needed, remove it
export interface UseWelcomeOnboardingOptions { - settings: LoadedSettings; isFolderTrustComplete: boolean; } export const useWelcomeOnboarding = ( options: UseWelcomeOnboardingOptions, ): UseWelcomeOnboardingReturn => { - const { settings: _settings, isFolderTrustComplete } = options; + const { isFolderTrustComplete } = options;
108-140: Model loading effect lacks cancellation for unmount/stale requests.If the provider changes rapidly or the component unmounts during the async
listAvailableModelscall, stale results could be applied to state. Consider adding a cleanup function:🔎 Add cancellation to prevent stale state updates
// Load available models when provider is selected useEffect(() => { + let cancelled = false; const loadModels = async () => { if (!state.selectedProvider) { setAvailableModels([]); setState((prev) => ({ ...prev, modelsLoadStatus: 'idle' })); return; } setState((prev) => ({ ...prev, modelsLoadStatus: 'loading' })); try { const models = await runtime.listAvailableModels( state.selectedProvider, ); + if (cancelled) return; const modelInfos: ModelInfo[] = models.map((m) => ({ id: m.name, name: m.name, })); setAvailableModels(modelInfos); setState((prev) => ({ ...prev, modelsLoadStatus: 'success' })); debug.log( `Loaded ${modelInfos.length} models for ${state.selectedProvider}`, ); } catch (error) { + if (cancelled) return; debug.log(`Failed to load models: ${error}`); setAvailableModels([]); setState((prev) => ({ ...prev, modelsLoadStatus: 'error' })); } }; loadModels(); + return () => { + cancelled = true; + }; }, [runtime, state.selectedProvider]);
171-183:onAuthCompletelogs stalestate.selectedProviderdue to closure.The
debug.logon line 173-175 capturesstate.selectedProviderfrom the closure, but this value might be stale if the callback is invoked after state has changed. Since this is only for logging, it's a minor issue, but be aware the logged value may not reflect the actual current state.docs/plans/2026-01-03-welcome-onboarding.md (1)
141-148: Plan document shows outdated step count (3 steps vs 5 in implementation).The plan document shows
WelcomeSteptype without'model'step, and UI text shows "Step X of 3". The actual implementation (useWelcomeOnboarding.ts) has 5 steps including'model'and UI shows "Step 4 of 5". This is expected since the model selection was added after the initial plan, but consider updating the plan document to reflect the final implementation for future reference.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (19)
docs/plans/2026-01-03-welcome-onboarding.mdpackages/cli/src/config/welcomeConfig.tspackages/cli/src/ui/AppContainer.tsxpackages/cli/src/ui/components/DialogManager.tsxpackages/cli/src/ui/components/WelcomeOnboarding/AuthMethodStep.tsxpackages/cli/src/ui/components/WelcomeOnboarding/AuthenticationStep.tsxpackages/cli/src/ui/components/WelcomeOnboarding/CompletionStep.tsxpackages/cli/src/ui/components/WelcomeOnboarding/ModelSelectStep.tsxpackages/cli/src/ui/components/WelcomeOnboarding/ProviderSelectStep.tsxpackages/cli/src/ui/components/WelcomeOnboarding/SkipExitStep.tsxpackages/cli/src/ui/components/WelcomeOnboarding/WelcomeDialog.tsxpackages/cli/src/ui/components/WelcomeOnboarding/WelcomeStep.tsxpackages/cli/src/ui/components/WelcomeOnboarding/index.tspackages/cli/src/ui/contexts/UIActionsContext.tsxpackages/cli/src/ui/contexts/UIStateContext.tsxpackages/cli/src/ui/hooks/useWelcomeOnboarding.tspackages/cli/src/ui/layouts/DefaultAppLayout.tsxproject-plans/welcome-onboarding/DESIGN.mdproject-plans/welcome-onboarding/PRD.md
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Don't useany- Always specify proper types. Useunknownif the type is truly unknown and add proper type guards.
Do not useconsole.logorconsole.debug- Use the sophisticated logging system instead. Log files are written to ~/.llxprt/debug/
Fix all linting errors, including warnings aboutanytypes
Files:
packages/cli/src/ui/layouts/DefaultAppLayout.tsxpackages/cli/src/ui/components/WelcomeOnboarding/AuthMethodStep.tsxpackages/cli/src/ui/components/WelcomeOnboarding/ModelSelectStep.tsxpackages/cli/src/ui/components/WelcomeOnboarding/ProviderSelectStep.tsxpackages/cli/src/ui/components/WelcomeOnboarding/WelcomeDialog.tsxpackages/cli/src/ui/contexts/UIActionsContext.tsxpackages/cli/src/ui/contexts/UIStateContext.tsxpackages/cli/src/ui/components/WelcomeOnboarding/CompletionStep.tsxpackages/cli/src/ui/hooks/useWelcomeOnboarding.tspackages/cli/src/ui/components/WelcomeOnboarding/WelcomeStep.tsxpackages/cli/src/ui/components/WelcomeOnboarding/AuthenticationStep.tsxpackages/cli/src/ui/AppContainer.tsxpackages/cli/src/ui/components/DialogManager.tsxpackages/cli/src/ui/components/WelcomeOnboarding/SkipExitStep.tsxpackages/cli/src/config/welcomeConfig.tspackages/cli/src/ui/components/WelcomeOnboarding/index.ts
**/*.md
📄 CodeRabbit inference engine (CLAUDE.md)
Documentation-only changes (*.md files, docs/) do NOT require build/test/lint cycle
Files:
project-plans/welcome-onboarding/PRD.mdproject-plans/welcome-onboarding/DESIGN.mddocs/plans/2026-01-03-welcome-onboarding.md
🧠 Learnings (1)
📚 Learning: 2025-12-12T23:31:19.937Z
Learnt from: acoliver
Repo: vybestack/llxprt-code PR: 779
File: project-plans/20251212issue488/PLAN.md:1-7
Timestamp: 2025-12-12T23:31:19.937Z
Learning: Do not validate or review plan documents in the vybestack/llxprt-code repository after implementation. Specifically, skip validation for files under project-plans (e.g., project-plans/**/PLAN.md) once the feature is implemented; these documents are not checked in reviews post-implementation.
Applied to files:
project-plans/welcome-onboarding/PRD.mdproject-plans/welcome-onboarding/DESIGN.md
🧬 Code graph analysis (7)
packages/cli/src/ui/components/WelcomeOnboarding/ModelSelectStep.tsx (4)
packages/cli/src/ui/hooks/useWelcomeOnboarding.ts (2)
ModelInfo(57-60)ModelsLoadStatus(27-27)packages/cli/src/ui/components/shared/RadioButtonSelect.tsx (2)
RadioSelectItem(21-25)RadioButtonSelect(56-100)packages/cli/src/ui/hooks/useKeypress.ts (1)
useKeypress(23-41)packages/cli/src/ui/colors.ts (1)
Colors(12-78)
packages/cli/src/ui/components/WelcomeOnboarding/WelcomeDialog.tsx (13)
packages/cli/src/ui/hooks/useWelcomeOnboarding.ts (4)
WelcomeState(29-37)WelcomeActions(39-50)ModelInfo(57-60)WelcomeStep(18-25)packages/cli/src/ui/components/WelcomeOnboarding/index.ts (7)
WelcomeDialog(7-7)WelcomeStep(8-8)ProviderSelectStep(9-9)AuthMethodStep(10-10)AuthenticationStep(11-11)CompletionStep(12-12)SkipExitStep(13-13)packages/cli/src/ui/hooks/useKeypress.ts (1)
useKeypress(23-41)scripts/oldui-tmux-harness.js (1)
key(274-274)packages/cli/src/ui/components/WelcomeOnboarding/WelcomeStep.tsx (2)
WelcomeChoice(15-15)WelcomeStep(22-70)packages/cli/src/ui/components/WelcomeOnboarding/ProviderSelectStep.tsx (1)
ProviderSelectStep(32-90)packages/cli/src/ui/components/WelcomeOnboarding/ModelSelectStep.tsx (1)
ModelSelectStep(29-129)packages/cli/src/ui/components/WelcomeOnboarding/AuthMethodStep.tsx (1)
AuthMethodStep(36-120)packages/cli/src/ui/components/WelcomeOnboarding/AuthenticationStep.tsx (1)
AuthenticationStep(27-174)packages/cli/src/ui/components/WelcomeOnboarding/CompletionStep.tsx (1)
CompletionStep(21-162)packages/cli/src/ui/components/WelcomeOnboarding/SkipExitStep.tsx (1)
SkipExitStep(17-57)packages/cli/test-utils/ink-stub.ts (1)
Box(22-22)packages/cli/src/ui/colors.ts (1)
Colors(12-78)
packages/cli/src/ui/contexts/UIStateContext.tsx (1)
packages/cli/src/ui/hooks/useWelcomeOnboarding.ts (2)
WelcomeState(29-37)ModelInfo(57-60)
packages/cli/src/ui/components/WelcomeOnboarding/CompletionStep.tsx (2)
packages/cli/src/ui/hooks/useKeypress.ts (1)
useKeypress(23-41)packages/cli/src/ui/colors.ts (1)
Colors(12-78)
packages/cli/src/ui/hooks/useWelcomeOnboarding.ts (3)
packages/cli/src/config/settings.ts (1)
LoadedSettings(339-467)packages/cli/src/ui/contexts/RuntimeContext.tsx (1)
useRuntimeApi(187-189)packages/cli/src/config/welcomeConfig.ts (2)
isWelcomeCompleted(80-82)markWelcomeCompleted(72-78)
packages/cli/src/ui/AppContainer.tsx (1)
packages/cli/src/ui/hooks/useWelcomeOnboarding.ts (1)
useWelcomeOnboarding(75-348)
packages/cli/src/ui/components/WelcomeOnboarding/SkipExitStep.tsx (3)
packages/cli/src/ui/components/WelcomeOnboarding/index.ts (1)
SkipExitStep(13-13)packages/cli/src/ui/hooks/useKeypress.ts (1)
useKeypress(23-41)packages/cli/src/ui/colors.ts (1)
Colors(12-78)
🪛 LanguageTool
project-plans/welcome-onboarding/PRD.md
[grammar] ~541-~541: Ensure spelling is correct
Context: ...-017]** Welcome flow shall start within 500ms of app launch. - [REQ-017.1] Firs...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🪛 markdownlint-cli2 (0.18.1)
project-plans/welcome-onboarding/PRD.md
18-18: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
27-27: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
93-93: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
94-94: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
95-95: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
98-98: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
99-99: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
100-100: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
103-103: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
104-104: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
105-105: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
106-106: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
109-109: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
110-110: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
111-111: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
112-112: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
115-115: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
116-116: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
117-117: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
118-118: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
121-121: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
122-122: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
123-123: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
124-124: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
127-127: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
128-128: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
129-129: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
132-132: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
133-133: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
134-134: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
137-137: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
138-138: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
139-139: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
140-140: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
141-141: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
142-142: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
147-147: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
148-148: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
149-149: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
150-150: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
151-151: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
154-154: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
155-155: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
156-156: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
157-157: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
160-160: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
161-161: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
162-162: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
165-165: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
166-166: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
167-167: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
172-172: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
173-173: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
174-174: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
177-177: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
178-178: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
179-179: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
182-182: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
183-183: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
184-184: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
189-189: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
210-210: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
229-229: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
250-250: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
265-265: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
280-280: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
297-297: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
447-447: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
542-542: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
543-543: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
546-546: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
547-547: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
552-552: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
553-553: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
554-554: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
557-557: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
558-558: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
559-559: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
564-564: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
565-565: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
566-566: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
569-569: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
570-570: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
571-571: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
578-578: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
579-579: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
580-580: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
583-583: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
584-584: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
585-585: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
588-588: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
589-589: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
590-590: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
593-593: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
594-594: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
595-595: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
598-598: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
599-599: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
600-600: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
605-605: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
606-606: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
607-607: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
610-610: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
611-611: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
612-612: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
615-615: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
616-616: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
617-617: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
652-652: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
653-653: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
654-654: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
655-655: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
658-658: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
659-659: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
660-660: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
661-661: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
664-664: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
665-665: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
666-666: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
667-667: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
670-670: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
671-671: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
672-672: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
696-696: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
701-701: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
706-706: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
711-711: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
716-716: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
807-807: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
813-813: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
819-819: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
825-825: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
852-852: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
863-863: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
project-plans/welcome-onboarding/DESIGN.md
19-19: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
38-38: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/plans/2026-01-03-welcome-onboarding.md
19-19: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
106-106: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
121-121: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
318-318: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
333-333: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
408-408: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
423-423: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
515-515: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
530-530: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
653-653: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
668-668: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
824-824: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
839-839: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
990-990: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1005-1005: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1067-1067: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1083-1083: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1211-1211: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1229-1229: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1244-1244: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1253-1253: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1262-1262: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1284-1284: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1320-1320: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1330-1330: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1346-1346: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1364-1364: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1375-1375: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1383-1383: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1387-1387: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1393-1393: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1397-1397: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1403-1403: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1409-1409: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1420-1420: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1426-1426: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1432-1432: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
1442-1442: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
🔇 Additional comments (27)
packages/cli/src/ui/layouts/DefaultAppLayout.tsx (1)
146-165: LGTM!The addition of
uiState.isWelcomeDialogOpento thedialogsVisiblecheck is consistent with the existing pattern for other dialogs and correctly integrates the welcome onboarding flow into the layout's dialog management.packages/cli/src/ui/components/DialogManager.tsx (2)
12-12: LGTM!The import statement correctly adds the WelcomeDialog component for onboarding integration.
102-112: LGTM!The WelcomeDialog integration follows the established pattern of other dialogs in this file. The conditional rendering based on
uiState.isWelcomeDialogOpenand the props passed align with the onboarding feature design.packages/cli/src/ui/contexts/UIStateContext.tsx (2)
30-30: LGTM!The import statement correctly brings in the necessary types for the welcome onboarding feature.
160-164: LGTM!The welcome onboarding fields added to the
UIStateinterface are well-typed and align with the onboarding feature requirements. The typesWelcomeStateandModelInfoare properly imported and defined in the related hook module.packages/cli/src/ui/components/WelcomeOnboarding/SkipExitStep.tsx (1)
1-57: LGTM! Clean and focused component.This component is well-implemented with proper TypeScript typing, correct use of the
useKeypresshook, and clear user guidance. The keyboard interaction (Enter to continue) is intuitive and properly gated by theisFocusedprop.packages/cli/src/ui/components/WelcomeOnboarding/WelcomeStep.tsx (1)
1-70: LGTM! Well-structured onboarding entry point.The component provides a clear initial choice for users with helpful descriptive text and proper keyboard navigation hints. TypeScript types are well-defined, and the integration with
RadioButtonSelectis correct.packages/cli/src/ui/components/WelcomeOnboarding/CompletionStep.tsx (2)
37-54: LGTM! Excellent error handling pattern.The
handleProfileSubmitfunction demonstrates proper error handling with type-safe narrowing fromunknowntoError. The validation logic (trimmed name check) and state management are well-implemented.
57-89: LGTM! Robust keyboard input handling.The keypress handler correctly manages multiple input scenarios: submission, dismissal, backspace/delete, and printable character input. The filtering to printable ASCII characters (line 82) is a good defensive practice that handles paste operations safely.
packages/cli/src/ui/contexts/UIActionsContext.tsx (1)
84-102: LGTM! Well-designed onboarding actions interface.The new welcome onboarding actions are properly typed and integrate cleanly into the existing
UIActionsinterface. The method signatures are intuitive, with appropriate async handling forsaveProfileandtriggerWelcomeAuth. The optionalapiKeyparameter intriggerWelcomeAuthcorrectly accommodates both OAuth and API key authentication flows.packages/cli/src/ui/components/WelcomeOnboarding/AuthMethodStep.tsx (2)
46-81: LGTM! Excellent use of React optimization hooks.The component properly uses
useMemoto memoize the options array (only recomputing whensupportsOAuthchanges) anduseCallbackto memoize the selection handler. The dependency arrays are correct, ensuring optimal performance without stale closures.
1-120: LGTM! Well-architected authentication method selection.The component elegantly handles provider-specific authentication capabilities, conditionally offering OAuth when supported while always providing API key fallback. The hardcoded provider configurations (lines 16, 18-24) are appropriate for this onboarding context, and the UI provides helpful hints like API key URLs.
packages/cli/src/ui/components/WelcomeOnboarding/WelcomeDialog.tsx (1)
1-146: LGTM! Well-structured onboarding orchestration.The component properly orchestrates the multi-step onboarding flow with:
- Defensive null guards for steps requiring prerequisites (lines 79, 91, 102, 115)
- Global escape handling that respects authentication state
- Clean switch-based step rendering
- Proper TypeScript typing throughout
project-plans/welcome-onboarding/PRD.md (1)
1-879: Skipping review of plan document per established guidance.Based on learnings, plan documents under project-plans/ are not reviewed after implementation.
packages/cli/src/ui/components/WelcomeOnboarding/ModelSelectStep.tsx (1)
1-129: LGTM! Comprehensive state handling for model selection.The component properly handles all model loading states:
- Loading, error, success (with/without models)
- Escape key recovery in error and empty states (lines 68-75)
- Clear user guidance for each state
- Proper TypeScript typing with no
anyusagepackages/cli/src/ui/components/WelcomeOnboarding/ProviderSelectStep.tsx (1)
1-90: LGTM! Clean provider selection with graceful fallback.The component properly handles provider display with:
- Fallback for unmapped provider IDs (line 40:
PROVIDER_DISPLAY_NAMES[provider] || provider)- Clear skip option handling via sentinel value
- Appropriate max visible items (8) for provider list
- Proper TypeScript typing throughout
packages/cli/src/ui/AppContainer.tsx (3)
629-640: LGTM! Proper welcome onboarding integration.The hook integration correctly:
- Sequences after folder trust (line 639:
isFolderTrustComplete: !isFolderTrustDialogOpen && !isRestarting)- Exposes all necessary state and actions for the onboarding flow
- Maintains consistent naming with other dialog patterns
1500-1519: LGTM! Initial prompt properly gated.The initial prompt submission correctly waits for welcome dialog completion (line 1500), ensuring new users complete onboarding before any automated queries run.
1651-1655: LGTM! UI state and actions properly extended.The welcome onboarding state and actions are correctly:
- Added to UIState (lines 1651-1655)
- Added to UIActions (lines 1734-1736)
- Included in memoization dependencies (lines 1821-1822)
This follows the established pattern for other dialogs in the application.
Also applies to: 1734-1736, 1821-1822
packages/cli/src/ui/components/WelcomeOnboarding/AuthenticationStep.tsx (3)
79-87: API key character filtering is correct and handles paste securely.The regex
/[^\x20-\x7E]/gcorrectly filters to printable ASCII characters, which is appropriate for API keys. The implementation properly handles both single keystrokes and pasted multi-character sequences. The bullet masking on line 136 ensures the key is never displayed in plain text.
42-55: LGTM - handleApiKeySubmit has proper error handling.The callback correctly:
- Guards against empty input
- Sets loading state before async operation
- Resets loading state on error
- Properly extracts error messages from unknown error types
57-90: Escape key handling during authentication could be clearer.The escape key check on line 60 allows going back even when
method !== 'api_key'(i.e., during OAuth), but line 65-67 only processes other keys forapi_keymode. This is intentional but the logic flow could be clearer. The current behavior is correct - Escape works in both modes when not authenticating.packages/cli/src/ui/hooks/useWelcomeOnboarding.ts (3)
220-264: Profile saving implementation is thorough with good error handling and logging.The
saveProfilefunction:
- Checks for duplicate profile names before saving
- Saves the profile snapshot
- Sets it as default for auto-load on startup
- Loads the profile immediately in the current session
- Has comprehensive debug logging throughout
- Properly propagates errors to the caller
273-327: triggerAuth handles provider switching and auth comprehensively.The implementation correctly:
- Switches the active provider first using
switchActiveProvider- Sets the selected model if available
- Handles both OAuth and API key authentication paths
- Throws appropriate errors for missing OAuth manager or API key
- Includes detailed debug logging
One minor observation: if
state.selectedModelis set butsetActiveModelfails, the error isn't caught separately - it would propagate to the caller which is acceptable behavior.
198-217:goBackfunction is missing the'model'step transition.The switch statement handles transitions from
model → provider, but the current'model'case clearsselectedProviderwhich seems incorrect. Going back from model selection should preserve the provider and just go back to provider selection for re-selection. However, looking more carefully, this appears intentional to allow the user to choose a different provider.Actually, the logic seems correct:
- From
model→ go toproviderand clearselectedProvider(to re-select)- From
auth_method→ go tomodeland clearselectedModeldocs/plans/2026-01-03-welcome-onboarding.md (2)
1-1464: Overall plan document provides comprehensive implementation guidance.The document successfully outlines:
- Config persistence with
welcomeConfig.ts- State management with
useWelcomeOnboardinghook- Component architecture with step-based navigation
- Integration points in AppContainer and DefaultAppLayout
- Testing and manual verification steps
The static analysis markdownlint warnings (MD036) about "Emphasis used instead of a heading" are false positives for this plan document format - the
**Step X:**pattern is an intentional stylistic choice that aids readability.
89-91: The actual implementation (packages/cli/src/config/welcomeConfig.ts:68) usesconsole.error, violating the coding guideline for**/*.{ts,tsx}files.Replace
console.error('Error saving welcome config:', error);with the sophisticated logging system (DebugLogger) per coding guidelines. The documentation file itself does not require changes as markdown files are excluded from code guidelines.⛔ Skipped due to learnings
Learnt from: CR Repo: vybestack/llxprt-code PR: 0 File: CLAUDE.md:0-0 Timestamp: 2025-12-05T14:59:34.368Z Learning: Applies to **/*.{ts,tsx} : Do not use `console.log` or `console.debug` - Use the sophisticated logging system instead. Log files are written to ~/.llxprt/debug/
| try { | ||
| if (fs.existsSync(configPath)) { | ||
| const content = fs.readFileSync(configPath, 'utf-8'); | ||
| cachedConfig = JSON.parse(content) as WelcomeConfig; | ||
| return cachedConfig; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add runtime validation for parsed config structure.
The type assertion as WelcomeConfig at Line 42 assumes the JSON structure is valid without verification. If the file is corrupted or manually edited, this could lead to runtime errors elsewhere.
🔎 Proposed fix with validation
export function loadWelcomeConfig(): WelcomeConfig {
if (cachedConfig) {
return cachedConfig;
}
const configPath = getWelcomeConfigPath();
try {
if (fs.existsSync(configPath)) {
const content = fs.readFileSync(configPath, 'utf-8');
- cachedConfig = JSON.parse(content) as WelcomeConfig;
+ const parsed = JSON.parse(content);
+
+ // Validate structure
+ if (
+ typeof parsed === 'object' &&
+ parsed !== null &&
+ typeof parsed.welcomeCompleted === 'boolean'
+ ) {
+ cachedConfig = parsed as WelcomeConfig;
+ } else {
+ // Invalid structure, fall through to default
+ throw new Error('Invalid config structure');
+ }
return cachedConfig;
}
} catch (_error) {
// If parsing fails, return default
}
cachedConfig = { welcomeCompleted: false };
return cachedConfig;
}🤖 Prompt for AI Agents
In packages/cli/src/config/welcomeConfig.ts around lines 39 to 44, the JSON is
parsed and cast to WelcomeConfig without runtime validation; replace the blind
type assertion with a validation step: after JSON.parse, validate that the
resulting object has the expected properties and types (e.g., required keys,
string/boolean/array shapes) using a small inline check or an existing
schema/validator function, log or handle parse/validation errors (delete or
ignore invalid file and return a safe default cachedConfig) instead of returning
a malformed object, and ensure cachedConfig is only assigned when validation
succeeds.
| }); | ||
| cachedConfig = config; | ||
| } catch (error) { | ||
| console.error('Error saving welcome config:', error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace console.error with the logging system.
The coding guidelines explicitly prohibit console.error and require using the sophisticated logging system. Log files are written to ~/.llxprt/debug/.
🔎 Proposed fix
+import { Logger } from '@vybestack/llxprt-code-core';
+
+const logger = new Logger('welcomeConfig');
+
export function saveWelcomeConfig(config: WelcomeConfig): void {
const configPath = getWelcomeConfigPath();
try {
const dirPath = path.dirname(configPath);
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), {
encoding: 'utf-8',
mode: 0o600,
});
cachedConfig = config;
} catch (error) {
- console.error('Error saving welcome config:', error);
+ logger.error('Error saving welcome config:', error);
}
}As per coding guidelines.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| console.error('Error saving welcome config:', error); | |
| import { Logger } from '@vybestack/llxprt-code-core'; | |
| const logger = new Logger('welcomeConfig'); | |
| export function saveWelcomeConfig(config: WelcomeConfig): void { | |
| const configPath = getWelcomeConfigPath(); | |
| try { | |
| const dirPath = path.dirname(configPath); | |
| if (!fs.existsSync(dirPath)) { | |
| fs.mkdirSync(dirPath, { recursive: true }); | |
| } | |
| fs.writeFileSync(configPath, JSON.stringify(config, null, 2), { | |
| encoding: 'utf-8', | |
| mode: 0o600, | |
| }); | |
| cachedConfig = config; | |
| } catch (error) { | |
| logger.error('Error saving welcome config:', error); | |
| } | |
| } |
🤖 Prompt for AI Agents
In packages/cli/src/config/welcomeConfig.ts at line 68, replace the
console.error call with the project's logging system: import or obtain the
module logger used across the CLI (the central logger that writes to
~/.llxprt/debug/), remove the console.error invocation, and call logger.error
with a clear message and the caught error object so the error details are
recorded (e.g., logger.error("Error saving welcome config", error)); ensure the
logger import/usage follows the same pattern as other CLI modules.
| export { WelcomeDialog } from './WelcomeDialog.js'; | ||
| export { WelcomeStep } from './WelcomeStep.js'; | ||
| export { ProviderSelectStep } from './ProviderSelectStep.js'; | ||
| export { AuthMethodStep } from './AuthMethodStep.js'; | ||
| export { AuthenticationStep } from './AuthenticationStep.js'; | ||
| export { CompletionStep } from './CompletionStep.js'; | ||
| export { SkipExitStep } from './SkipExitStep.js'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# Check if ModelSelectStep component exists
fd -t f "ModelSelectStep" packages/cli/src/ui/components/WelcomeOnboarding/Repository: vybestack/llxprt-code
Length of output: 133
🏁 Script executed:
# List all files in the WelcomeOnboarding directory to see what actually exists
ls -la packages/cli/src/ui/components/WelcomeOnboarding/Repository: vybestack/llxprt-code
Length of output: 781
🏁 Script executed:
# Check the current index.ts to see all exports
cat -n packages/cli/src/ui/components/WelcomeOnboarding/index.tsRepository: vybestack/llxprt-code
Length of output: 629
🏁 Script executed:
# Search for any references to ModelSelectStep in the codebase
rg "ModelSelectStep" packages/cli/Repository: vybestack/llxprt-code
Length of output: 518
Add ModelSelectStep export to the barrel file.
The ModelSelectStep component exists and is actively used by WelcomeDialog, but it's not exported from the barrel file while all other step components are. This breaks the consistent API surface for the module and should be exported to match the pattern.
Add this line to packages/cli/src/ui/components/WelcomeOnboarding/index.ts:
export { ModelSelectStep } from './ModelSelectStep.js';
🤖 Prompt for AI Agents
In packages/cli/src/ui/components/WelcomeOnboarding/index.ts around lines 7 to
13, the barrel file is missing an export for ModelSelectStep which is used by
WelcomeDialog; add an export for the component to match the other step exports
by adding an export line for ModelSelectStep that re-exports it from
'./ModelSelectStep.js'.
🎯 Purpose
Provide a structured, guided onboarding experience for first-time llxprt users. The 5-step wizard helps users set up their AI provider, choose their preferred model, configure authentication, and save their setup as a reusable profile that auto-loads on every startup.
📋 Summary
🔄 Onboarding Flow
Step 1 of 5: Choose Your AI Provider
Users select from available AI providers (Anthropic, OpenAI, Google Gemini, etc.) with human-friendly display names. Option to skip and configure manually later.
UI: Radio button selection with provider names
Actions: Next → Step 2, Skip → Skip Exit
Step 2 of 5: Choose Your Model
After selecting a provider, available models are automatically loaded and displayed. Users pick their preferred model for that provider.
UI: Loading spinner during fetch, error state with recovery option, radio button selection for models
Features:
Actions: Next → Step 3, Back → Step 1, Escape → Step 1
Step 3 of 5: Choose Authentication Method
Users select between OAuth (recommended) or API key authentication. Provider-specific API key URLs are shown for guidance.
UI: Radio buttons for OAuth vs API Key with descriptions
Features:
Actions: Select → Step 4 (Authenticating), Back → Step 2
Step 4 of 5: Authenticate
Two paths based on auth method choice:
OAuth Path:
API Key Path:
UI: Spinner + status message during auth
Features:
Actions: Complete → Step 5, Error → Step 3, Escape → Step 3
Step 5 of 5: Save Your Profile
User names their configuration profile. The profile is saved, set as default, and immediately loaded in the current session.
UI: Text input for profile name
Features:
Actions: Save → Completion (shows next steps), Done → Exit onboarding
🛡️ Error Handling & Recovery
Model Loading Failures
Authentication Failures
Profile Save Failures
State Guard Failures
✅ Validation
🔐 Security
🧪 Testing
Reset onboarding to trigger again:
rm ~/.llxprt/welcomeConfig.jsonThen restart llxprt to see the welcome wizard.
Images
Summary by CodeRabbit
Release Notes
✏️ Tip: You can customize this high-level summary in your review settings.