Fix Codex startup approvals and companion upgrades
This commit is contained in:
+174
-35
@@ -28,6 +28,7 @@ read_env_value() {
|
||||
|
||||
HOST_CODEX_SOCKET="${HOST_CODEX_SOCKET:-$(read_env_value HOST_CODEX_SOCKET)}"
|
||||
HOST_CODEX_SOCKET="${HOST_CODEX_SOCKET:-$RUN_DIR/codex.sock}"
|
||||
CODEX_APPROVE_FOR_ME="${CODEX_APPROVE_FOR_ME:-$(read_env_value CODEX_APPROVE_FOR_ME)}"
|
||||
|
||||
mkdir -p "$RUN_DIR"
|
||||
chmod 700 "$RUN_DIR"
|
||||
@@ -37,15 +38,17 @@ usage() {
|
||||
Usage: $0 <start|stop|status|check-updates|check-upgrade> [options]
|
||||
|
||||
Commands:
|
||||
start Start codex app-server if it is not already running.
|
||||
start [--approve-for-me]
|
||||
Start codex app-server if it is not already running.
|
||||
stop Stop codex app-server and remove stale runtime files.
|
||||
status Print whether codex app-server is running.
|
||||
check-updates [-y] Check GitHub releases and optionally install the latest Codex binary.
|
||||
check-updates [-y] Check GitHub releases and optionally install Codex and its companion binaries.
|
||||
check-upgrade [-y] Alias for check-updates.
|
||||
|
||||
Environment:
|
||||
CODEX_BIN Codex executable to replace. Defaults to the codex found on PATH.
|
||||
CODEX_RELEASE_REPO GitHub repo for releases. Defaults to openai/codex.
|
||||
CODEX_APPROVE_FOR_ME Enable automatic approval review when starting Codex (1/true/yes).
|
||||
USAGE
|
||||
}
|
||||
|
||||
@@ -114,7 +117,13 @@ codex_bin() {
|
||||
}
|
||||
|
||||
start_server() {
|
||||
local old_pid pid start_codex_bin
|
||||
local old_pid pid start_codex_bin approve_for_me
|
||||
approve_for_me="${1:-$CODEX_APPROVE_FOR_ME}"
|
||||
case "$approve_for_me" in
|
||||
1|true|yes|on) approve_for_me=1 ;;
|
||||
0|false|no|off|"") approve_for_me=0 ;;
|
||||
*) echo "invalid CODEX_APPROVE_FOR_ME value: $approve_for_me" >&2; return 2 ;;
|
||||
esac
|
||||
old_pid="$(pid_from_file)"
|
||||
if [[ -n "$old_pid" ]] && kill -0 "$old_pid" 2>/dev/null; then
|
||||
if [[ -S "$HOST_CODEX_SOCKET" ]]; then
|
||||
@@ -145,8 +154,12 @@ start_server() {
|
||||
tail -f /dev/null > "$1" &
|
||||
writer=$!
|
||||
trap "kill $writer 2>/dev/null || true" EXIT
|
||||
"$4" app-server --listen "$2" < "$1"
|
||||
' codex-app-server "$STDIN_FIFO" "unix://$HOST_CODEX_SOCKET" "$PID_FILE" "$start_codex_bin" >> "$LOG_FILE" 2>&1
|
||||
codex_args=(app-server --listen "$2")
|
||||
if [[ "$5" == "1" ]]; then
|
||||
codex_args=(--approve-for-me "${codex_args[@]}")
|
||||
fi
|
||||
"$4" "${codex_args[@]}" < "$1"
|
||||
' codex-app-server "$STDIN_FIFO" "unix://$HOST_CODEX_SOCKET" "$PID_FILE" "$start_codex_bin" "$approve_for_me" >> "$LOG_FILE" 2>&1
|
||||
|
||||
for _ in $(seq 1 50); do
|
||||
[[ -f "$PID_FILE" ]] && break
|
||||
@@ -312,6 +325,7 @@ target, path = sys.argv[1], sys.argv[2]
|
||||
needs_bwrap = "linux" in target
|
||||
codex_asset_name = f"codex-{target}.tar.gz"
|
||||
bwrap_asset_name = f"bwrap-{target}.tar.gz" if needs_bwrap else None
|
||||
code_mode_host_asset_name = f"codex-code-mode-host-{target}.tar.gz"
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
release = json.load(f)
|
||||
tag = release.get("tag_name", "")
|
||||
@@ -323,7 +337,11 @@ elif version.startswith("v"):
|
||||
assets = {asset.get("name"): asset for asset in release.get("assets", [])}
|
||||
codex_asset = assets.get(codex_asset_name)
|
||||
bwrap_asset = assets.get(bwrap_asset_name) if needs_bwrap else None
|
||||
required_assets = [(codex_asset_name, codex_asset)]
|
||||
code_mode_host_asset = assets.get(code_mode_host_asset_name)
|
||||
required_assets = [
|
||||
(codex_asset_name, codex_asset),
|
||||
(code_mode_host_asset_name, code_mode_host_asset),
|
||||
]
|
||||
if needs_bwrap:
|
||||
required_assets.append((bwrap_asset_name, bwrap_asset))
|
||||
missing = [name for name, asset in required_assets if asset is None]
|
||||
@@ -338,6 +356,8 @@ if bwrap_asset is not None:
|
||||
else:
|
||||
print("")
|
||||
print("")
|
||||
print(code_mode_host_asset.get("browser_download_url", ""))
|
||||
print(code_mode_host_asset.get("digest", ""))
|
||||
print(version)
|
||||
print(tag)
|
||||
PY
|
||||
@@ -399,6 +419,32 @@ extract_bwrap_binary() {
|
||||
printf '%s\n' "$found"
|
||||
}
|
||||
|
||||
extract_code_mode_host_binary() {
|
||||
local archive="$1" dest="$2" found
|
||||
local -a matches=()
|
||||
mkdir -p "$dest/code-mode-host-extract"
|
||||
tar -xzf "$archive" -C "$dest/code-mode-host-extract"
|
||||
mapfile -d '' -t matches < <(
|
||||
find "$dest/code-mode-host-extract" -type f \
|
||||
\( -name codex-code-mode-host -o -name 'codex-code-mode-host-*' \) -print0
|
||||
)
|
||||
if [[ "${#matches[@]}" -eq 0 ]]; then
|
||||
echo "downloaded archive does not contain a code-mode host executable" >&2
|
||||
return 1
|
||||
fi
|
||||
if [[ "${#matches[@]}" -ne 1 ]]; then
|
||||
echo "downloaded archive contains multiple code-mode host executables" >&2
|
||||
return 1
|
||||
fi
|
||||
found="${matches[0]}"
|
||||
chmod +x "$found"
|
||||
if ! "$found" --help >/dev/null 2>&1; then
|
||||
echo "downloaded code-mode host executable failed validation" >&2
|
||||
return 1
|
||||
fi
|
||||
printf '%s\n' "$found"
|
||||
}
|
||||
|
||||
bundled_bwrap_path() {
|
||||
local bin="$1"
|
||||
printf '%s/codex-resources/bwrap\n' "$(dirname "$bin")"
|
||||
@@ -414,6 +460,17 @@ bwrap_required_for_target() {
|
||||
[[ "$1" == *linux* ]]
|
||||
}
|
||||
|
||||
code_mode_host_path() {
|
||||
local bin="$1"
|
||||
printf '%s/codex-code-mode-host\n' "$(dirname "$bin")"
|
||||
}
|
||||
|
||||
code_mode_host_installed() {
|
||||
local bin="$1" host
|
||||
host="$(code_mode_host_path "$bin")"
|
||||
[[ -x "$host" && ! -L "$host" ]]
|
||||
}
|
||||
|
||||
run_install() {
|
||||
if [[ "${#INSTALL_PREFIX[@]}" -gt 0 ]]; then
|
||||
"${INSTALL_PREFIX[@]}" "$@"
|
||||
@@ -456,8 +513,27 @@ install_bundled_bwrap() {
|
||||
run_install mv -f "$tmp_new" "$bundled"
|
||||
}
|
||||
|
||||
install_code_mode_host() {
|
||||
local candidate="$1" bin="$2" backup="$3" host host_dir tmp_new host_backup host_missing
|
||||
host="$(code_mode_host_path "$bin")"
|
||||
host_dir="$(dirname "$host")"
|
||||
tmp_new="$host.new.$$"
|
||||
host_backup="$backup.code-mode-host"
|
||||
host_missing="$backup.code-mode-host.missing"
|
||||
|
||||
run_install mkdir -p "$host_dir"
|
||||
if [[ -e "$host" ]]; then
|
||||
run_install cp -p "$host" "$host_backup"
|
||||
else
|
||||
run_install touch "$host_missing"
|
||||
fi
|
||||
run_install install -m 0755 "$candidate" "$tmp_new"
|
||||
run_install mv -f "$tmp_new" "$host"
|
||||
}
|
||||
|
||||
install_candidate() {
|
||||
local candidate="$1" bwrap_candidate="$2" bin="$3" backup="$4" tmp_new="$bin.new.$$"
|
||||
local candidate="$1" bwrap_candidate="$2" code_mode_host_candidate="$3" bin="$4" backup="$5" tmp_new
|
||||
tmp_new="$bin.new.$$"
|
||||
choose_install_prefix "$bin"
|
||||
run_install cp -p "$bin" "$backup"
|
||||
run_install install -m 0755 "$candidate" "$tmp_new"
|
||||
@@ -465,10 +541,11 @@ install_candidate() {
|
||||
if [[ -n "$bwrap_candidate" ]]; then
|
||||
install_bundled_bwrap "$bwrap_candidate" "$bin" "$backup"
|
||||
fi
|
||||
install_code_mode_host "$code_mode_host_candidate" "$bin" "$backup"
|
||||
}
|
||||
|
||||
restore_backup() {
|
||||
local bin="$1" backup="$2" tmp_failed="$bin.failed.$$" bundled bwrap_backup bwrap_missing
|
||||
local bin="$1" backup="$2" tmp_failed="$bin.failed.$$" bundled bwrap_backup bwrap_missing host host_backup host_missing
|
||||
if [[ ! -e "$backup" ]]; then
|
||||
echo "backup missing; cannot restore $bin" >&2
|
||||
return 1
|
||||
@@ -489,6 +566,17 @@ restore_backup() {
|
||||
run_install rm -f "$bundled"
|
||||
run_install rm -f "$bwrap_missing"
|
||||
fi
|
||||
|
||||
host="$(code_mode_host_path "$bin")"
|
||||
host_backup="$backup.code-mode-host"
|
||||
host_missing="$backup.code-mode-host.missing"
|
||||
if [[ -e "$host_backup" ]]; then
|
||||
run_install mkdir -p "$(dirname "$host")"
|
||||
run_install mv -f "$host_backup" "$host"
|
||||
elif [[ -e "$host_missing" ]]; then
|
||||
run_install rm -f "$host"
|
||||
run_install rm -f "$host_missing"
|
||||
fi
|
||||
}
|
||||
|
||||
confirm_upgrade() {
|
||||
@@ -506,14 +594,15 @@ confirm_upgrade() {
|
||||
}
|
||||
|
||||
apply_upgrade() {
|
||||
local candidate="$1" bwrap_candidate="$2" bin="$3" backup="$4" local_version="$5" latest_version="$6" was_running=0
|
||||
local candidate="$1" bwrap_candidate="$2" code_mode_host_candidate="$3" bin="$4" backup="$5" local_version="$6" latest_version="$7" was_running=0
|
||||
if is_running; then
|
||||
was_running=1
|
||||
stop_server
|
||||
fi
|
||||
|
||||
if ! install_candidate "$candidate" "$bwrap_candidate" "$bin" "$backup"; then
|
||||
if ! install_candidate "$candidate" "$bwrap_candidate" "$code_mode_host_candidate" "$bin" "$backup"; then
|
||||
echo "failed to install Codex update" >&2
|
||||
restore_backup "$bin" "$backup" || true
|
||||
if [[ "$was_running" == "1" ]]; then
|
||||
start_server || true
|
||||
fi
|
||||
@@ -534,12 +623,12 @@ apply_upgrade() {
|
||||
}
|
||||
|
||||
handoff_upgrade() {
|
||||
local candidate="$1" bwrap_candidate="$2" bin="$3" backup="$4" update_dir="$5" local_version="$6" latest_version="$7"
|
||||
local candidate="$1" bwrap_candidate="$2" code_mode_host_candidate="$3" bin="$4" backup="$5" update_dir="$6" local_version="$7" latest_version="$8"
|
||||
: > "$UPGRADE_LOG_FILE"
|
||||
setsid -f bash -c '
|
||||
sleep 1
|
||||
"$0" __apply-upgrade "$1" "$2" "$3" "$4" "$5" "$6" "$7"
|
||||
' "$0" "$candidate" "$bwrap_candidate" "$bin" "$backup" "$update_dir" "$local_version" "$latest_version" >> "$UPGRADE_LOG_FILE" 2>&1
|
||||
"$0" __apply-upgrade "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8"
|
||||
' "$0" "$candidate" "$bwrap_candidate" "$code_mode_host_candidate" "$bin" "$backup" "$update_dir" "$local_version" "$latest_version" >> "$UPGRADE_LOG_FILE" 2>&1
|
||||
echo "Codex upgrade handoff started; app-server will restart if replacement succeeds. log=$UPGRADE_LOG_FILE"
|
||||
}
|
||||
|
||||
@@ -559,8 +648,8 @@ check_updates() {
|
||||
require_cmd python3
|
||||
require_cmd ps
|
||||
|
||||
local bin local_version target json latest_version latest_tag codex_download_url codex_digest bwrap_download_url bwrap_digest
|
||||
local codex_archive bwrap_archive tmp candidate bwrap_candidate candidate_version backup
|
||||
local bin local_version target json latest_version latest_tag codex_download_url codex_digest bwrap_download_url bwrap_digest code_mode_host_download_url code_mode_host_digest
|
||||
local codex_archive bwrap_archive code_mode_host_archive tmp candidate bwrap_candidate code_mode_host_candidate candidate_version backup missing_bwrap missing_code_mode_host
|
||||
bin="$(codex_bin)"
|
||||
if [[ -z "$bin" ]]; then
|
||||
echo "codex executable not found; set CODEX_BIN" >&2
|
||||
@@ -585,8 +674,10 @@ check_updates() {
|
||||
codex_digest="${release_info[1]:-}"
|
||||
bwrap_download_url="${release_info[2]:-}"
|
||||
bwrap_digest="${release_info[3]:-}"
|
||||
latest_version="${release_info[4]:-}"
|
||||
latest_tag="${release_info[5]:-}"
|
||||
code_mode_host_download_url="${release_info[4]:-}"
|
||||
code_mode_host_digest="${release_info[5]:-}"
|
||||
latest_version="${release_info[6]:-}"
|
||||
latest_tag="${release_info[7]:-}"
|
||||
if [[ -z "$latest_version" || -z "$codex_download_url" ]]; then
|
||||
rm -rf "$tmp"
|
||||
echo "could not determine latest Codex release for $target" >&2
|
||||
@@ -597,28 +688,59 @@ check_updates() {
|
||||
echo "could not determine latest bundled bwrap release for $target" >&2
|
||||
return 1
|
||||
fi
|
||||
if [[ -z "$code_mode_host_download_url" ]]; then
|
||||
rm -rf "$tmp"
|
||||
echo "could not determine latest code-mode host release for $target" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! version_gt "$latest_version" "$local_version"; then
|
||||
if ! bwrap_required_for_target "$target" || bundled_bwrap_installed "$bin"; then
|
||||
missing_bwrap=0
|
||||
missing_code_mode_host=0
|
||||
if bwrap_required_for_target "$target" && ! bundled_bwrap_installed "$bin"; then
|
||||
missing_bwrap=1
|
||||
fi
|
||||
if ! code_mode_host_installed "$bin"; then
|
||||
missing_code_mode_host=1
|
||||
fi
|
||||
if [[ "$missing_bwrap" == "0" && "$missing_code_mode_host" == "0" ]]; then
|
||||
rm -rf "$tmp"
|
||||
echo "Codex is already current: $local_version (latest $latest_version)"
|
||||
return 0
|
||||
fi
|
||||
echo "Codex is already current: $local_version (latest $latest_version); installing missing bundled bwrap"
|
||||
bwrap_archive="$tmp/bwrap-$target.tar.gz"
|
||||
curl -fL "$bwrap_download_url" -o "$bwrap_archive"
|
||||
verify_digest "$bwrap_archive" "$bwrap_digest"
|
||||
bwrap_candidate="$(extract_bwrap_binary "$bwrap_archive" "$tmp")"
|
||||
echo "Codex is already current: $local_version (latest $latest_version); installing missing companion binaries"
|
||||
bwrap_candidate=""
|
||||
code_mode_host_candidate=""
|
||||
if [[ "$missing_bwrap" == "1" ]]; then
|
||||
bwrap_archive="$tmp/bwrap-$target.tar.gz"
|
||||
curl -fL "$bwrap_download_url" -o "$bwrap_archive"
|
||||
verify_digest "$bwrap_archive" "$bwrap_digest"
|
||||
bwrap_candidate="$(extract_bwrap_binary "$bwrap_archive" "$tmp")"
|
||||
fi
|
||||
if [[ "$missing_code_mode_host" == "1" ]]; then
|
||||
code_mode_host_archive="$tmp/codex-code-mode-host-$target.tar.gz"
|
||||
curl -fL "$code_mode_host_download_url" -o "$code_mode_host_archive"
|
||||
verify_digest "$code_mode_host_archive" "$code_mode_host_digest"
|
||||
code_mode_host_candidate="$(extract_code_mode_host_binary "$code_mode_host_archive" "$tmp")"
|
||||
fi
|
||||
backup="$bin.bak.$(date -u +%Y%m%d%H%M%S)"
|
||||
choose_install_prefix "$bin"
|
||||
if install_bundled_bwrap "$bwrap_candidate" "$bin" "$backup"; then
|
||||
if [[ -n "$bwrap_candidate" ]]; then
|
||||
install_bundled_bwrap "$bwrap_candidate" "$bin" "$backup"
|
||||
run_install rm -f "$backup.bwrap.missing"
|
||||
rm -rf "$tmp"
|
||||
echo "Bundled bwrap installed: $(bundled_bwrap_path "$bin")"
|
||||
return 0
|
||||
fi
|
||||
if [[ -n "$code_mode_host_candidate" ]]; then
|
||||
install_code_mode_host "$code_mode_host_candidate" "$bin" "$backup"
|
||||
run_install rm -f "$backup.code-mode-host.missing"
|
||||
fi
|
||||
rm -rf "$tmp"
|
||||
return 1
|
||||
if [[ "$missing_bwrap" == "1" ]]; then
|
||||
echo "Bundled bwrap installed: $(bundled_bwrap_path "$bin")"
|
||||
fi
|
||||
if [[ "$missing_code_mode_host" == "1" ]]; then
|
||||
echo "Code-mode host installed: $(code_mode_host_path "$bin")"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
echo "Codex update available: $local_version -> $latest_version ($latest_tag)"
|
||||
confirm_upgrade "$local_version" "$latest_version" "$bin"
|
||||
@@ -635,6 +757,10 @@ check_updates() {
|
||||
else
|
||||
bwrap_candidate=""
|
||||
fi
|
||||
code_mode_host_archive="$tmp/codex-code-mode-host-$target.tar.gz"
|
||||
curl -fL "$code_mode_host_download_url" -o "$code_mode_host_archive"
|
||||
verify_digest "$code_mode_host_archive" "$code_mode_host_digest"
|
||||
code_mode_host_candidate="$(extract_code_mode_host_binary "$code_mode_host_archive" "$tmp")"
|
||||
candidate_version="$(codex_version_from "$candidate")"
|
||||
if [[ "$candidate_version" != "$latest_version" ]]; then
|
||||
rm -rf "$tmp"
|
||||
@@ -646,11 +772,11 @@ check_updates() {
|
||||
choose_install_prefix "$bin"
|
||||
|
||||
if is_running; then
|
||||
handoff_upgrade "$candidate" "$bwrap_candidate" "$bin" "$backup" "$tmp" "$local_version" "$latest_version"
|
||||
handoff_upgrade "$candidate" "$bwrap_candidate" "$code_mode_host_candidate" "$bin" "$backup" "$tmp" "$local_version" "$latest_version"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if apply_upgrade "$candidate" "$bwrap_candidate" "$bin" "$backup" "$local_version" "$latest_version"; then
|
||||
if apply_upgrade "$candidate" "$bwrap_candidate" "$code_mode_host_candidate" "$bin" "$backup" "$local_version" "$latest_version"; then
|
||||
rm -rf "$tmp"
|
||||
return 0
|
||||
fi
|
||||
@@ -659,7 +785,7 @@ check_updates() {
|
||||
}
|
||||
|
||||
apply_upgrade_worker() {
|
||||
local candidate="$1" bwrap_candidate="$2" bin="$3" backup="$4" update_dir="$5" local_version="$6" latest_version="$7" rc=0
|
||||
local candidate="$1" bwrap_candidate="$2" code_mode_host_candidate="$3" bin="$4" backup="$5" update_dir="$6" local_version="$7" latest_version="$8" rc=0
|
||||
if [[ ! -x "$candidate" ]]; then
|
||||
echo "upgrade candidate is missing or not executable: $candidate" >&2
|
||||
rm -rf "$update_dir"
|
||||
@@ -670,7 +796,12 @@ apply_upgrade_worker() {
|
||||
rm -rf "$update_dir"
|
||||
return 1
|
||||
fi
|
||||
if ! apply_upgrade "$candidate" "$bwrap_candidate" "$bin" "$backup" "$local_version" "$latest_version"; then
|
||||
if [[ ! -x "$code_mode_host_candidate" ]]; then
|
||||
echo "code-mode host candidate is missing or not executable: $code_mode_host_candidate" >&2
|
||||
rm -rf "$update_dir"
|
||||
return 1
|
||||
fi
|
||||
if ! apply_upgrade "$candidate" "$bwrap_candidate" "$code_mode_host_candidate" "$bin" "$backup" "$local_version" "$latest_version"; then
|
||||
rc=1
|
||||
fi
|
||||
rm -rf "$update_dir"
|
||||
@@ -681,8 +812,16 @@ cmd="${1:-help}"
|
||||
case "$cmd" in
|
||||
start)
|
||||
shift || true
|
||||
if [[ $# -ne 0 ]]; then usage; exit 2; fi
|
||||
start_server
|
||||
start_approve_for_me="$CODEX_APPROVE_FOR_ME"
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--approve-for-me) start_approve_for_me=1 ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) echo "unknown start option: $1" >&2; usage; exit 2 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
start_server "$start_approve_for_me"
|
||||
;;
|
||||
stop)
|
||||
shift || true
|
||||
@@ -700,7 +839,7 @@ case "$cmd" in
|
||||
;;
|
||||
__apply-upgrade)
|
||||
shift || true
|
||||
if [[ $# -ne 7 ]]; then echo "invalid upgrade worker arguments" >&2; exit 2; fi
|
||||
if [[ $# -ne 8 ]]; then echo "invalid upgrade worker arguments" >&2; exit 2; fi
|
||||
apply_upgrade_worker "$@"
|
||||
;;
|
||||
-h|--help|help)
|
||||
|
||||
Reference in New Issue
Block a user