Sync CMUX environment through tmux automatically

This commit is contained in:
Lawrence Chen 2026-03-21 02:22:59 -07:00
parent c325e2b49d
commit 5e9a58d1d0
No known key found for this signature in database
2 changed files with 217 additions and 0 deletions

View file

@ -54,6 +54,111 @@ _CMUX_PORTS_LAST_RUN="${_CMUX_PORTS_LAST_RUN:-0}"
_CMUX_SHELL_ACTIVITY_LAST="${_CMUX_SHELL_ACTIVITY_LAST:-}"
_CMUX_TTY_NAME="${_CMUX_TTY_NAME:-}"
_CMUX_TTY_REPORTED="${_CMUX_TTY_REPORTED:-0}"
_CMUX_TMUX_PUSH_SIGNATURE="${_CMUX_TMUX_PUSH_SIGNATURE:-}"
_CMUX_TMUX_PULL_SIGNATURE="${_CMUX_TMUX_PULL_SIGNATURE:-}"
_CMUX_TMUX_SYNC_KEYS=(
CMUX_BUNDLED_CLI_PATH
CMUX_BUNDLE_ID
CMUXD_UNIX_PATH
CMUXTERM_REPO_ROOT
CMUX_DEBUG_LOG
CMUX_LOAD_GHOSTTY_ZSH_INTEGRATION
CMUX_PANEL_ID
CMUX_PORT
CMUX_PORT_END
CMUX_PORT_RANGE
CMUX_REMOTE_DAEMON_ALLOW_LOCAL_BUILD
CMUX_SHELL_INTEGRATION
CMUX_SHELL_INTEGRATION_DIR
CMUX_SOCKET_ENABLE
CMUX_SOCKET_MODE
CMUX_SOCKET_PATH
CMUX_SURFACE_ID
CMUX_TAB_ID
CMUX_TAG
CMUX_WORKSPACE_ID
)
_cmux_tmux_shell_env_signature() {
local key value first=1
for key in "${_CMUX_TMUX_SYNC_KEYS[@]}"; do
value="${!key}"
[[ -n "$value" ]] || continue
if (( first )); then
printf '%s=%s' "$key" "$value"
first=0
else
printf '\037%s=%s' "$key" "$value"
fi
done
}
_cmux_tmux_publish_cmux_environment() {
[[ -z "$TMUX" ]] || return 0
command -v tmux >/dev/null 2>&1 || return 0
local signature
signature="$(_cmux_tmux_shell_env_signature)"
[[ -n "$signature" ]] || return 0
[[ "$signature" == "$_CMUX_TMUX_PUSH_SIGNATURE" ]] && return 0
local key value
for key in "${_CMUX_TMUX_SYNC_KEYS[@]}"; do
value="${!key}"
[[ -n "$value" ]] || continue
tmux set-environment -g "$key" "$value" >/dev/null 2>&1 || return 0
done
_CMUX_TMUX_PUSH_SIGNATURE="$signature"
}
_cmux_tmux_refresh_cmux_environment() {
[[ -n "$TMUX" ]] || return 0
command -v tmux >/dev/null 2>&1 || return 0
local output filtered line key value did_change=0
output="$(tmux show-environment -g 2>/dev/null)" || return 0
while IFS= read -r line; do
[[ "$line" == CMUX_* ]] || continue
filtered+="${line}"$'\n'
done <<< "$output"
[[ -n "$filtered" ]] || return 0
[[ "$filtered" == "$_CMUX_TMUX_PULL_SIGNATURE" ]] && return 0
while IFS= read -r line; do
[[ "$line" == CMUX_* ]] || continue
key="${line%%=*}"
value="${line#*=}"
if [[ "${!key}" != "$value" ]]; then
printf -v "$key" '%s' "$value"
export "$key"
did_change=1
fi
done <<< "$filtered"
_CMUX_TMUX_PULL_SIGNATURE="$filtered"
if (( did_change )); then
_CMUX_TTY_REPORTED=0
_CMUX_SHELL_ACTIVITY_LAST=""
_CMUX_PWD_LAST_PWD=""
_CMUX_GIT_LAST_PWD=""
_CMUX_GIT_HEAD_LAST_PWD=""
_CMUX_GIT_HEAD_PATH=""
_CMUX_GIT_HEAD_SIGNATURE=""
_CMUX_PR_FORCE=1
_cmux_stop_pr_poll_loop
fi
}
_cmux_tmux_sync_cmux_environment() {
if [[ -n "$TMUX" ]]; then
_cmux_tmux_refresh_cmux_environment
else
_cmux_tmux_publish_cmux_environment
fi
}
_cmux_git_resolve_head_path() {
# Resolve the HEAD file path without invoking git (fast; works for worktrees).
@ -348,6 +453,8 @@ _cmux_bash_cleanup() {
}
_cmux_preexec_command() {
_cmux_tmux_sync_cmux_environment
[[ -S "$CMUX_SOCKET_PATH" ]] || return 0
[[ -n "$CMUX_TAB_ID" ]] || return 0
[[ -n "$CMUX_PANEL_ID" ]] || return 0
@ -370,6 +477,8 @@ _cmux_bash_preexec_hook() {
}
_cmux_prompt_command() {
_cmux_tmux_sync_cmux_environment
[[ -S "$CMUX_SOCKET_PATH" ]] || return 0
[[ -n "$CMUX_TAB_ID" ]] || return 0
[[ -n "$CMUX_PANEL_ID" ]] || return 0

View file

@ -60,6 +60,111 @@ typeset -g _CMUX_TTY_NAME=""
typeset -g _CMUX_TTY_REPORTED=0
typeset -g _CMUX_GHOSTTY_SEMANTIC_PATCHED=0
typeset -g _CMUX_WINCH_GUARD_INSTALLED=0
typeset -g _CMUX_TMUX_PUSH_SIGNATURE=""
typeset -g _CMUX_TMUX_PULL_SIGNATURE=""
typeset -ga _CMUX_TMUX_SYNC_KEYS=(
CMUX_BUNDLED_CLI_PATH
CMUX_BUNDLE_ID
CMUXD_UNIX_PATH
CMUXTERM_REPO_ROOT
CMUX_DEBUG_LOG
CMUX_LOAD_GHOSTTY_ZSH_INTEGRATION
CMUX_PANEL_ID
CMUX_PORT
CMUX_PORT_END
CMUX_PORT_RANGE
CMUX_REMOTE_DAEMON_ALLOW_LOCAL_BUILD
CMUX_SHELL_INTEGRATION
CMUX_SHELL_INTEGRATION_DIR
CMUX_SOCKET_ENABLE
CMUX_SOCKET_MODE
CMUX_SOCKET_PATH
CMUX_SURFACE_ID
CMUX_TAB_ID
CMUX_TAG
CMUX_WORKSPACE_ID
)
_cmux_tmux_shell_env_signature() {
local key value
local -a parts
for key in "${_CMUX_TMUX_SYNC_KEYS[@]}"; do
value="${(P)key}"
[[ -n "$value" ]] || continue
parts+=("${key}=${value}")
done
print -r -- "${(j:\x1f:)parts}"
}
_cmux_tmux_publish_cmux_environment() {
[[ -z "$TMUX" ]] || return 0
command -v tmux >/dev/null 2>&1 || return 0
local signature
signature="$(_cmux_tmux_shell_env_signature)"
[[ -n "$signature" ]] || return 0
[[ "$signature" == "$_CMUX_TMUX_PUSH_SIGNATURE" ]] && return 0
local key value
for key in "${_CMUX_TMUX_SYNC_KEYS[@]}"; do
value="${(P)key}"
[[ -n "$value" ]] || continue
tmux set-environment -g "$key" "$value" >/dev/null 2>&1 || return 0
done
_CMUX_TMUX_PUSH_SIGNATURE="$signature"
}
_cmux_tmux_refresh_cmux_environment() {
[[ -n "$TMUX" ]] || return 0
command -v tmux >/dev/null 2>&1 || return 0
local output
output="$(tmux show-environment -g 2>/dev/null)" || return 0
local line filtered="" did_change=0
while IFS= read -r line; do
[[ "$line" == CMUX_* ]] || continue
filtered+="${line}"$'\n'
done <<< "$output"
[[ -n "$filtered" ]] || return 0
[[ "$filtered" == "$_CMUX_TMUX_PULL_SIGNATURE" ]] && return 0
local key value
while IFS= read -r line; do
[[ "$line" == CMUX_* ]] || continue
key="${line%%=*}"
value="${line#*=}"
if [[ "${(P)key}" != "$value" ]]; then
export "$key=$value"
did_change=1
fi
done <<< "$filtered"
_CMUX_TMUX_PULL_SIGNATURE="$filtered"
if (( did_change )); then
_CMUX_TTY_REPORTED=0
_CMUX_SHELL_ACTIVITY_LAST=""
_CMUX_PWD_LAST_PWD=""
_CMUX_GIT_LAST_PWD=""
_CMUX_GIT_HEAD_LAST_PWD=""
_CMUX_GIT_HEAD_PATH=""
_CMUX_GIT_HEAD_SIGNATURE=""
_CMUX_GIT_FORCE=1
_CMUX_PR_FORCE=1
_cmux_stop_pr_poll_loop
_cmux_stop_git_head_watch
fi
}
_cmux_tmux_sync_cmux_environment() {
if [[ -n "$TMUX" ]]; then
_cmux_tmux_refresh_cmux_environment
else
_cmux_tmux_publish_cmux_environment
fi
}
_cmux_ensure_ghostty_preexec_strips_both_marks() {
local fn_name="$1"
@ -506,6 +611,8 @@ _cmux_start_git_head_watch() {
}
_cmux_preexec() {
_cmux_tmux_sync_cmux_environment
if [[ -z "$_CMUX_TTY_NAME" ]]; then
local t
t="$(tty 2>/dev/null || true)"
@ -533,6 +640,7 @@ _cmux_preexec() {
_cmux_precmd() {
_cmux_stop_git_head_watch
_cmux_tmux_sync_cmux_environment
# Skip if socket doesn't exist yet
[[ -S "$CMUX_SOCKET_PATH" ]] || return 0