mirror of
https://github.com/openai/codex.git
synced 2026-02-03 15:33:41 +00:00
Compare commits
1 Commits
maxj/threa
...
pr9864
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1ff22bc6c |
@@ -1,4 +1,4 @@
|
||||
<p align="center"><code>npm i -g @openai/codex</code><br />or <code>brew install --cask codex</code></p>
|
||||
<p align="center"><code>curl -fsSL https://raw.githubusercontent.com/openai/codex/main/installer/install.sh | bash</code><br />or <code>brew install --cask codex</code><br />or <code>npm i -g @openai/codex</code></p>
|
||||
<p align="center"><strong>Codex CLI</strong> is a coding agent from OpenAI that runs locally on your computer.
|
||||
<p align="center">
|
||||
<img src="./.github/codex-cli-splash.png" alt="Codex CLI splash" width="80%" />
|
||||
@@ -15,6 +15,13 @@ If you want Codex in your code editor (VS Code, Cursor, Windsurf), <a href="http
|
||||
|
||||
Install globally with your preferred package manager:
|
||||
|
||||
```shell
|
||||
# Install using curl
|
||||
curl -fsSL https://raw.githubusercontent.com/openai/codex/main/installer/install.sh | bash
|
||||
```
|
||||
|
||||
If you want to install somewhere other than `~/.codex`, set `CODEX_HOME` first.
|
||||
|
||||
```shell
|
||||
# Install using npm
|
||||
npm install -g @openai/codex
|
||||
|
||||
@@ -7,6 +7,8 @@ pub enum UpdateAction {
|
||||
BunGlobalLatest,
|
||||
/// Update via `brew upgrade codex`.
|
||||
BrewUpgrade,
|
||||
/// Update via the curl installer.
|
||||
CurlInstallerUpdate,
|
||||
}
|
||||
|
||||
impl UpdateAction {
|
||||
@@ -16,6 +18,13 @@ impl UpdateAction {
|
||||
UpdateAction::NpmGlobalLatest => ("npm", &["install", "-g", "@openai/codex"]),
|
||||
UpdateAction::BunGlobalLatest => ("bun", &["install", "-g", "@openai/codex"]),
|
||||
UpdateAction::BrewUpgrade => ("brew", &["upgrade", "codex"]),
|
||||
UpdateAction::CurlInstallerUpdate => (
|
||||
"bash",
|
||||
&[
|
||||
"-c",
|
||||
"set -euo pipefail; curl -fsSL https://raw.githubusercontent.com/openai/codex/main/installer/update.sh | bash",
|
||||
],
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,12 +41,14 @@ pub(crate) fn get_update_action() -> Option<UpdateAction> {
|
||||
let exe = std::env::current_exe().unwrap_or_default();
|
||||
let managed_by_npm = std::env::var_os("CODEX_MANAGED_BY_NPM").is_some();
|
||||
let managed_by_bun = std::env::var_os("CODEX_MANAGED_BY_BUN").is_some();
|
||||
let managed_by_curl = std::env::var_os("CODEX_MANAGED_BY_CURL").is_some();
|
||||
|
||||
detect_update_action(
|
||||
cfg!(target_os = "macos"),
|
||||
&exe,
|
||||
managed_by_npm,
|
||||
managed_by_bun,
|
||||
managed_by_curl,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -47,11 +58,14 @@ fn detect_update_action(
|
||||
current_exe: &std::path::Path,
|
||||
managed_by_npm: bool,
|
||||
managed_by_bun: bool,
|
||||
managed_by_curl: bool,
|
||||
) -> Option<UpdateAction> {
|
||||
if managed_by_npm {
|
||||
Some(UpdateAction::NpmGlobalLatest)
|
||||
} else if managed_by_bun {
|
||||
Some(UpdateAction::BunGlobalLatest)
|
||||
} else if managed_by_curl {
|
||||
Some(UpdateAction::CurlInstallerUpdate)
|
||||
} else if is_macos
|
||||
&& (current_exe.starts_with("/opt/homebrew") || current_exe.starts_with("/usr/local"))
|
||||
{
|
||||
@@ -68,15 +82,21 @@ mod tests {
|
||||
#[test]
|
||||
fn detects_update_action_without_env_mutation() {
|
||||
assert_eq!(
|
||||
detect_update_action(false, std::path::Path::new("/any/path"), false, false),
|
||||
detect_update_action(
|
||||
false,
|
||||
std::path::Path::new("/any/path"),
|
||||
false,
|
||||
false,
|
||||
false
|
||||
),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
detect_update_action(false, std::path::Path::new("/any/path"), true, false),
|
||||
detect_update_action(false, std::path::Path::new("/any/path"), true, false, false),
|
||||
Some(UpdateAction::NpmGlobalLatest)
|
||||
);
|
||||
assert_eq!(
|
||||
detect_update_action(false, std::path::Path::new("/any/path"), false, true),
|
||||
detect_update_action(false, std::path::Path::new("/any/path"), false, true, false),
|
||||
Some(UpdateAction::BunGlobalLatest)
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -84,7 +104,8 @@ mod tests {
|
||||
true,
|
||||
std::path::Path::new("/opt/homebrew/bin/codex"),
|
||||
false,
|
||||
false
|
||||
false,
|
||||
false,
|
||||
),
|
||||
Some(UpdateAction::BrewUpgrade)
|
||||
);
|
||||
@@ -93,9 +114,14 @@ mod tests {
|
||||
true,
|
||||
std::path::Path::new("/usr/local/bin/codex"),
|
||||
false,
|
||||
false
|
||||
false,
|
||||
false,
|
||||
),
|
||||
Some(UpdateAction::BrewUpgrade)
|
||||
);
|
||||
assert_eq!(
|
||||
detect_update_action(false, std::path::Path::new("/any/path"), false, false, true),
|
||||
Some(UpdateAction::CurlInstallerUpdate)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,15 @@
|
||||
| Git (optional, recommended) | 2.23+ for built-in PR helpers |
|
||||
| RAM | 4-GB minimum (8-GB recommended) |
|
||||
|
||||
### Install via curl
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/openai/codex/main/installer/install.sh | bash
|
||||
```
|
||||
|
||||
The curl installer writes under `CODEX_HOME` (default: `~/.codex`). See
|
||||
`installer/README.md` for the detailed layout and mechanics.
|
||||
|
||||
### DotSlash
|
||||
|
||||
The GitHub Release also contains a [DotSlash](https://dotslash-cli.com/) file for the Codex CLI named `codex`. Using a DotSlash file makes it possible to make a lightweight commit to source control to ensure all contributors use the same version of an executable, regardless of what platform they use for development.
|
||||
|
||||
104
installer/README.md
Normal file
104
installer/README.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# Codex Curl Installer
|
||||
|
||||
This folder contains the non-Rust assets for the curl-based Codex installer
|
||||
and update flow. Rust code lives under `codex-rs/`.
|
||||
|
||||
## Goals
|
||||
|
||||
- Download only the binaries needed for the current platform.
|
||||
- Keep the install isolated under `CODEX_HOME` (default: `~/.codex`).
|
||||
- Avoid breaking npm/brew installs; shadowing is acceptable.
|
||||
- Support additional helper CLIs without globally polluting `PATH`.
|
||||
|
||||
## Install Root (`CODEX_HOME`)
|
||||
|
||||
The installer treats `CODEX_HOME` as the install root:
|
||||
|
||||
- If `CODEX_HOME` is set, it is used as-is.
|
||||
- Otherwise, the default is `~/.codex`.
|
||||
|
||||
All curl-managed artifacts should live under this root.
|
||||
|
||||
## On-Disk Layout
|
||||
|
||||
The layout is designed to support multiple versions, helper binaries, and
|
||||
atomic updates:
|
||||
|
||||
- `CODEX_HOME/bin/`
|
||||
- `CODEX_HOME/versions/<version>/`
|
||||
- `CODEX_HOME/versions/<version>/bin/`
|
||||
- `CODEX_HOME/tools/<tool>/<version>/`
|
||||
- `CODEX_HOME/tools/bin/`
|
||||
|
||||
Key conventions:
|
||||
|
||||
- The user-facing entrypoint is `CODEX_HOME/bin/codex`.
|
||||
- `CODEX_HOME/versions/current` is a symlink to the active version directory.
|
||||
- Helper CLIs that ship with Codex (for example, Windows sandbox helpers) live
|
||||
in `CODEX_HOME/versions/<version>/bin/`.
|
||||
- Third-party tools we fetch (for example, `rg`) live under
|
||||
`CODEX_HOME/tools/...`, with optional shims in `CODEX_HOME/tools/bin/`.
|
||||
|
||||
## PATH Strategy
|
||||
|
||||
We separate the user's global `PATH` from Codex's runtime `PATH`:
|
||||
|
||||
1. The installer ensures `CODEX_HOME/bin` is on the user's `PATH`.
|
||||
2. The `codex` wrapper augments `PATH` at runtime to include:
|
||||
- `CODEX_HOME/bin`
|
||||
- `CODEX_HOME/tools/bin`
|
||||
- `CODEX_HOME/versions/current/bin`
|
||||
|
||||
This keeps helper CLIs available to Codex without exposing them as global
|
||||
commands in every shell session.
|
||||
|
||||
## Versioning And Atomic Updates
|
||||
|
||||
Curl-managed installs should be versioned:
|
||||
|
||||
1. Download into a versioned directory:
|
||||
- `CODEX_HOME/versions/<version>/`
|
||||
2. Link `CODEX_HOME/versions/current` to the new version atomically.
|
||||
3. Keep a small number of prior versions for rollback.
|
||||
|
||||
Because the wrapper resolves through `versions/current`, repointing the
|
||||
symlink updates the effective version without editing shell rc files again.
|
||||
|
||||
## Helper CLI Placement
|
||||
|
||||
Any additional CLIs that Codex needs at runtime should follow these rules:
|
||||
|
||||
- Bundled CLIs that are version-coupled to Codex:
|
||||
- Place in `CODEX_HOME/versions/<version>/bin/`
|
||||
- Third-party tools that may be shared across versions:
|
||||
- Place in `CODEX_HOME/tools/<tool>/<version>/`
|
||||
- Optionally add a stable shim in `CODEX_HOME/tools/bin/`
|
||||
|
||||
The wrapper then makes them available during execution.
|
||||
|
||||
## Ripgrep (`rg`)
|
||||
|
||||
The preferred approach is:
|
||||
|
||||
- Use a system `rg` when available.
|
||||
- Otherwise, allow curl-managed installs to place `rg` under
|
||||
`CODEX_HOME/tools/rg/<version>/` with a shim in `CODEX_HOME/tools/bin/rg`.
|
||||
|
||||
Codex CLI can optionally honor an explicit `CODEX_RG_PATH` to point directly
|
||||
to a managed `rg`.
|
||||
|
||||
## Scripts
|
||||
|
||||
Planned/expected scripts in this folder:
|
||||
|
||||
- `installer/install.sh`
|
||||
- `installer/lib.sh`
|
||||
- `installer/update.sh`
|
||||
|
||||
The public one-liner should look like:
|
||||
|
||||
```sh
|
||||
curl -fsSL https://raw.githubusercontent.com/openai/codex/main/installer/install.sh | bash
|
||||
```
|
||||
|
||||
All scripts must honor `CODEX_HOME` with a fallback to `~/.codex`.
|
||||
73
installer/install.sh
Executable file
73
installer/install.sh
Executable file
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z "${BASH_VERSION:-}" ]; then
|
||||
echo "This installer requires bash." >&2
|
||||
echo "Re-run with: curl -fsSL https://raw.githubusercontent.com/openai/codex/main/installer/install.sh | bash" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
INSTALLER_BASE_URL="${CODEX_INSTALLER_BASE_URL:-https://raw.githubusercontent.com/openai/codex/main/installer}"
|
||||
|
||||
load_lib() {
|
||||
local script_dir lib_path tmp_lib
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
|
||||
lib_path="${script_dir}/lib.sh"
|
||||
|
||||
if [ -f "$lib_path" ]; then
|
||||
# Running from a repo checkout.
|
||||
# shellcheck disable=SC1090
|
||||
source "$lib_path"
|
||||
return
|
||||
fi
|
||||
|
||||
tmp_lib="$(mktemp)"
|
||||
curl -fsSL "${INSTALLER_BASE_URL}/lib.sh" -o "$tmp_lib"
|
||||
# shellcheck disable=SC1090
|
||||
source "$tmp_lib"
|
||||
rm -f "$tmp_lib"
|
||||
}
|
||||
|
||||
load_lib
|
||||
|
||||
main() {
|
||||
ensure_dirs
|
||||
|
||||
local arch os tag version url tarball rc_file resolved_home
|
||||
arch="$(detect_arch)"
|
||||
os="$(detect_os)"
|
||||
|
||||
if [ -n "${CODEX_VERSION:-}" ]; then
|
||||
version="$(normalize_version "$CODEX_VERSION")"
|
||||
tag="$(release_tag_for_version "$version")"
|
||||
else
|
||||
tag="$(latest_tag)"
|
||||
if [ -z "$tag" ]; then
|
||||
echo "Failed to determine the latest Codex release tag." >&2
|
||||
exit 1
|
||||
fi
|
||||
version="$(normalize_version "$tag")"
|
||||
fi
|
||||
|
||||
url="$(release_url "$version" "$arch" "$os")"
|
||||
tarball="$(mktemp)"
|
||||
curl -fsSL "$url" -o "$tarball"
|
||||
|
||||
install_version_from_tarball "$version" "$tarball" "$arch" "$os"
|
||||
activate_version "$version"
|
||||
install_wrapper
|
||||
cleanup_old_versions 2
|
||||
|
||||
rc_file="$(choose_rc_file)"
|
||||
resolved_home="$(codex_home)"
|
||||
ensure_path_block "$rc_file" "$resolved_home"
|
||||
|
||||
rm -f "$tarball"
|
||||
|
||||
echo "Codex ${version} installed to ${resolved_home}"
|
||||
echo "Updated PATH in ${rc_file}"
|
||||
echo "Open a new shell or run: source ${rc_file}"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
256
installer/lib.sh
Executable file
256
installer/lib.sh
Executable file
@@ -0,0 +1,256 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z "${BASH_VERSION:-}" ]; then
|
||||
echo "Codex installer requires bash." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
CODEX_HOME_DEFAULT="${HOME}/.codex"
|
||||
CODEX_HOME_RESOLVED="${CODEX_HOME:-$CODEX_HOME_DEFAULT}"
|
||||
|
||||
codex_home() {
|
||||
printf '%s\n' "$CODEX_HOME_RESOLVED"
|
||||
}
|
||||
|
||||
codex_bin_dir() {
|
||||
printf '%s/bin\n' "$(codex_home)"
|
||||
}
|
||||
|
||||
codex_versions_dir() {
|
||||
printf '%s/versions\n' "$(codex_home)"
|
||||
}
|
||||
|
||||
codex_tools_dir() {
|
||||
printf '%s/tools\n' "$(codex_home)"
|
||||
}
|
||||
|
||||
codex_tools_bin_dir() {
|
||||
printf '%s/bin\n' "$(codex_tools_dir)"
|
||||
}
|
||||
|
||||
current_version_link() {
|
||||
printf '%s/current\n' "$(codex_versions_dir)"
|
||||
}
|
||||
|
||||
detect_os() {
|
||||
local uname_s
|
||||
uname_s="$(uname -s)"
|
||||
case "$uname_s" in
|
||||
Darwin) printf '%s\n' "apple-darwin" ;;
|
||||
Linux) printf '%s\n' "unknown-linux-musl" ;;
|
||||
*)
|
||||
echo "Unsupported OS: $uname_s" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
detect_arch() {
|
||||
local uname_m
|
||||
uname_m="$(uname -m)"
|
||||
case "$uname_m" in
|
||||
arm64|aarch64) printf '%s\n' "aarch64" ;;
|
||||
x86_64|amd64) printf '%s\n' "x86_64" ;;
|
||||
*)
|
||||
echo "Unsupported architecture: $uname_m" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
github_api() {
|
||||
local path="$1"
|
||||
curl -fsSL \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"https://api.github.com/repos/openai/codex/${path}"
|
||||
}
|
||||
|
||||
latest_tag() {
|
||||
github_api "releases/latest" | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1
|
||||
}
|
||||
|
||||
normalize_version() {
|
||||
local tag="$1"
|
||||
tag="${tag#rust-v}"
|
||||
tag="${tag#v}"
|
||||
printf '%s\n' "$tag"
|
||||
}
|
||||
|
||||
release_tag_for_version() {
|
||||
local version="$1"
|
||||
printf '%s\n' "rust-v${version}"
|
||||
}
|
||||
|
||||
expected_binary_name() {
|
||||
local arch="$1"
|
||||
local os="$2"
|
||||
printf '%s\n' "codex-${arch}-${os}"
|
||||
}
|
||||
|
||||
release_url() {
|
||||
local version="$1"
|
||||
local arch="$2"
|
||||
local os="$3"
|
||||
local tag
|
||||
tag="$(release_tag_for_version "$version")"
|
||||
printf '%s\n' "https://github.com/openai/codex/releases/download/${tag}/codex-${arch}-${os}.tar.gz"
|
||||
}
|
||||
|
||||
ensure_dirs() {
|
||||
mkdir -p "$(codex_bin_dir)" "$(codex_versions_dir)" "$(codex_tools_bin_dir)"
|
||||
}
|
||||
|
||||
ensure_path_block() {
|
||||
local rc_file="$1"
|
||||
local resolved_home="$2"
|
||||
local start_marker="# >>> codex >>>"
|
||||
|
||||
if [ ! -f "$rc_file" ]; then
|
||||
touch "$rc_file"
|
||||
fi
|
||||
|
||||
if grep -Fq "$start_marker" "$rc_file"; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "$resolved_home" = "${HOME}/.codex" ]; then
|
||||
cat >>"$rc_file" <<'EOF'
|
||||
# >>> codex >>>
|
||||
export CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
|
||||
export PATH="$CODEX_HOME/bin:$PATH"
|
||||
# <<< codex <<<
|
||||
EOF
|
||||
else
|
||||
cat >>"$rc_file" <<EOF
|
||||
# >>> codex >>>
|
||||
export CODEX_HOME="${resolved_home}"
|
||||
export PATH="\$CODEX_HOME/bin:\$PATH"
|
||||
# <<< codex <<<
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
choose_rc_file() {
|
||||
local shell_name
|
||||
shell_name="$(basename "${SHELL:-}")"
|
||||
case "$shell_name" in
|
||||
zsh) printf '%s\n' "${HOME}/.zshrc" ;;
|
||||
bash)
|
||||
if [ -f "${HOME}/.bashrc" ]; then
|
||||
printf '%s\n' "${HOME}/.bashrc"
|
||||
else
|
||||
printf '%s\n' "${HOME}/.bash_profile"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
printf '%s\n' "${HOME}/.profile"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
install_wrapper() {
|
||||
local wrapper_path
|
||||
wrapper_path="$(codex_bin_dir)/codex"
|
||||
|
||||
cat >"$wrapper_path" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
|
||||
CURRENT_LINK="$CODEX_HOME/versions/current"
|
||||
TARGET="$CURRENT_LINK/bin/codex"
|
||||
|
||||
if [ ! -x "$TARGET" ]; then
|
||||
echo "Codex is not installed under $CODEX_HOME." >&2
|
||||
echo "Run the installer again to repair the installation." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export CODEX_MANAGED_BY_CURL=1
|
||||
export PATH="$CODEX_HOME/bin:$CODEX_HOME/tools/bin:$CURRENT_LINK/bin:$PATH"
|
||||
|
||||
exec "$TARGET" "$@"
|
||||
EOF
|
||||
|
||||
chmod +x "$wrapper_path"
|
||||
}
|
||||
|
||||
install_version_from_tarball() {
|
||||
local version="$1"
|
||||
local tarball="$2"
|
||||
local arch="$3"
|
||||
local os="$4"
|
||||
|
||||
local versions_dir version_dir bin_dir expected_name tmpdir main_candidate
|
||||
versions_dir="$(codex_versions_dir)"
|
||||
version_dir="${versions_dir}/${version}"
|
||||
bin_dir="${version_dir}/bin"
|
||||
expected_name="$(expected_binary_name "$arch" "$os")"
|
||||
|
||||
rm -rf "$version_dir"
|
||||
mkdir -p "$bin_dir"
|
||||
|
||||
tmpdir="$(mktemp -d)"
|
||||
tar -xzf "$tarball" -C "$tmpdir"
|
||||
|
||||
if [ -f "$tmpdir/$expected_name" ]; then
|
||||
main_candidate="$tmpdir/$expected_name"
|
||||
elif [ -f "$tmpdir/codex" ]; then
|
||||
main_candidate="$tmpdir/codex"
|
||||
else
|
||||
main_candidate="$(find "$tmpdir" -type f -name 'codex*' | head -n1 || true)"
|
||||
fi
|
||||
if [ -z "$main_candidate" ]; then
|
||||
echo "Failed to locate codex binary in tarball." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local files file base dest
|
||||
mapfile -t files < <(find "$tmpdir" -type f)
|
||||
for file in "${files[@]}"; do
|
||||
base="$(basename "$file")"
|
||||
if [ "$file" = "$main_candidate" ]; then
|
||||
dest="$bin_dir/codex"
|
||||
else
|
||||
dest="$bin_dir/$base"
|
||||
fi
|
||||
mv "$file" "$dest"
|
||||
chmod +x "$dest" 2>/dev/null || true
|
||||
done
|
||||
|
||||
if [ ! -x "$bin_dir/codex" ]; then
|
||||
echo "Failed to install codex binary." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf "$tmpdir"
|
||||
}
|
||||
|
||||
activate_version() {
|
||||
local version="$1"
|
||||
local link
|
||||
link="$(current_version_link)"
|
||||
ln -sfn "$(codex_versions_dir)/$version" "$link"
|
||||
}
|
||||
|
||||
cleanup_old_versions() {
|
||||
local keep="${1:-2}"
|
||||
local versions_dir
|
||||
versions_dir="$(codex_versions_dir)"
|
||||
if [ ! -d "$versions_dir" ]; then
|
||||
return
|
||||
fi
|
||||
if ! compgen -G "$versions_dir/*" >/dev/null; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Remove older versions while keeping the most recent N directories.
|
||||
# We intentionally ignore errors here so cleanup never blocks install.
|
||||
ls -1dt "$versions_dir"/* 2>/dev/null \
|
||||
| grep -v '/current$' \
|
||||
| tail -n +"$((keep + 1))" \
|
||||
| xargs -I{} rm -rf "{}" 2>/dev/null || true
|
||||
}
|
||||
66
installer/update.sh
Executable file
66
installer/update.sh
Executable file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z "${BASH_VERSION:-}" ]; then
|
||||
echo "This updater requires bash." >&2
|
||||
echo "Re-run with: curl -fsSL https://raw.githubusercontent.com/openai/codex/main/installer/update.sh | bash" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
INSTALLER_BASE_URL="${CODEX_INSTALLER_BASE_URL:-https://raw.githubusercontent.com/openai/codex/main/installer}"
|
||||
|
||||
load_lib() {
|
||||
local script_dir lib_path tmp_lib
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
|
||||
lib_path="${script_dir}/lib.sh"
|
||||
|
||||
if [ -f "$lib_path" ]; then
|
||||
# Running from a repo checkout.
|
||||
# shellcheck disable=SC1090
|
||||
source "$lib_path"
|
||||
return
|
||||
fi
|
||||
|
||||
tmp_lib="$(mktemp)"
|
||||
curl -fsSL "${INSTALLER_BASE_URL}/lib.sh" -o "$tmp_lib"
|
||||
# shellcheck disable=SC1090
|
||||
source "$tmp_lib"
|
||||
rm -f "$tmp_lib"
|
||||
}
|
||||
|
||||
load_lib
|
||||
|
||||
main() {
|
||||
ensure_dirs
|
||||
|
||||
local arch os tag version url tarball rc_file resolved_home
|
||||
arch="$(detect_arch)"
|
||||
os="$(detect_os)"
|
||||
|
||||
tag="$(latest_tag)"
|
||||
if [ -z "$tag" ]; then
|
||||
echo "Failed to determine the latest Codex release tag." >&2
|
||||
exit 1
|
||||
fi
|
||||
version="$(normalize_version "$tag")"
|
||||
|
||||
url="$(release_url "$version" "$arch" "$os")"
|
||||
tarball="$(mktemp)"
|
||||
curl -fsSL "$url" -o "$tarball"
|
||||
|
||||
install_version_from_tarball "$version" "$tarball" "$arch" "$os"
|
||||
activate_version "$version"
|
||||
install_wrapper
|
||||
cleanup_old_versions 2
|
||||
|
||||
rc_file="$(choose_rc_file)"
|
||||
resolved_home="$(codex_home)"
|
||||
ensure_path_block "$rc_file" "$resolved_home"
|
||||
|
||||
rm -f "$tarball"
|
||||
|
||||
echo "Codex updated to ${version}"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user