mirror of
https://github.com/hanzoai/dev.git
synced 2026-10-25 03:23:33 +00:00
fix(core/config): prefer ~/.code writes while reading legacy state
This commit is contained in:
@@ -2,6 +2,7 @@ use std::future::Future;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use codex_core::config::resolve_codex_path_for_read;
|
||||
use codex_core::CODEX_APPLY_PATCH_ARG1;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::symlink;
|
||||
@@ -113,7 +114,8 @@ const ILLEGAL_ENV_VAR_PREFIX: &str = "CODEX_";
|
||||
fn load_dotenv() {
|
||||
// 1) Load from global ~/.code/.env (or ~/.codex/.env) first.
|
||||
if let Ok(codex_home) = codex_core::config::find_codex_home() {
|
||||
if let Ok(iter) = dotenvy::from_path_iter(codex_home.join(".env")) {
|
||||
let global_env_path = resolve_codex_path_for_read(&codex_home, Path::new(".env"));
|
||||
if let Ok(iter) = dotenvy::from_path_iter(global_env_path) {
|
||||
// Global env may legitimately contain provider keys for Code usage.
|
||||
set_filtered(iter);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ use codex_protocol::mcp_protocol::AuthMode;
|
||||
|
||||
use crate::token_data::TokenData;
|
||||
use crate::token_data::parse_id_token;
|
||||
use crate::config::resolve_codex_path_for_read;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CodexAuth {
|
||||
@@ -238,8 +239,9 @@ fn load_auth(
|
||||
// back to AuthMode::ApiKey using the OPENAI_API_KEY environment variable
|
||||
// (if it is set).
|
||||
let auth_file = get_auth_file(codex_home);
|
||||
let auth_read_path = resolve_codex_path_for_read(codex_home, Path::new("auth.json"));
|
||||
let client = crate::default_client::create_client(originator);
|
||||
let auth_dot_json = match try_read_auth_json(&auth_file) {
|
||||
let auth_dot_json = match try_read_auth_json(&auth_read_path) {
|
||||
Ok(auth) => auth,
|
||||
// If auth.json does not exist, try to read the OPENAI_API_KEY from the
|
||||
// environment variable.
|
||||
|
||||
+94
-39
@@ -31,9 +31,10 @@ use dirs::home_dir;
|
||||
use serde::Deserialize;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
use std::io::ErrorKind;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::io::ErrorKind;
|
||||
use std::sync::OnceLock;
|
||||
use tempfile::NamedTempFile;
|
||||
use toml::Value as TomlValue;
|
||||
use toml_edit::Array as TomlArray;
|
||||
@@ -284,8 +285,8 @@ pub fn load_config_as_toml_with_cli_overrides(
|
||||
/// Read `CODEX_HOME/config.toml` and return it as a generic TOML value. Returns
|
||||
/// an empty TOML table when the file does not exist.
|
||||
pub fn load_config_as_toml(codex_home: &Path) -> std::io::Result<TomlValue> {
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
match std::fs::read_to_string(&config_path) {
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
match std::fs::read_to_string(&read_path) {
|
||||
Ok(contents) => match toml::from_str::<TomlValue>(&contents) {
|
||||
Ok(val) => Ok(val),
|
||||
Err(e) => {
|
||||
@@ -323,7 +324,8 @@ pub fn write_global_mcp_servers(
|
||||
servers: &BTreeMap<String, McpServerConfig>,
|
||||
) -> std::io::Result<()> {
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
let mut doc = match std::fs::read_to_string(&config_path) {
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
let mut doc = match std::fs::read_to_string(&read_path) {
|
||||
Ok(contents) => contents
|
||||
.parse::<DocumentMut>()
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?,
|
||||
@@ -397,7 +399,8 @@ pub async fn persist_model_selection(
|
||||
use tokio::fs;
|
||||
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
let existing = match fs::read_to_string(&config_path).await {
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
let existing = match fs::read_to_string(&read_path).await {
|
||||
Ok(raw) => Some(raw),
|
||||
Err(err) if err.kind() == ErrorKind::NotFound => None,
|
||||
Err(err) => return Err(err.into()),
|
||||
@@ -473,7 +476,8 @@ pub async fn persist_model_selection(
|
||||
pub fn set_project_trusted(codex_home: &Path, project_path: &Path) -> anyhow::Result<()> {
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
// Parse existing config if present; otherwise start a new document.
|
||||
let mut doc = match std::fs::read_to_string(config_path.clone()) {
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
let mut doc = match std::fs::read_to_string(&read_path) {
|
||||
Ok(s) => s.parse::<DocumentMut>()?,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => DocumentMut::new(),
|
||||
Err(e) => return Err(e.into()),
|
||||
@@ -559,7 +563,8 @@ pub fn set_tui_theme_name(codex_home: &Path, theme: ThemeName) -> anyhow::Result
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
|
||||
// Parse existing config if present; otherwise start a new document.
|
||||
let mut doc = match std::fs::read_to_string(config_path.clone()) {
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
let mut doc = match std::fs::read_to_string(&read_path) {
|
||||
Ok(s) => s.parse::<DocumentMut>()?,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => DocumentMut::new(),
|
||||
Err(e) => return Err(e.into()),
|
||||
@@ -613,7 +618,8 @@ pub fn set_tui_spinner_name(codex_home: &Path, spinner_name: &str) -> anyhow::Re
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
|
||||
// Parse existing config if present; otherwise start a new document.
|
||||
let mut doc = match std::fs::read_to_string(config_path.clone()) {
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
let mut doc = match std::fs::read_to_string(&read_path) {
|
||||
Ok(s) => s.parse::<DocumentMut>()?,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => DocumentMut::new(),
|
||||
Err(e) => return Err(e.into()),
|
||||
@@ -645,7 +651,8 @@ pub fn set_custom_spinner(
|
||||
frames: &[String],
|
||||
) -> anyhow::Result<()> {
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
let mut doc = match std::fs::read_to_string(&config_path) {
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
let mut doc = match std::fs::read_to_string(&read_path) {
|
||||
Ok(s) => s.parse::<DocumentMut>()?,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => DocumentMut::new(),
|
||||
Err(e) => return Err(e.into()),
|
||||
@@ -678,7 +685,8 @@ pub fn set_custom_theme(
|
||||
is_dark: Option<bool>,
|
||||
) -> anyhow::Result<()> {
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
let mut doc = match std::fs::read_to_string(&config_path) {
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
let mut doc = match std::fs::read_to_string(&read_path) {
|
||||
Ok(s) => s.parse::<DocumentMut>()?,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => DocumentMut::new(),
|
||||
Err(e) => return Err(e.into()),
|
||||
@@ -742,7 +750,8 @@ pub fn set_tui_alternate_screen(codex_home: &Path, enabled: bool) -> anyhow::Res
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
|
||||
// Parse existing config if present; otherwise start a new document.
|
||||
let mut doc = match std::fs::read_to_string(config_path.clone()) {
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
let mut doc = match std::fs::read_to_string(&read_path) {
|
||||
Ok(s) => s.parse::<DocumentMut>()?,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => DocumentMut::new(),
|
||||
Err(e) => return Err(e.into()),
|
||||
@@ -769,7 +778,8 @@ pub fn set_github_check_on_push(codex_home: &Path, enabled: bool) -> anyhow::Res
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
|
||||
// Parse existing config if present; otherwise start a new document.
|
||||
let mut doc = match std::fs::read_to_string(config_path.clone()) {
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
let mut doc = match std::fs::read_to_string(&read_path) {
|
||||
Ok(s) => s.parse::<DocumentMut>()?,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => DocumentMut::new(),
|
||||
Err(e) => return Err(e.into()),
|
||||
@@ -802,7 +812,8 @@ pub fn set_project_access_mode(
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
|
||||
// Parse existing config if present; otherwise start a new document.
|
||||
let mut doc = match std::fs::read_to_string(config_path.clone()) {
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
let mut doc = match std::fs::read_to_string(&read_path) {
|
||||
Ok(s) => s.parse::<DocumentMut>()?,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => DocumentMut::new(),
|
||||
Err(e) => return Err(e.into()),
|
||||
@@ -864,8 +875,8 @@ pub fn list_mcp_servers(codex_home: &Path) -> anyhow::Result<(
|
||||
Vec<(String, McpServerConfig)>,
|
||||
Vec<(String, McpServerConfig)>,
|
||||
)> {
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
let doc_str = std::fs::read_to_string(&config_path).unwrap_or_default();
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
let doc_str = std::fs::read_to_string(&read_path).unwrap_or_default();
|
||||
let doc = doc_str.parse::<DocumentMut>().unwrap_or_else(|_| DocumentMut::new());
|
||||
|
||||
fn table_to_list(tbl: &toml_edit::Table) -> Vec<(String, McpServerConfig)> {
|
||||
@@ -937,7 +948,8 @@ pub fn add_mcp_server(
|
||||
}
|
||||
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
let mut doc = match std::fs::read_to_string(&config_path) {
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
let mut doc = match std::fs::read_to_string(&read_path) {
|
||||
Ok(s) => s.parse::<DocumentMut>()?,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => DocumentMut::new(),
|
||||
Err(e) => return Err(e.into()),
|
||||
@@ -994,7 +1006,8 @@ pub fn set_mcp_server_enabled(
|
||||
enabled: bool,
|
||||
) -> anyhow::Result<bool> {
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
let mut doc = match std::fs::read_to_string(&config_path) {
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
let mut doc = match std::fs::read_to_string(&read_path) {
|
||||
Ok(s) => s.parse::<DocumentMut>()?,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => DocumentMut::new(),
|
||||
Err(e) => return Err(e.into()),
|
||||
@@ -1731,26 +1744,76 @@ fn default_review_model() -> String {
|
||||
OPENAI_DEFAULT_REVIEW_MODEL.to_string()
|
||||
}
|
||||
|
||||
fn env_path(var: &str) -> std::io::Result<Option<PathBuf>> {
|
||||
match std::env::var(var) {
|
||||
Ok(val) if !val.trim().is_empty() => {
|
||||
let canonical = PathBuf::from(val).canonicalize()?;
|
||||
Ok(Some(canonical))
|
||||
}
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn env_overrides_present() -> bool {
|
||||
matches!(std::env::var("CODE_HOME"), Ok(ref v) if !v.trim().is_empty())
|
||||
|| matches!(std::env::var("CODEX_HOME"), Ok(ref v) if !v.trim().is_empty())
|
||||
}
|
||||
|
||||
fn legacy_codex_home_dir() -> Option<PathBuf> {
|
||||
static LEGACY: OnceLock<Option<PathBuf>> = OnceLock::new();
|
||||
LEGACY
|
||||
.get_or_init(|| {
|
||||
if env_overrides_present() {
|
||||
return None;
|
||||
}
|
||||
let Some(home) = home_dir() else {
|
||||
return None;
|
||||
};
|
||||
let candidate = home.join(".codex");
|
||||
if path_exists(&candidate) {
|
||||
Some(candidate)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.clone()
|
||||
}
|
||||
|
||||
fn path_exists(path: &Path) -> bool {
|
||||
std::fs::metadata(path).is_ok()
|
||||
}
|
||||
|
||||
/// Resolve the filesystem path used for *reading* Codex state that may live in
|
||||
/// a legacy `~/.codex` directory. Writes should continue targeting `codex_home`.
|
||||
pub fn resolve_codex_path_for_read(codex_home: &Path, relative: &Path) -> PathBuf {
|
||||
if env_overrides_present() {
|
||||
return codex_home.join(relative);
|
||||
}
|
||||
|
||||
if let Some(legacy) = legacy_codex_home_dir() {
|
||||
let candidate = legacy.join(relative);
|
||||
if path_exists(&candidate) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
codex_home.join(relative)
|
||||
}
|
||||
|
||||
/// Returns the path to the Code/Codex configuration directory, which can be
|
||||
/// specified by the `CODE_HOME` or `CODEX_HOME` environment variables. If not set,
|
||||
/// defaults to `~/.code` (falling back to `~/.codex` if it exists for compatibility).
|
||||
/// defaults to `~/.code` for the fork.
|
||||
///
|
||||
/// - If `CODE_HOME` or `CODEX_HOME` is set, the value will be canonicalized and this
|
||||
/// function will Err if the path does not exist.
|
||||
/// - If neither is set, this function does not verify that the directory exists.
|
||||
pub fn find_codex_home() -> std::io::Result<PathBuf> {
|
||||
// First check CODE_HOME for the fork
|
||||
if let Ok(val) = std::env::var("CODE_HOME") {
|
||||
if !val.is_empty() {
|
||||
return PathBuf::from(val).canonicalize();
|
||||
}
|
||||
if let Some(path) = env_path("CODE_HOME")? {
|
||||
return Ok(path);
|
||||
}
|
||||
|
||||
// Fall back to CODEX_HOME for compatibility
|
||||
if let Ok(val) = std::env::var("CODEX_HOME") {
|
||||
if !val.is_empty() {
|
||||
return PathBuf::from(val).canonicalize();
|
||||
}
|
||||
if let Some(path) = env_path("CODEX_HOME")? {
|
||||
return Ok(path);
|
||||
}
|
||||
|
||||
let home = home_dir().ok_or_else(|| {
|
||||
@@ -1760,17 +1823,9 @@ pub fn find_codex_home() -> std::io::Result<PathBuf> {
|
||||
)
|
||||
})?;
|
||||
|
||||
// Check if ~/.codex exists for backward compatibility
|
||||
let mut codex_path = home.clone();
|
||||
codex_path.push(".codex");
|
||||
if codex_path.exists() {
|
||||
return Ok(codex_path);
|
||||
}
|
||||
|
||||
// Otherwise use ~/.code for the fork
|
||||
let mut p = home;
|
||||
p.push(".code");
|
||||
Ok(p)
|
||||
let mut write_path = home;
|
||||
write_path.push(".code");
|
||||
Ok(write_path)
|
||||
}
|
||||
|
||||
/// Returns the path to the folder where Codex logs are stored. Does not verify
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::config::resolve_codex_path_for_read;
|
||||
use crate::config_types::SubagentCommandConfig;
|
||||
use anyhow::Result;
|
||||
use std::path::Path;
|
||||
@@ -99,7 +100,8 @@ fn apply_toml_edit_override_segments(
|
||||
pub async fn upsert_subagent_command(codex_home: &Path, cmd: &SubagentCommandConfig) -> Result<()> {
|
||||
const CONFIG_TOML_FILE: &str = "config.toml";
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
let mut doc = match tokio::fs::read_to_string(&config_path).await {
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
let mut doc = match tokio::fs::read_to_string(&read_path).await {
|
||||
Ok(s) => s.parse::<DocumentMut>()?,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
||||
tokio::fs::create_dir_all(codex_home).await?;
|
||||
@@ -166,7 +168,8 @@ pub async fn upsert_subagent_command(codex_home: &Path, cmd: &SubagentCommandCon
|
||||
pub async fn delete_subagent_command(codex_home: &Path, name: &str) -> Result<bool> {
|
||||
const CONFIG_TOML_FILE: &str = "config.toml";
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
let mut doc = match tokio::fs::read_to_string(&config_path).await {
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
let mut doc = match tokio::fs::read_to_string(&read_path).await {
|
||||
Ok(s) => s.parse::<DocumentMut>()?,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(false),
|
||||
Err(e) => return Err(e.into()),
|
||||
@@ -207,7 +210,8 @@ pub async fn upsert_agent_config(
|
||||
) -> Result<()> {
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
|
||||
let mut doc = match tokio::fs::read_to_string(&config_path).await {
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
let mut doc = match tokio::fs::read_to_string(&read_path).await {
|
||||
Ok(s) => s.parse::<DocumentMut>()?,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
||||
tokio::fs::create_dir_all(codex_home).await?;
|
||||
@@ -328,7 +332,8 @@ async fn persist_overrides_with_behavior(
|
||||
}
|
||||
|
||||
let config_path = codex_home.join(CONFIG_TOML_FILE);
|
||||
let read_result = tokio::fs::read_to_string(&config_path).await;
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(CONFIG_TOML_FILE));
|
||||
let read_result = tokio::fs::read_to_string(&read_path).await;
|
||||
let mut doc = match read_result {
|
||||
Ok(contents) => contents.parse::<DocumentMut>()?,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
||||
|
||||
@@ -5,6 +5,8 @@ use std::io::ErrorKind;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::config::resolve_codex_path_for_read;
|
||||
|
||||
pub(crate) const INTERNAL_STORAGE_FILE: &str = "internal_storage.json";
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
@@ -19,8 +21,9 @@ pub struct InternalStorage {
|
||||
impl InternalStorage {
|
||||
pub fn load(codex_home: &Path) -> Self {
|
||||
let storage_path = codex_home.join(INTERNAL_STORAGE_FILE);
|
||||
let read_path = resolve_codex_path_for_read(codex_home, Path::new(INTERNAL_STORAGE_FILE));
|
||||
|
||||
match std::fs::read_to_string(&storage_path) {
|
||||
match std::fs::read_to_string(&read_path) {
|
||||
Ok(serialized) => match serde_json::from_str::<Self>(&serialized) {
|
||||
Ok(mut storage) => {
|
||||
storage.storage_path = storage_path;
|
||||
|
||||
@@ -17,6 +17,7 @@ use uuid::Uuid;
|
||||
use super::SESSIONS_SUBDIR;
|
||||
use codex_protocol::protocol::RolloutItem;
|
||||
use codex_protocol::protocol::RolloutLine;
|
||||
use crate::config::resolve_codex_path_for_read;
|
||||
|
||||
/// Returned page of conversation summaries.
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
@@ -90,8 +91,7 @@ pub(crate) async fn get_conversations(
|
||||
page_size: usize,
|
||||
cursor: Option<&Cursor>,
|
||||
) -> io::Result<ConversationsPage> {
|
||||
let mut root = codex_home.to_path_buf();
|
||||
root.push(SESSIONS_SUBDIR);
|
||||
let root = resolve_codex_path_for_read(codex_home, Path::new(SESSIONS_SUBDIR));
|
||||
|
||||
if !root.exists() {
|
||||
return Ok(ConversationsPage {
|
||||
|
||||
@@ -111,6 +111,7 @@ use crate::user_approval_widget::ApprovalRequest;
|
||||
use codex_ansi_escape::ansi_escape_line;
|
||||
use codex_browser::BrowserManager;
|
||||
use codex_core::config::find_codex_home;
|
||||
use codex_core::config::resolve_codex_path_for_read;
|
||||
use codex_core::config::set_github_check_on_push;
|
||||
use codex_file_search::FileMatch;
|
||||
use codex_protocol::models::ContentItem;
|
||||
@@ -138,7 +139,7 @@ struct CachedConnection {
|
||||
|
||||
async fn read_cached_connection() -> Option<(Option<u16>, Option<String>)> {
|
||||
let codex_home = find_codex_home().ok()?;
|
||||
let path = codex_home.join("cache.json");
|
||||
let path = resolve_codex_path_for_read(&codex_home, std::path::Path::new("cache.json"));
|
||||
let bytes = tokio::fs::read(path).await.ok()?;
|
||||
let parsed: CachedConnection = serde_json::from_slice(&bytes).ok()?;
|
||||
Some((parsed.port, parsed.ws))
|
||||
|
||||
@@ -7,12 +7,14 @@ use serde::Serialize;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use codex_core::config::resolve_codex_path_for_read;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::default_client::create_client;
|
||||
|
||||
pub fn get_upgrade_version(config: &Config) -> Option<String> {
|
||||
let version_file = version_filepath(config);
|
||||
let info = read_version_info(&version_file).ok();
|
||||
let read_path = resolve_codex_path_for_read(&config.codex_home, Path::new(VERSION_FILENAME));
|
||||
let info = read_version_info(&read_path).ok();
|
||||
let originator = config.responses_originator_header.clone();
|
||||
|
||||
// Always refresh the cached latest version in the background so TUI startup
|
||||
|
||||
Reference in New Issue
Block a user