mirror of
https://github.com/openai/codex.git
synced 2026-10-22 17:58:46 +00:00
## Why Vite+ launches Codex through the same JavaScript shim as npm, so Codex could misidentify Vite+-owned installations and recommend npm for updates. ## What changed - Detect Vite+ global installs from their package ownership metadata and pass a dedicated `CODEX_MANAGED_BY_VITE_PLUS` marker to the native binary. - Represent Vite+ in install context and `codex doctor` output. - Recommend `vp install -g @openai/codex` in update and repair flows for Vite+-managed installs. See https://github.com/openai/codex/pull/30880. GitOrigin-RevId: 8add724eefd31170a078086392609dbbd7f20b26
158 lines
5.5 KiB
Rust
158 lines
5.5 KiB
Rust
//! Captures how this Codex process was launched.
|
|
//!
|
|
//! Runtime diagnostics answer provenance questions that are hard to infer from
|
|
//! user reports: which binary is running, which install channel it resembles,
|
|
//! which platform it targets, and whether the search command comes from bundled
|
|
//! package files or from PATH.
|
|
|
|
use std::env;
|
|
use std::process::Command;
|
|
|
|
use codex_install_context::InstallContext;
|
|
use codex_install_context::InstallMethod;
|
|
|
|
use super::CheckStatus;
|
|
use super::DoctorCheck;
|
|
use super::describe_install_context;
|
|
use super::doctor_install_context;
|
|
use super::push_path_detail;
|
|
|
|
/// Builds the process provenance row for the current Codex executable.
|
|
///
|
|
/// This check is informational and should not fail on its own; inconsistent
|
|
/// install state is reported by the installation and update checks instead.
|
|
pub(super) fn runtime_check() -> DoctorCheck {
|
|
let current_exe = env::current_exe().ok();
|
|
let install_context = doctor_install_context(current_exe.as_deref());
|
|
let os = env::consts::OS;
|
|
let arch = env::consts::ARCH;
|
|
let platform = format!("{os}-{arch}");
|
|
let install_method = install_method_name(&install_context);
|
|
let mut details = vec![
|
|
format!("version: {}", env!("CARGO_PKG_VERSION")),
|
|
format!("platform: {platform}"),
|
|
format!(
|
|
"install method: {}",
|
|
describe_install_context(&install_context)
|
|
),
|
|
format!("commit: {}", build_commit()),
|
|
];
|
|
push_path_detail(&mut details, "current executable", current_exe.as_deref());
|
|
|
|
DoctorCheck::new(
|
|
"runtime.provenance",
|
|
"runtime",
|
|
CheckStatus::Ok,
|
|
format!("running {install_method} on {platform}"),
|
|
)
|
|
.details(details)
|
|
}
|
|
|
|
/// Verifies that the search command selected by the install context is usable.
|
|
///
|
|
/// Package-layout installs should point at a bundled ripgrep binary, while local
|
|
/// installs without that layout usually resolve rg from PATH. A warning here
|
|
/// means features that depend on file search may degrade even when the CLI
|
|
/// launches.
|
|
pub(super) fn search_check() -> DoctorCheck {
|
|
let current_exe = env::current_exe().ok();
|
|
let install_context = doctor_install_context(current_exe.as_deref());
|
|
let rg_command = install_context.rg_command();
|
|
let provider = search_provider(&install_context);
|
|
let mut details = vec![
|
|
format!("search command: {}", rg_command.display()),
|
|
format!("search provider: {provider}"),
|
|
];
|
|
|
|
let status = if rg_command.components().count() > 1 {
|
|
match std::fs::metadata(&rg_command) {
|
|
Ok(metadata) if metadata.is_file() => {
|
|
details.push("search command readiness: file exists".to_string());
|
|
CheckStatus::Ok
|
|
}
|
|
Ok(_) => {
|
|
details.push("search command readiness: path is not a file".to_string());
|
|
CheckStatus::Warning
|
|
}
|
|
Err(err) => {
|
|
details.push(format!("search command readiness: {err}"));
|
|
CheckStatus::Warning
|
|
}
|
|
}
|
|
} else {
|
|
match Command::new(&rg_command).arg("--version").output() {
|
|
Ok(output) if output.status.success() => {
|
|
let version = String::from_utf8_lossy(&output.stdout)
|
|
.lines()
|
|
.next()
|
|
.unwrap_or("rg version unknown")
|
|
.to_string();
|
|
details.push(format!("search command readiness: {version}"));
|
|
CheckStatus::Ok
|
|
}
|
|
Ok(output) => {
|
|
details.push(format!(
|
|
"search command readiness: exited with status {}",
|
|
output.status
|
|
));
|
|
CheckStatus::Warning
|
|
}
|
|
Err(err) => {
|
|
details.push(format!("search command readiness: {err}"));
|
|
CheckStatus::Warning
|
|
}
|
|
}
|
|
};
|
|
|
|
let summary = match status {
|
|
CheckStatus::Ok => format!("search is OK ({provider})"),
|
|
CheckStatus::Warning => "search command could not be verified".to_string(),
|
|
CheckStatus::Fail => unreachable!(),
|
|
};
|
|
let mut check = DoctorCheck::new("runtime.search", "search", status, summary).details(details);
|
|
if status != CheckStatus::Ok {
|
|
check = check.remediation("Install ripgrep or repair the bundled Codex package.");
|
|
}
|
|
check
|
|
}
|
|
|
|
fn install_method_name(context: &InstallContext) -> &'static str {
|
|
match &context.method {
|
|
InstallMethod::Standalone { .. } => "standalone",
|
|
InstallMethod::Npm => "npm",
|
|
InstallMethod::Bun => "bun",
|
|
InstallMethod::VitePlus => "vite+",
|
|
InstallMethod::Pnpm => "pnpm",
|
|
InstallMethod::Brew => "brew",
|
|
InstallMethod::Other => "local build",
|
|
}
|
|
}
|
|
|
|
fn search_provider(context: &InstallContext) -> &'static str {
|
|
let rg_command = context.rg_command();
|
|
let from_package_layout = context
|
|
.package_layout
|
|
.as_ref()
|
|
.and_then(|package_layout| package_layout.path_dir.as_ref())
|
|
.is_some_and(|path_dir| rg_command.starts_with(path_dir));
|
|
let from_legacy_standalone = matches!(
|
|
&context.method,
|
|
InstallMethod::Standalone {
|
|
resources_dir: Some(resources_dir),
|
|
..
|
|
} if rg_command.starts_with(resources_dir)
|
|
);
|
|
|
|
if from_package_layout || from_legacy_standalone {
|
|
"bundled"
|
|
} else {
|
|
"system"
|
|
}
|
|
}
|
|
|
|
fn build_commit() -> &'static str {
|
|
option_env!("CODEX_BUILD_COMMIT")
|
|
.or(option_env!("GIT_COMMIT"))
|
|
.unwrap_or("unknown")
|
|
}
|