Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,9 @@ export const AuthMethodStep: React.FC<AuthMethodStepProps> = ({
<Text bold color={Colors.AccentCyan}>
Step 3 of 5: Choose Authentication Method
</Text>
<Text> </Text>
<Text>How would you like to authenticate with {providerDisplay}?</Text>
<Text color={Colors.Foreground}>
How would you like to authenticate with {providerDisplay}?
</Text>
</Box>

{error && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,18 @@ export const AuthenticationStep: React.FC<AuthenticationStepProps> = ({
<Text color={Colors.AccentYellow}>
<Spinner type="dots" />
</Text>{' '}
Opening browser for OAuth authentication...
<Text color={Colors.Foreground}>
Opening browser for OAuth authentication...
</Text>
</Text>
</Box>

<Text>Please complete the authentication in your browser.</Text>
<Text>This window will update when done.</Text>
<Text color={Colors.Foreground}>
Please complete the authentication in your browser.
</Text>
<Text color={Colors.Foreground}>
This window will update when done.
</Text>

<Box marginTop={1}>
<Text color={Colors.Gray}>Press Esc to cancel and go back</Text>
Expand All @@ -149,18 +155,20 @@ export const AuthenticationStep: React.FC<AuthenticationStepProps> = ({
<Text color={Colors.AccentYellow}>
<Spinner type="dots" />
</Text>{' '}
Validating API key...
<Text color={Colors.Foreground}>Validating API key...</Text>
</Text>
</Box>
) : (
<>
<Box marginBottom={1}>
<Text>Enter your {providerDisplay} API key:</Text>
<Text color={Colors.Foreground}>
Enter your {providerDisplay} API key:
</Text>
</Box>

<Box>
<Text>API Key: </Text>
<Text>{maskedValue}</Text>
<Text color={Colors.Foreground}>API Key: </Text>
<Text color={Colors.Foreground}>{maskedValue}</Text>
<Text color={Colors.AccentCyan}>▌</Text>
</Box>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,22 +94,23 @@ export const CompletionStep: React.FC<CompletionStepProps> = ({
<Text bold color={Colors.AccentCyan}>
Step 5 of 5: Save Your Profile
</Text>
<Text> </Text>
<Text bold color={Colors.AccentGreen}>
{'✓ Authentication complete!'}
[OK] Authentication complete!
</Text>
</Box>

<Box flexDirection="column" marginBottom={1}>
<Text>Provider: {providerDisplay}</Text>
{model && <Text>Model: {model}</Text>}
<Text>Authentication: {authDisplay}</Text>
<Text color={Colors.Foreground}>Provider: {providerDisplay}</Text>
{model && <Text color={Colors.Foreground}>Model: {model}</Text>}
<Text color={Colors.Foreground}>Authentication: {authDisplay}</Text>
</Box>

{showProfilePrompt ? (
<Box flexDirection="column">
<Box marginBottom={1}>
<Text bold>Save this setup as a profile</Text>
<Text bold color={Colors.Foreground}>
Save this setup as a profile
</Text>
</Box>

<Text color={Colors.Gray}>
Expand All @@ -127,11 +128,11 @@ export const CompletionStep: React.FC<CompletionStepProps> = ({
)}

{saving ? (
<Text>Saving profile...</Text>
<Text color={Colors.Foreground}>Saving profile...</Text>
) : (
<Box>
<Text>Profile name: </Text>
<Text>{profileName}</Text>
<Text color={Colors.Foreground}>Profile name: </Text>
<Text color={Colors.Foreground}>{profileName}</Text>
<Text color={Colors.AccentCyan}>▌</Text>
</Box>
)}
Expand All @@ -146,7 +147,7 @@ export const CompletionStep: React.FC<CompletionStepProps> = ({
) : (
<Box flexDirection="column">
<Box marginBottom={1}>
<Text>Try asking me something like:</Text>
<Text color={Colors.Foreground}>Try asking me something like:</Text>
<Text color={Colors.AccentCyan}>
{'"Explain how async/await works in JavaScript"'}
</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,10 @@ export const ModelSelectStep: React.FC<ModelSelectStepProps> = ({
<Text bold color={Colors.AccentCyan}>
Step 2 of 5: Choose Your Model
</Text>
<Text> </Text>
<Text>Select a model for {providerDisplay}:</Text>
<Text color={Colors.Foreground}>
{' '}
Select a model for {providerDisplay}:
</Text>
</Box>

{modelsLoadStatus === 'loading' && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ export const ProviderSelectStep: React.FC<ProviderSelectStepProps> = ({
<Text bold color={Colors.AccentCyan}>
Step 1 of 5: Choose Your AI Provider
</Text>
<Text> </Text>
<Text>{"Select which AI provider you'd like to use:"}</Text>
<Text color={Colors.Foreground}>
{"Select which AI provider you'd like to use:"}
</Text>
</Box>

<RadioButtonSelect
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,22 @@ export const SkipExitStep: React.FC<SkipExitStepProps> = ({
return (
<Box flexDirection="column">
<Box flexDirection="column" marginBottom={1}>
<Text bold>Setup skipped</Text>
<Text bold color={Colors.Foreground}>
Setup skipped
</Text>
</Box>

<Box flexDirection="column" marginBottom={1}>
<Text>To configure llxprt manually:</Text>
<Text> </Text>
<Text>
<Text color={Colors.Foreground}>To configure llxprt manually:</Text>
<Text color={Colors.Foreground}>
• Use <Text color={Colors.AccentCyan}>/auth &lt;provider&gt;</Text> to
set up authentication
</Text>
<Text>
<Text color={Colors.Foreground}>
• Use <Text color={Colors.AccentCyan}>/provider</Text> to select your
AI provider
</Text>
<Text>
<Text color={Colors.Foreground}>
• Type <Text color={Colors.AccentCyan}>/help</Text> for more commands
</Text>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,20 @@ export const WelcomeStep: React.FC<WelcomeStepProps> = ({
<Text bold color={Colors.AccentCyan}>
Welcome to llxprt!
</Text>
<Text> </Text>
<Text>{"Let's get you set up in just a few steps."}</Text>
<Text>
<Text color={Colors.Foreground}>
{' '}
{"Let's get you set up in just a few steps."}
</Text>
<Text color={Colors.Foreground}>
{"You'll choose an AI provider and configure authentication"}
</Text>
<Text>so llxprt can work its magic.</Text>
<Text color={Colors.Foreground}>so llxprt can work its magic.</Text>
</Box>

<Box flexDirection="column" marginBottom={1}>
<Text bold>What would you like to do?</Text>
<Text bold color={Colors.Foreground}>
What would you like to do?
</Text>
</Box>

<RadioButtonSelect
Expand Down
68 changes: 65 additions & 3 deletions packages/cli/src/ui/hooks/useWelcomeOnboarding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { useState, useCallback, useEffect } from 'react';
import { useState, useCallback, useEffect, useMemo } from 'react';
import { DebugLogger } from '@vybestack/llxprt-code-core';
import { type LoadedSettings } from '../../config/settings.js';
import {
Expand All @@ -15,6 +15,8 @@

const debug = new DebugLogger('llxprt:ui:useWelcomeOnboarding');

const PLACEHOLDER_MODEL_NAMES = new Set(['placeholder-model']);

export type WelcomeStep =
| 'welcome'
| 'provider'
Expand Down Expand Up @@ -81,8 +83,68 @@
isWelcomeCompleted(),
);

// Only show welcome after folder trust is complete
const showWelcome = !welcomeCompleted && isFolderTrustComplete;
const isSystemDefaultModelName = useCallback((modelName: string): boolean => {

Check failure on line 86 in packages/cli/src/ui/hooks/useWelcomeOnboarding.ts

View workflow job for this annotation

GitHub Actions / Lint (Javascript)

Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`
return PLACEHOLDER_MODEL_NAMES.has(modelName);
}, []);
Comment on lines +86 to +88
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix ESLint arrow-body-style violation (CI failure).

The linter reports: "Unexpected block statement surrounding arrow body; move the returned value immediately after the =>".

🔎 Proposed fix
-  const isSystemDefaultModelName = useCallback((modelName: string): boolean => {
-    return PLACEHOLDER_MODEL_NAMES.has(modelName);
-  }, []);
+  const isSystemDefaultModelName = useCallback(
+    (modelName: string): boolean => PLACEHOLDER_MODEL_NAMES.has(modelName),
+    [],
+  );
📝 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.

Suggested change
const isSystemDefaultModelName = useCallback((modelName: string): boolean => {
return PLACEHOLDER_MODEL_NAMES.has(modelName);
}, []);
const isSystemDefaultModelName = useCallback(
(modelName: string): boolean => PLACEHOLDER_MODEL_NAMES.has(modelName),
[],
);
🧰 Tools
🪛 GitHub Actions: LLxprt Code CI

[error] 86-86: ESLint: Unexpected block statement surrounding arrow body; move the returned value immediately after the '=>' (arrow-body-style).

🪛 GitHub Check: Lint (Javascript)

[failure] 86-86:
Unexpected block statement surrounding arrow body; move the returned value immediately after the =>

🤖 Prompt for AI Agents
In @packages/cli/src/ui/hooks/useWelcomeOnboarding.ts around lines 86 - 88, The
arrow function is using a block body which triggers the ESLint arrow-body-style
rule; change the isSystemDefaultModelName declaration to use a concise arrow
body that directly returns the boolean expression (e.g., replace the block with
an expression using PLACEHOLDER_MODEL_NAMES.has(modelName)) so the function
becomes a single-expression arrow function.


const shouldSuppressWelcome = useMemo(() => {
// Always prefer showing onboarding until the user explicitly completes/skips it.
if (!isFolderTrustComplete || welcomeCompleted) {
return false;
}

// Non-interactive signals (CLI/env) that indicate the user already configured things.
// Keep this conservative: avoid treating system defaults as user configuration.

if (process.env.LLXPRT_PROFILE) {
debug.log('Welcome suppressed: LLXPRT_PROFILE environment variable set');
return true;
}

// If a provider is already active (typically set via CLI flags or prior usage),
// suppress welcome.
const providerManager = runtime.getCliProviderManager();
if (providerManager) {
try {
const providerName = providerManager.getActiveProviderName();
const hasActiveProvider =
providerManager.hasActiveProvider?.() ?? false;

if (providerName || hasActiveProvider) {
debug.log('Welcome suppressed: active provider configured');
return true;
}
} catch (error) {
debug.log('Could not check for active provider:', error);
}
}

try {
const activeModel = runtime.getActiveModelName();
if (activeModel && !isSystemDefaultModelName(activeModel)) {
debug.log('Welcome suppressed: active model configured');
return true;
}
} catch (error) {
debug.log('Could not check for active model:', error);
}

// Intentionally do NOT suppress based solely on defaultProfile. A profile can be
// present due to system defaults and should not skip onboarding unless the user
// has explicitly completed it.

return false;
}, [
isFolderTrustComplete,
isSystemDefaultModelName,
runtime,
welcomeCompleted,
]);

// Show welcome after folder trust is complete unless it was completed/skipped,
// or we detect a non-interactive configuration state.
const showWelcome =
!welcomeCompleted && isFolderTrustComplete && !shouldSuppressWelcome;

const [state, setState] = useState<WelcomeState>({
step: 'welcome',
Expand Down
Loading