Skip to content

Commit 3845040

Browse files
Your Nameclaude
andcommitted
feat: wizard entry points -- /setup command, claw setup subcommand, and RuntimeProviderConfig
The setup wizard was merged in PR ultraworkers#3017 but was orphaned -- it was not declared as a module in main.rs, making it unreachable. Additionally, the setup_wizard.rs imports RuntimeProviderConfig which did not exist on upstream/main. This commit makes the wizard accessible and adds the necessary RuntimeProviderConfig type. Changes: - Add RuntimeProviderConfig struct to runtime/src/config.rs with kind(), api_key(), base_url(), model() accessors. - Add parse_optional_provider_config() to parse the provider object from merged settings JSON. - Add provider() method to RuntimeConfig and RuntimeFeatureConfig. - Export RuntimeProviderConfig, save_user_provider_settings, clear_user_provider_settings, and default_config_home from runtime crate public API (runtime/src/lib.rs). - Add mod setup_wizard to rusty-claude-cli/src/main.rs. - Add claw setup CLI subcommand. - Add /setup slash command. - Add Setup variant to SlashCommand enum. - Add Setup to LocalHelpTopic enum. - Add setup to diagnostic subcommand matching. - Add subagentModel to TOP_LEVEL_FIELDS in config_validate.rs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 503d515 commit 3845040

6 files changed

Lines changed: 192 additions & 188 deletions

File tree

