Files
codecraft/cli/src/conf.rs
T
Richard ZinkandClaude Opus 5.5 6dffcb501a Add terminal client, memory, model fallback, version and install improvements
- codecraft: full-screen terminal client (ratatui) – local tools and files,
  models via the CodeCraft server gateway or own providers (standalone with a
  guided setup), slash commands, @files, permission dialogs, resume, update
- Static Linux CLI builds (x86_64/aarch64, cargo-zigbuild) served by the
  server: /cli/install.sh and /cli/download/<target>
- Project memory (remember tool, .codecraft/memory.md) and personal memory
- Model fallback when a host is unreachable or a budget is used up
- Version/commit in UI and health, daily release check, "What's new" dialog
- PWA: install button, maskable icon, manifest id and screenshots
- Case-insensitive detection of connection errors for retries

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 00:13:06 +01:00

103 lines
3.6 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Local configuration (~/.config/codecraft/config.toml, readable only by the user).
use anyhow::{Context, Result};
use codecraft_core::config::ProviderConfig;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerLogin {
pub url: String,
pub token: String,
#[serde(default)]
pub username: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Config {
/// Signed-in CodeCraft server (models, modes and rules come from there).
#[serde(default, skip_serializing_if = "Option::is_none")]
pub server: Option<ServerLogin>,
/// Model used for new sessions ("provider/model", server models as "server:provider/model").
#[serde(default, skip_serializing_if = "Option::is_none")]
pub default_model: Option<String>,
/// Permission mode for new sessions (default: auto).
#[serde(default, skip_serializing_if = "Option::is_none")]
pub permission_mode: Option<String>,
/// UI language (en, de); default from the server or $LANG.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub lang: Option<String>,
/// Theme override, e.g. "nord" and "dark" (default: your server theme).
#[serde(default, skip_serializing_if = "Option::is_none")]
pub theme: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub theme_mode: Option<String>,
/// Own model providers (standalone mode), same format as the server config.
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub providers: BTreeMap<String, ProviderConfig>,
}
pub fn config_dir() -> PathBuf {
if let Some(x) = std::env::var_os("CODECRAFT_CONFIG_DIR") {
return PathBuf::from(x);
}
#[cfg(windows)]
if let Some(x) = std::env::var_os("APPDATA") {
return PathBuf::from(x).join("codecraft");
}
let base = std::env::var_os("XDG_CONFIG_HOME").map(PathBuf::from).unwrap_or_else(|| home().join(".config"));
base.join("codecraft")
}
pub fn data_dir() -> PathBuf {
if let Some(x) = std::env::var_os("CODECRAFT_DATA_DIR") {
return PathBuf::from(x);
}
#[cfg(windows)]
if let Some(x) = std::env::var_os("LOCALAPPDATA") {
return PathBuf::from(x).join("codecraft");
}
let base = std::env::var_os("XDG_DATA_HOME").map(PathBuf::from).unwrap_or_else(|| home().join(".local").join("share"));
base.join("codecraft")
}
pub fn home() -> PathBuf {
std::env::var_os("HOME").or_else(|| std::env::var_os("USERPROFILE")).map(PathBuf::from).unwrap_or_else(|| PathBuf::from("."))
}
fn path() -> PathBuf {
config_dir().join("config.toml")
}
impl Config {
pub fn load() -> Result<Self> {
let p = path();
match std::fs::read_to_string(&p) {
Ok(text) => toml::from_str(&text).with_context(|| format!("invalid {}", p.display())),
Err(_) => Ok(Self::default()),
}
}
pub fn save(&self) -> Result<()> {
let p = path();
std::fs::create_dir_all(p.parent().unwrap())?;
let text = format!(
"# CodeCraft terminal client – edit with `codecraft setup` or by hand.\n# API keys may be written as \"${{ENV_VAR}}\".\n\n{}",
toml::to_string_pretty(self)?
);
std::fs::write(&p, text)?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(&p, std::fs::Permissions::from_mode(0o600))?;
}
Ok(())
}
/// Nothing set up yet: the setup wizard runs first.
pub fn is_empty(&self) -> bool {
self.server.is_none() && self.providers.is_empty()
}
}