Class: Rubino::CLI::OnboardingWizard
- Inherits:
-
Object
- Object
- Rubino::CLI::OnboardingWizard
- Defined in:
- lib/rubino/cli/onboarding_wizard.rb
Overview
First-run onboarding (#93). A small, skippable interactive wizard that takes a brand-new user from an empty home to a working model: pick a provider/model, paste the key (written to .env, never echoed back), and persist the matching model.default / model.provider / providers.<name> block to config.yml. The catalog mirrors DOCS-BLUEPRINT models-and-keys.
It is only invoked when no usable credential is configured AND we are on a real TTY (ChatCommand#ensure_model_configured!); non-interactive contexts get the actionable guidance instead. #run returns true on a completed setup, false if the user skipped — the caller re-checks usability either way, so a partial/declined run safely falls through to the guidance+exit.
Constant Summary collapse
- PROVIDERS =
Each provider: the model.provider to write, a default model id, the .env key var, and any providers.<name> config block to persist. Ordered so the recommended default comes first and matches the seeded config default (config/defaults.rb model.default => openai/gpt-4.1), keeping the from-zero experience consistent between the wizard and the non-interactive fail-fast guidance. OpenAI is the recommended default (maintainer directive); MiniMax stays a first-class selectable option — listed but NOT pushed or auto-selected — and carries the anthropic_compatible + base_url wiring it needs so picking it still yields a first-turn-working config.
[ { key: "openai", label: "OpenAI (GPT) — recommended default", provider: "openai", model: "gpt-4.1", env_var: "OPENAI_API_KEY", config: {} }, { key: "minimax", label: "MiniMax (Anthropic-compatible)", provider: "minimax", model: "MiniMax-M3", env_var: "MINIMAX_API_KEY", config: { "anthropic_compatible" => true, "base_url" => "https://api.minimax.io/anthropic", "api_key" => "${MINIMAX_API_KEY}" } }, { key: "anthropic", label: "Anthropic (Claude)", provider: "anthropic", model: "claude-sonnet-4-5", env_var: "ANTHROPIC_API_KEY", config: {} }, { key: "gemini", label: "Google (Gemini)", provider: "google", model: "gemini-2.5-pro", env_var: "GEMINI_API_KEY", config: {} }, { key: "gateway", label: "OpenAI-compatible gateway", provider: "gateway", model: "auto", env_var: "OPENAI_API_KEY", config: { "openai_compatible" => true, "assume_model_exists" => true, "base_url" => nil # filled in interactively } } ].freeze
Instance Method Summary collapse
-
#initialize(ui: Rubino.ui, input: $stdin, output: $stdout) ⇒ OnboardingWizard
constructor
A new instance of OnboardingWizard.
-
#run ⇒ Object
Drives the wizard.
Constructor Details
#initialize(ui: Rubino.ui, input: $stdin, output: $stdout) ⇒ OnboardingWizard
Returns a new instance of OnboardingWizard.
80 81 82 83 84 |
# File 'lib/rubino/cli/onboarding_wizard.rb', line 80 def initialize(ui: Rubino.ui, input: $stdin, output: $stdout) @ui = ui @input = input @output = output end |
Instance Method Details
#run ⇒ Object
Drives the wizard. Returns true when a provider was configured, false when the user skipped (empty/‘s`/`skip` at the provider prompt).
A Ctrl-C MID-wizard — after picking a provider, before pasting the key —used to escape as a raw ‘Interrupt` backtrace out of `gets`/`noecho` (H2). Catch it here and abort CLEANLY: print “Setup cancelled.” and exit 130 (the conventional SIGINT code). Nothing is half-written — #persist! (the only writer of the provider’s model.* / .env key) runs ONLY after a non-empty key is obtained, several lines below the interrupt point, so an abort leaves the config at the seeded defaults and re-running ‘setup` works. The base config.yml/.env `setup` materialized before onboarding are the intended seed files, not partial wizard state.
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/rubino/cli/onboarding_wizard.rb', line 98 def run @ui.blank_line @ui.info("Welcome to rubino — let's get you connected to a model.") @ui.status("No API key is configured yet. Pick a provider (or press Enter to skip).") @ui.blank_line choice = ask_provider return false unless choice # When the provider was just CONFIRMED via its already-present env key # (F3), that key is the one to use — don't re-ask "use the detected key?" # one line later. Otherwise prompt/paste as usual. api_key = ask_api_key(choice, skip_env_prompt: @confirmed_env_key) return false if api_key.nil? || api_key.empty? base_url = ask_base_url(choice) persist!(choice, api_key, base_url) Rubino.reload_configuration! @ui.blank_line @ui.success("Configured #{choice[:label]} with model #{choice[:model]}.") @ui.status("Saved to #{config_loader.config_path} and #{config_loader.env_path}.") @ui.blank_line true rescue Interrupt @output.puts @ui.warning("Setup cancelled.") exit(130) end |