rust/crates/commands/src/lib.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,13 @@ const SLASH_COMMAND_SPECS: &[SlashCommandSpec] = &[
720720
argument_hint: None,
721721
resume_supported: true,
722722
},
723+
SlashCommandSpec {
724+
name: "setup",
725+
aliases: &[],
726+
summary: "Run the interactive provider setup wizard",
727+
argument_hint: None,
728+
resume_supported: false,
729+
},
723730
SlashCommandSpec {
724731
name: "notifications",
725732
aliases: &[],
@@ -1102,6 +1109,7 @@ pub enum SlashCommand {
11021109
args: Option<String>,
11031110
},
11041111
Doctor,
1112+
Setup,
11051113
Login,
11061114
Logout,
11071115
Vim,
@@ -1223,6 +1231,7 @@ impl SlashCommand {
12231231
Self::Compact { .. } => "/compact",
12241232
Self::Cost => "/cost",
12251233
Self::Doctor => "/doctor",
1234+
Self::Setup => "/setup",
12261235
Self::Config { .. } => "/config",
12271236
Self::Memory { .. } => "/memory",
12281237
Self::History { .. } => "/history",
@@ -1392,6 +1401,10 @@ pub fn validate_slash_command_input(
13921401
validate_no_args(command, &args)?;
13931402
SlashCommand::Doctor
13941403
}
1404+
"setup" => {
1405+
validate_no_args(command, &args)?;
1406+
SlashCommand::Setup
1407+
}
13951408
"login" | "logout" => {
13961409
return Err(command_error(
13971410
"This auth flow was removed. Set ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN instead.",
@@ -1914,7 +1927,7 @@ fn slash_command_category(name: &str) -> &'static str {
19141927
| "stickers" | "language" | "profile" | "max-tokens" | "temperature" | "system-prompt"
19151928
| "api-key" | "terminal-setup" | "notifications" | "telemetry" | "providers" | "env"
19161929
| "project" | "reasoning" | "budget" | "rate-limit" | "workspace" | "reset" | "ide"
1917-
| "desktop" | "upgrade" => "Config",
1930+
| "desktop" | "upgrade" | "setup" => "Config",
19181931
"debug-tool-call" | "doctor" | "sandbox" | "diagnostics" | "tool-details" | "changelog"
19191932
| "metrics" => "Debug",
19201933
_ => "Tools",
@@ -5381,6 +5394,7 @@ pub fn handle_slash_command(
53815394
| SlashCommand::AddDir { .. }
53825395
| SlashCommand::History { .. }
53835396
| SlashCommand::Team { .. }
5397+
| SlashCommand::Setup
53845398
| SlashCommand::Unknown(_) => None,
53855399
}
53865400
}

rust/crates/runtime/src/config.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,46 @@ pub struct RuntimeFeatureConfig {
162162
trusted_roots: Vec<String>,
163163
api_timeout: ApiTimeoutConfig,
164164
rules_import: RulesImportConfig,
165+
provider: RuntimeProviderConfig,
165166
}
166167

167168
/// Controls which external AI coding framework rules are imported into the system prompt.
168169
#[derive(Debug, Clone, PartialEq, Eq, Default)]
170+
/// Stored provider configuration from the setup wizard.
171+
///
172+
/// Represents the `provider` section in `~/.claw/settings.json`, used as a
173+
/// fallback when environment variables are absent (3-tier resolution:
174+
/// env var > .env file > stored config).
175+
#[derive(Debug, Clone, PartialEq, Eq, Default)]
176+
pub struct RuntimeProviderConfig {
177+
kind: Option<String>,
178+
api_key: Option<String>,
179+
base_url: Option<String>,
180+
model: Option<String>,
181+
}
182+
183+
impl RuntimeProviderConfig {
184+
#[must_use]
185+
pub fn kind(&self) -> Option<&str> {
186+
self.kind.as_deref()
187+
}
188+
189+
#[must_use]
190+
pub fn api_key(&self) -> Option<&str> {
191+
self.api_key.as_deref()
192+
}
193+
194+
#[must_use]
195+
pub fn base_url(&self) -> Option<&str> {
196+
self.base_url.as_deref()
197+
}
198+
199+
#[must_use]
200+
pub fn model(&self) -> Option<&str> {
201+
self.model.as_deref()
202+
}
203+
}
204+
169205
pub enum RulesImportConfig {
170206
/// Import from all supported frameworks when files are detected.
171207
#[default]
@@ -764,6 +800,7 @@ fn build_runtime_config(
764800
trusted_roots: parse_optional_trusted_roots(&merged_value)?,
765801
api_timeout: parse_optional_api_timeout_config(&merged_value)?,
766802
rules_import: parse_optional_rules_import(&merged_value)?,
803+
provider: parse_optional_provider_config(&merged_value)?,
767804
};
768805

769806
Ok(RuntimeConfig {
@@ -891,6 +928,13 @@ impl RuntimeConfig {
891928
}
892929

893930
impl RuntimeFeatureConfig {
931+
/// Parsed provider configuration (kind, apiKey, baseUrl, model) from
932+
/// merged settings.
933+
#[must_use]
934+
pub fn provider(&self) -> &RuntimeProviderConfig {
935+
&self.provider
936+
}
937+
894938
#[must_use]
895939
pub fn with_hooks(mut self, hooks: RuntimeHookConfig) -> Self {
896940
self.hooks = hooks;
@@ -2104,6 +2148,25 @@ fn parse_optional_rules_import(root: &JsonValue) -> Result<RulesImportConfig, Co
21042148
}
21052149
}
21062150

2151+
fn parse_optional_provider_config(root: &JsonValue) -> Result<RuntimeProviderConfig, ConfigError> {
2152+
let Some(provider_value) = root.as_object().and_then(|object| object.get("provider")) else {
2153+
return Ok(RuntimeProviderConfig::default());
2154+
};
2155+
let Some(object) = provider_value.as_object() else {
2156+
return Ok(RuntimeProviderConfig::default());
2157+
};
2158+
let kind = optional_string(object, "kind", "provider")?.map(str::to_string);
2159+
let api_key = optional_string(object, "apiKey", "provider")?.map(str::to_string);
2160+
let base_url = optional_string(object, "baseUrl", "provider")?.map(str::to_string);
2161+
let model = optional_string(object, "model", "provider")?.map(str::to_string);
2162+
Ok(RuntimeProviderConfig {
2163+
kind,
2164+
api_key,
2165+
base_url,
2166+
model,
2167+
})
2168+
}
2169+
21072170
fn parse_filesystem_mode_label(value: &str) -> Result<FilesystemIsolationMode, ConfigError> {
21082171
match value {
21092172
"off" => Ok(FilesystemIsolationMode::Off),

0 commit comments

Comments
 (0)