diff --git a/src/wizard/onboarding.finalize.ts b/src/wizard/onboarding.finalize.ts index 9ef3024b41..3ec0c50aca 100644 --- a/src/wizard/onboarding.finalize.ts +++ b/src/wizard/onboarding.finalize.ts @@ -6,7 +6,9 @@ import type { RuntimeEnv } from "../runtime.js"; import type { GatewayWizardSettings, WizardFlow } from "./onboarding.types.js"; import type { WizardPrompter } from "./prompts.js"; import { DEFAULT_BOOTSTRAP_FILENAME } from "../agents/workspace.js"; +import { resolveCliName } from "../cli/cli-name.js"; import { formatCliCommand } from "../cli/command-format.js"; +import { installCompletion } from "../cli/completion-cli.js"; import { buildGatewayInstallPlan, gatewayInstallErrorHint, @@ -15,6 +17,10 @@ import { DEFAULT_GATEWAY_DAEMON_RUNTIME, GATEWAY_DAEMON_RUNTIME_OPTIONS, } from "../commands/daemon-runtime.js"; +import { + checkShellCompletionStatus, + ensureCompletionCacheExists, +} from "../commands/doctor-completion.js"; import { formatHealthCheckFailure } from "../commands/health-format.js"; import { healthCommand } from "../commands/health.js"; import { @@ -387,6 +393,51 @@ export async function finalizeOnboardingWizard( "Security", ); + // Shell completion setup + const cliName = resolveCliName(); + const completionStatus = await checkShellCompletionStatus(cliName); + + if (completionStatus.usesSlowPattern) { + // Case 1: Profile uses slow dynamic pattern - silently upgrade to cached version + const cacheGenerated = await ensureCompletionCacheExists(cliName); + if (cacheGenerated) { + await installCompletion(completionStatus.shell, true, cliName); + } + } else if (completionStatus.profileInstalled && !completionStatus.cacheExists) { + // Case 2: Profile has completion but no cache - auto-fix silently + await ensureCompletionCacheExists(cliName); + } else if (!completionStatus.profileInstalled) { + // Case 3: No completion at all - prompt to install + const installShellCompletion = await prompter.confirm({ + message: `Enable ${completionStatus.shell} shell completion for ${cliName}?`, + initialValue: true, + }); + if (installShellCompletion) { + // Generate cache first (required for fast shell startup) + const cacheGenerated = await ensureCompletionCacheExists(cliName); + if (cacheGenerated) { + // Install to shell profile + await installCompletion(completionStatus.shell, true, cliName); + const profileHint = + completionStatus.shell === "zsh" + ? "~/.zshrc" + : completionStatus.shell === "bash" + ? "~/.bashrc" + : "~/.config/fish/config.fish"; + await prompter.note( + `Shell completion installed. Restart your shell or run: source ${profileHint}`, + "Shell completion", + ); + } else { + await prompter.note( + `Failed to generate completion cache. Run \`${cliName} completion --install\` later.`, + "Shell completion", + ); + } + } + } + // Case 4: Both profile and cache exist (using cached version) - all good, nothing to do + const shouldOpenControlUi = !opts.skipUi && settings.authMode === "token" &&