/**
* First-run wizard (L5). Shown on the very first IDE launch: it offers the
* pre-filled, selectable reference profiles (Claude/Codex — only AIs drivable in
* structured mode, §17.6/D7) with **editable** commands, lets the user detect
* which CLIs are installed (✓/✗), then saves the chosen profiles and closes the
* first run.
*
* The candidate list is already filtered server-side (`reference_profiles` only
* exposes selectable profiles), so the wizard renders whatever it receives.
* Adding an arbitrary custom profile is no longer offered, since we cannot drive
* it in structured mode.
*
* Pure presentation: all behaviour comes from {@link useFirstRun} (the
* {@link ProfileGateway} port). Profile validation is the pure logic in
* `./profile`.
*/
import type {
AgentProfile,
HttpChatConfig,
LocalModelServerConfig,
} from "@/domain";
import { useEffect, useState } from "react";
import { Button, IconButton, Input, Panel, Toolbar, cn } from "@/shared";
import { useI18n } from "@/i18n";
import {
ModelServersPanel,
useModelServers,
} from "@/features/model-servers";
import { useFirstRun, type WizardEntry } from "./useFirstRun";
import {
defaultHttpChatConfig,
parseArgs,
validateProfile,
type ProfileErrors,
} from "./profile";
import {
OpenCodeModeFields,
useOpenCodeProviderCatalog,
type OpenCodeProviderCatalog,
} from "./OpenCodeModeFields";
/** A small caption above a control. */
function Caption({ children }: { children: React.ReactNode }) {
return {children};
}
/**
* Renders the wizard when it is the first run. Calls `onDone` once the user
* finishes (so the host can drop the wizard and show the normal UI). Returns
* Returns `null` while loading. By default it also returns `null` once the first
* run is done (auto-show path in {@link App}); pass `forceOpen` to render it
* regardless — used by "Settings ▸ Configure profiles" to reopen the wizard after
* the first run.
*/
export function FirstRunWizard({
onDone,
forceOpen = false,
}: {
onDone?: () => void;
/** Render the wizard even when it is no longer the first run. */
forceOpen?: boolean;
}) {
const { tr } = useI18n();
// Mode is explicit (ticket #44), driven by the entry point — never inferred
// from `isFirstRun`: reopening from Settings (`forceOpen`) is the "edit" mode,
// which pre-loads and pre-selects the already-configured profiles.
const vm = useFirstRun(forceOpen ? "edit" : "firstRun");
const modelServers = useModelServers();
const providerCatalog = useOpenCodeProviderCatalog();
if (vm.isFirstRun === null) return null;
if (!forceOpen && vm.isFirstRun === false) return null;
async function finish() {
await vm.finish();
onDone?.();
}
return (
{tr("Bienvenue dans IdeA", "Welcome to IdeA")}
{tr("Choisissez les CLI d’IA à configurer. Les commandes sont préremplies et modifiables.", "Choose which AI CLIs to configure. Commands are pre-filled and editable.")}
}
>
{vm.error && (
{vm.error}
)}
{/* `detecting` deliberately does NOT disable this button (ticket #28):
detection is best-effort and may never answer. */}
{vm.detecting && (
{tr("Détection…", "Detecting…")}
)}
{/* F36: declare several local OpenCode profiles. Each click clones the
canonical `opencode-llamacpp` seed into a new, editable row. */}
{/* F35.2 — declare/edit/delete the local llama.cpp servers an OpenCode
profile can bind to. Sits above the profile list so a server exists
before it is picked in the OpenCode dropdown. */}