From 4784ac20bf08f4f84e6b51eb4144472a4e53fa3f Mon Sep 17 00:00:00 2001 From: Owen Lin Date: Tue, 17 Feb 2026 15:55:27 -0800 Subject: [PATCH] chore(zsh): add patched-zsh patch artifact and build script --- scripts/build-patched-zsh.sh | 126 +++++++++++ shell-tool-mcp/patches/zsh-exec-wrapper.patch | 204 +++++++++++++++++- 2 files changed, 325 insertions(+), 5 deletions(-) create mode 100755 scripts/build-patched-zsh.sh diff --git a/scripts/build-patched-zsh.sh b/scripts/build-patched-zsh.sh new file mode 100755 index 00000000000..c6bca32b102 --- /dev/null +++ b/scripts/build-patched-zsh.sh @@ -0,0 +1,126 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Build the Codex-patched zsh used by shell-tool-mcp. +# +# Defaults are intentionally override-friendly: +# CODEX_REPO Codex repo root containing shell-tool-mcp/patches +# ZSH_SRC_DIR Working clone location for zsh source +# INSTALL_PREFIX Install prefix for make install +# JOBS Parallel jobs for make +# ZSH_REMOTE Upstream zsh remote +# INSTALL_DOCS Set to 1 to run full `make install` (includes manpages) + +ZSH_COMMIT="77045ef899e53b9598bebc5a41db93a548a40ca6" +ZSH_REMOTE="${ZSH_REMOTE:-https://git.code.sf.net/p/zsh/code}" +INSTALL_PREFIX="${INSTALL_PREFIX:-$HOME/.local/codex-zsh-${ZSH_COMMIT:0:7}}" + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" + +resolve_codex_repo() { + if [[ -n "${CODEX_REPO:-}" ]]; then + printf '%s\n' "$CODEX_REPO" + return + fi + + # Most reliable when this script is run from inside the codex repo. + local from_script + from_script="$(cd -- "$SCRIPT_DIR/.." && pwd)" + if [[ -f "$from_script/shell-tool-mcp/patches/zsh-exec-wrapper.patch" ]]; then + printf '%s\n' "$from_script" + return + fi + + # Common local workspace layouts. + if [[ -f "$HOME/repos/codex/shell-tool-mcp/patches/zsh-exec-wrapper.patch" ]]; then + printf '%s\n' "$HOME/repos/codex" + return + fi + + if [[ -f "$HOME/code/codex/shell-tool-mcp/patches/zsh-exec-wrapper.patch" ]]; then + printf '%s\n' "$HOME/code/codex" + return + fi + + echo "Could not locate codex repo. Set CODEX_REPO=/path/to/codex." >&2 + exit 1 +} + +resolve_zsh_src_dir() { + if [[ -n "${ZSH_SRC_DIR:-}" ]]; then + printf '%s\n' "$ZSH_SRC_DIR" + return + fi + + if [[ -d "$HOME/repos/zsh/.git" ]]; then + printf '%s\n' "$HOME/repos/zsh" + return + fi + + if [[ -d "$HOME/code/zsh/.git" ]]; then + printf '%s\n' "$HOME/code/zsh" + return + fi + + # Fallback for users without an existing clone. + printf '%s\n' "$HOME/src/zsh-code" +} + +CODEX_REPO="$(resolve_codex_repo)" +ZSH_SRC_DIR="$(resolve_zsh_src_dir)" +PATCH_FILE="$CODEX_REPO/shell-tool-mcp/patches/zsh-exec-wrapper.patch" + +if [[ ! -f "$PATCH_FILE" ]]; then + echo "Patch file not found: $PATCH_FILE" >&2 + exit 1 +fi + +if [[ -z "${JOBS:-}" ]]; then + if command -v nproc >/dev/null 2>&1; then + JOBS="$(nproc)" + elif command -v sysctl >/dev/null 2>&1; then + JOBS="$(sysctl -n hw.ncpu)" + else + JOBS=4 + fi +fi + +mkdir -p "$(dirname -- "$ZSH_SRC_DIR")" + +if [[ ! -d "$ZSH_SRC_DIR/.git" ]]; then + git clone "$ZSH_REMOTE" "$ZSH_SRC_DIR" +fi + +git -C "$ZSH_SRC_DIR" fetch --depth 1 origin "$ZSH_COMMIT" +git -C "$ZSH_SRC_DIR" checkout --detach -f "$ZSH_COMMIT" +git -C "$ZSH_SRC_DIR" reset --hard "$ZSH_COMMIT" + +if git -C "$ZSH_SRC_DIR" apply --reverse --check "$PATCH_FILE" >/dev/null 2>&1; then + echo "Patch already applied: $PATCH_FILE" +else + git -C "$ZSH_SRC_DIR" apply --check "$PATCH_FILE" + git -C "$ZSH_SRC_DIR" apply "$PATCH_FILE" +fi + +( + cd "$ZSH_SRC_DIR" + ./Util/preconfig + ./configure --prefix="$INSTALL_PREFIX" + make -j"$JOBS" + if [[ "${INSTALL_DOCS:-0}" == "1" ]]; then + make install + else + make install.bin + fi +) + +cat < 0 && ++ wrapper_origin_len < (int)sizeof(wrapper_origin_buf)) { ++ wrapper_envc = 0; ++ wrapper_origin_idx = -1; ++ for (eep = newenvp; *eep; eep++) { ++ if (strncmp(*eep, "CODEX_ZSH_EXEC_BRIDGE_WRAPPER_ORIGIN=", ++ sizeof("CODEX_ZSH_EXEC_BRIDGE_WRAPPER_ORIGIN=") - 1) == 0) ++ wrapper_origin_idx = wrapper_envc; ++ wrapper_envc++; ++ } ++ wrapper_envp = zalloc((wrapper_envc + 2) * sizeof(char *)); ++ if (wrapper_origin_idx >= 0) { ++ for (wrapper_envc = 0; newenvp[wrapper_envc]; wrapper_envc++) ++ wrapper_envp[wrapper_envc] = ++ wrapper_envc == wrapper_origin_idx ? ++ wrapper_origin_buf : newenvp[wrapper_envc]; ++ wrapper_envp[wrapper_envc] = NULL; ++ } else { ++ for (wrapper_envc = 0; newenvp[wrapper_envc]; wrapper_envc++) ++ wrapper_envp[wrapper_envc] = newenvp[wrapper_envc]; ++ wrapper_envp[wrapper_envc++] = wrapper_origin_buf; ++ wrapper_envp[wrapper_envc] = NULL; ++ } ++ } + pth = exec_wrapper; + } winch_unblock(); - execve(pth, argv, newenvp); -+ execve(pth, exec_argv, newenvp); ++ execve(pth, exec_argv, wrapper_envp); + pth = orig_pth; /* If the execve returns (which in general shouldn't happen), * * then check for an errno equal to ENOEXEC. This errno is set * +diff --git a/Src/init.c b/Src/init.c +index 20b8cc7fd..b6d5c9c9a 100644 +--- a/Src/init.c ++++ b/Src/init.c +@@ -59,6 +59,9 @@ int underscoreused; + /**/ + int sourcelevel; + ++/**/ ++int zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_USER_COMMAND; ++ + /* the shell tty fd */ + + /**/ +@@ -1450,14 +1453,25 @@ init_signals(void) + void + run_init_scripts(void) + { ++ int old_origin; ++ + noerrexit = NOERREXIT_EXIT | NOERREXIT_RETURN | NOERREXIT_SIGNAL; ++ zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_USER_COMMAND; + + if (EMULATION(EMULATE_KSH|EMULATE_SH)) { +- if (islogin) ++ if (islogin) { ++ old_origin = zsh_exec_wrapper_origin; ++ zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_LOGIN_STARTUP; + source("/etc/profile"); ++ zsh_exec_wrapper_origin = old_origin; ++ } + if (unset(PRIVILEGED)) { +- if (islogin) ++ if (islogin) { ++ old_origin = zsh_exec_wrapper_origin; ++ zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_LOGIN_STARTUP; + sourcehome(".profile"); ++ zsh_exec_wrapper_origin = old_origin; ++ } + + if (interact) { + noerrs = 2; +@@ -1467,16 +1481,26 @@ run_init_scripts(void) + if (!parsestr(&s)) { + singsub(&s); + noerrs = 0; ++ old_origin = zsh_exec_wrapper_origin; ++ zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_RC_STARTUP; + source(s); ++ zsh_exec_wrapper_origin = old_origin; + } + } + noerrs = 0; + } +- } else ++ } else { ++ old_origin = zsh_exec_wrapper_origin; ++ zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_LOGIN_STARTUP; + source("/etc/suid_profile"); ++ zsh_exec_wrapper_origin = old_origin; ++ } + } else { + #ifdef GLOBAL_ZSHENV ++ old_origin = zsh_exec_wrapper_origin; ++ zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_RC_STARTUP; + source(GLOBAL_ZSHENV); ++ zsh_exec_wrapper_origin = old_origin; + #endif + + if (isset(RCS) && unset(PRIVILEGED)) +@@ -1492,33 +1516,61 @@ run_init_scripts(void) + } + } + ++ old_origin = zsh_exec_wrapper_origin; ++ zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_RC_STARTUP; + sourcehome(".zshenv"); ++ zsh_exec_wrapper_origin = old_origin; + } + if (islogin) { + #ifdef GLOBAL_ZPROFILE +- if (isset(RCS) && isset(GLOBALRCS)) ++ if (isset(RCS) && isset(GLOBALRCS)) { ++ old_origin = zsh_exec_wrapper_origin; ++ zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_LOGIN_STARTUP; + source(GLOBAL_ZPROFILE); ++ zsh_exec_wrapper_origin = old_origin; ++ } + #endif +- if (isset(RCS) && unset(PRIVILEGED)) ++ if (isset(RCS) && unset(PRIVILEGED)) { ++ old_origin = zsh_exec_wrapper_origin; ++ zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_LOGIN_STARTUP; + sourcehome(".zprofile"); ++ zsh_exec_wrapper_origin = old_origin; ++ } + } + if (interact) { + #ifdef GLOBAL_ZSHRC +- if (isset(RCS) && isset(GLOBALRCS)) ++ if (isset(RCS) && isset(GLOBALRCS)) { ++ old_origin = zsh_exec_wrapper_origin; ++ zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_RC_STARTUP; + source(GLOBAL_ZSHRC); ++ zsh_exec_wrapper_origin = old_origin; ++ } + #endif +- if (isset(RCS) && unset(PRIVILEGED)) ++ if (isset(RCS) && unset(PRIVILEGED)) { ++ old_origin = zsh_exec_wrapper_origin; ++ zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_RC_STARTUP; + sourcehome(".zshrc"); ++ zsh_exec_wrapper_origin = old_origin; ++ } + } + if (islogin) { + #ifdef GLOBAL_ZLOGIN +- if (isset(RCS) && isset(GLOBALRCS)) ++ if (isset(RCS) && isset(GLOBALRCS)) { ++ old_origin = zsh_exec_wrapper_origin; ++ zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_LOGIN_STARTUP; + source(GLOBAL_ZLOGIN); ++ zsh_exec_wrapper_origin = old_origin; ++ } + #endif +- if (isset(RCS) && unset(PRIVILEGED)) ++ if (isset(RCS) && unset(PRIVILEGED)) { ++ old_origin = zsh_exec_wrapper_origin; ++ zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_LOGIN_STARTUP; + sourcehome(".zlogin"); ++ zsh_exec_wrapper_origin = old_origin; ++ } + } + } ++ zsh_exec_wrapper_origin = EXEC_WRAPPER_ORIGIN_USER_COMMAND; + noerrexit = 0; + nohistsave = 0; + } +diff --git a/Src/zsh.h b/Src/zsh.h +index 5bda04e88..c0750cf45 100644 +--- a/Src/zsh.h ++++ b/Src/zsh.h +@@ -2215,6 +2215,14 @@ enum source_return { + SOURCE_ERROR = 2 + }; + ++enum exec_wrapper_origin { ++ EXEC_WRAPPER_ORIGIN_USER_COMMAND = 0, ++ EXEC_WRAPPER_ORIGIN_LOGIN_STARTUP = 1, ++ EXEC_WRAPPER_ORIGIN_RC_STARTUP = 2 ++}; ++ ++extern int zsh_exec_wrapper_origin; ++ + enum noerrexit_bits { + /* Suppress ERR_EXIT and traps: global */ + NOERREXIT_EXIT = 1,