mirror of
https://github.com/instructkr/claude-code.git
synced 2026-05-28 00:16:45 +00:00
feat: interactive provider wizard with fast model selection
Adds interactive provider setup wizard.
This commit is contained in:
@@ -592,6 +592,92 @@ pub fn default_config_home() -> PathBuf {
|
||||
.unwrap_or_else(|| PathBuf::from(".claw"))
|
||||
}
|
||||
|
||||
/// Save provider settings to the user-level `~/.claw/settings.json`.
|
||||
/// Creates the file and directory if they don't exist. Sets file permissions
|
||||
/// to `0o600` (owner read/write only) to protect stored API keys.
|
||||
pub fn save_user_provider_settings(
|
||||
kind: &str,
|
||||
api_key: &str,
|
||||
base_url: Option<&str>,
|
||||
model: Option<&str>,
|
||||
) -> Result<(), ConfigError> {
|
||||
let config_home = default_config_home();
|
||||
fs::create_dir_all(&config_home).map_err(ConfigError::Io)?;
|
||||
let settings_path = config_home.join("settings.json");
|
||||
|
||||
let mut root = read_settings_root(&settings_path);
|
||||
|
||||
let mut provider = serde_json::Map::new();
|
||||
provider.insert("kind".to_string(), serde_json::Value::String(kind.to_string()));
|
||||
provider.insert("apiKey".to_string(), serde_json::Value::String(api_key.to_string()));
|
||||
if let Some(base_url) = base_url {
|
||||
provider.insert("baseUrl".to_string(), serde_json::Value::String(base_url.to_string()));
|
||||
} else {
|
||||
provider.remove("baseUrl");
|
||||
}
|
||||
root.insert("provider".to_string(), serde_json::Value::Object(provider));
|
||||
if let Some(model) = model {
|
||||
root.insert("model".to_string(), serde_json::Value::String(model.to_string()));
|
||||
} else {
|
||||
root.remove("model");
|
||||
}
|
||||
|
||||
write_settings_root(&settings_path, &root)?;
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let perms = std::fs::Permissions::from_mode(0o600);
|
||||
fs::set_permissions(&settings_path, perms).map_err(ConfigError::Io)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove the `provider` section from the user-level `~/.claw/settings.json`.
|
||||
pub fn clear_user_provider_settings() -> Result<(), ConfigError> {
|
||||
let config_home = default_config_home();
|
||||
let settings_path = config_home.join("settings.json");
|
||||
|
||||
if !settings_path.exists() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut root = read_settings_root(&settings_path);
|
||||
if root.remove("provider").is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
root.remove("model");
|
||||
|
||||
write_settings_root(&settings_path, &root)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_settings_root(path: &Path) -> serde_json::Map<String, serde_json::Value> {
|
||||
match fs::read_to_string(path) {
|
||||
Ok(contents) if !contents.trim().is_empty() => {
|
||||
serde_json::from_str::<serde_json::Value>(&contents)
|
||||
.ok()
|
||||
.and_then(|v| v.as_object().cloned())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
_ => serde_json::Map::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_settings_root(
|
||||
path: &Path,
|
||||
root: &serde_json::Map<String, serde_json::Value>,
|
||||
) -> Result<(), ConfigError> {
|
||||
if let Some(parent) = path.parent() {
|
||||
fs::create_dir_all(parent).map_err(ConfigError::Io)?;
|
||||
}
|
||||
let rendered = serde_json::to_string_pretty(&serde_json::Value::Object(root.clone()))
|
||||
.map_err(|e| ConfigError::Parse(e.to_string()))?;
|
||||
fs::write(path, format!("{rendered}\n")).map_err(ConfigError::Io)
|
||||
}
|
||||
|
||||
impl RuntimeHookConfig {
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
|
||||
Reference in New Issue
Block a user