Previously, the Rust TUI was writing log files to `/tmp`, which is world-readable and not available on Windows, so that isn't great. This PR tries to clean things up by adding a function that provides the path to the "Codex config dir," e.g., `~/.codex` (though I suppose we could support `$CODEX_HOME` to override this?) and then defines other paths in terms of the result of `codex_dir()`. For example, `log_dir()` returns the folder where log files should be written which is defined in terms of `codex_dir()`. I updated the TUI to use this function. On UNIX, we even go so far as to `chmod 600` the log file by default, though as noted in a comment, it's a bit tedious to do the equivalent on Windows, so we just let that go for now. This also changes the default logging level to `info` for `codex_core` and `codex_tui` when `RUST_LOG` is not specified. I'm not really sure if we should use a more verbose default (it may be helpful when debugging user issues), though if so, we should probably also set up log rotation?
66 lines
2.0 KiB
Rust
66 lines
2.0 KiB
Rust
use std::path::PathBuf;
|
||
|
||
use dirs::home_dir;
|
||
use serde::Deserialize;
|
||
|
||
/// Embedded fallback instructions that mirror the TypeScript CLI’s default system prompt. These
|
||
/// are compiled into the binary so a clean install behaves correctly even if the user has not
|
||
/// created `~/.codex/instructions.md`.
|
||
const EMBEDDED_INSTRUCTIONS: &str = include_str!("../prompt.md");
|
||
|
||
#[derive(Default, Deserialize, Debug, Clone)]
|
||
pub struct Config {
|
||
pub model: Option<String>,
|
||
pub instructions: Option<String>,
|
||
}
|
||
|
||
impl Config {
|
||
/// Load ~/.codex/config.toml and ~/.codex/instructions.md (if present).
|
||
/// Returns `None` if neither file exists.
|
||
pub fn load() -> Option<Self> {
|
||
let mut cfg: Config = Self::load_from_toml().unwrap_or_default();
|
||
|
||
// Highest precedence → user‑provided ~/.codex/instructions.md (if present)
|
||
// Fallback → embedded default instructions baked into the binary
|
||
|
||
cfg.instructions =
|
||
Self::load_instructions().or_else(|| Some(EMBEDDED_INSTRUCTIONS.to_string()));
|
||
|
||
Some(cfg)
|
||
}
|
||
|
||
fn load_from_toml() -> Option<Self> {
|
||
let mut p = codex_dir().ok()?;
|
||
p.push("config.toml");
|
||
let contents = std::fs::read_to_string(&p).ok()?;
|
||
toml::from_str(&contents).ok()
|
||
}
|
||
|
||
fn load_instructions() -> Option<String> {
|
||
let mut p = codex_dir().ok()?;
|
||
p.push("instructions.md");
|
||
std::fs::read_to_string(&p).ok()
|
||
}
|
||
}
|
||
|
||
/// Returns the path to the Codex configuration directory, which is `~/.codex`.
|
||
/// Does not verify that the directory exists.
|
||
pub fn codex_dir() -> std::io::Result<PathBuf> {
|
||
let mut p = home_dir().ok_or_else(|| {
|
||
std::io::Error::new(
|
||
std::io::ErrorKind::NotFound,
|
||
"Could not find home directory",
|
||
)
|
||
})?;
|
||
p.push(".codex");
|
||
Ok(p)
|
||
}
|
||
|
||
/// Returns the path to the folder where Codex logs are stored. Does not verify
|
||
/// that the directory exists.
|
||
pub fn log_dir() -> std::io::Result<PathBuf> {
|
||
let mut p = codex_dir()?;
|
||
p.push("log");
|
||
Ok(p)
|
||
}
|