Fix sidebar branch refresh during agent-driven git checkout (#671)
This commit is contained in:
parent
80baae355a
commit
39a0da2b7e
2 changed files with 86 additions and 10 deletions
|
|
@ -46,6 +46,7 @@ typeset -g _CMUX_GIT_FORCE=0
|
|||
typeset -g _CMUX_GIT_HEAD_LAST_PWD=""
|
||||
typeset -g _CMUX_GIT_HEAD_PATH=""
|
||||
typeset -g _CMUX_GIT_HEAD_MTIME=0
|
||||
typeset -g _CMUX_GIT_HEAD_WATCH_PID=""
|
||||
typeset -g _CMUX_HAVE_ZSTAT=0
|
||||
typeset -g _CMUX_PR_LAST_PWD=""
|
||||
typeset -g _CMUX_PR_LAST_RUN=0
|
||||
|
|
@ -148,6 +149,65 @@ _cmux_ports_kick() {
|
|||
} >/dev/null 2>&1 &!
|
||||
}
|
||||
|
||||
_cmux_report_git_branch_for_path() {
|
||||
local repo_path="$1"
|
||||
[[ -n "$repo_path" ]] || return 0
|
||||
[[ -S "$CMUX_SOCKET_PATH" ]] || return 0
|
||||
[[ -n "$CMUX_TAB_ID" ]] || return 0
|
||||
[[ -n "$CMUX_PANEL_ID" ]] || return 0
|
||||
|
||||
local branch dirty_opt="" first
|
||||
branch="$(git -C "$repo_path" branch --show-current 2>/dev/null)"
|
||||
if [[ -n "$branch" ]]; then
|
||||
first="$(git -C "$repo_path" status --porcelain -uno 2>/dev/null | head -1)"
|
||||
[[ -n "$first" ]] && dirty_opt="--status=dirty"
|
||||
_cmux_send "report_git_branch $branch $dirty_opt --tab=$CMUX_TAB_ID --panel=$CMUX_PANEL_ID"
|
||||
else
|
||||
_cmux_send "clear_git_branch --tab=$CMUX_TAB_ID --panel=$CMUX_PANEL_ID"
|
||||
fi
|
||||
}
|
||||
|
||||
_cmux_stop_git_head_watch() {
|
||||
if [[ -n "$_CMUX_GIT_HEAD_WATCH_PID" ]]; then
|
||||
kill "$_CMUX_GIT_HEAD_WATCH_PID" >/dev/null 2>&1 || true
|
||||
_CMUX_GIT_HEAD_WATCH_PID=""
|
||||
fi
|
||||
}
|
||||
|
||||
_cmux_start_git_head_watch() {
|
||||
[[ -S "$CMUX_SOCKET_PATH" ]] || return 0
|
||||
[[ -n "$CMUX_TAB_ID" ]] || return 0
|
||||
[[ -n "$CMUX_PANEL_ID" ]] || return 0
|
||||
|
||||
local watch_pwd="$PWD"
|
||||
local watch_head_path
|
||||
watch_head_path="$(_cmux_git_resolve_head_path 2>/dev/null || true)"
|
||||
[[ -n "$watch_head_path" ]] || return 0
|
||||
|
||||
local watch_head_mtime
|
||||
watch_head_mtime="$(_cmux_git_head_mtime "$watch_head_path" 2>/dev/null || echo 0)"
|
||||
|
||||
_CMUX_GIT_HEAD_LAST_PWD="$watch_pwd"
|
||||
_CMUX_GIT_HEAD_PATH="$watch_head_path"
|
||||
_CMUX_GIT_HEAD_MTIME="$watch_head_mtime"
|
||||
|
||||
_cmux_stop_git_head_watch
|
||||
{
|
||||
local last_mtime="$watch_head_mtime"
|
||||
while true; do
|
||||
sleep 1
|
||||
|
||||
local mtime
|
||||
mtime="$(_cmux_git_head_mtime "$watch_head_path" 2>/dev/null || echo 0)"
|
||||
if [[ -n "$mtime" && "$mtime" != 0 && "$mtime" != "$last_mtime" ]]; then
|
||||
last_mtime="$mtime"
|
||||
_cmux_report_git_branch_for_path "$watch_pwd"
|
||||
fi
|
||||
done
|
||||
} >/dev/null 2>&1 &!
|
||||
_CMUX_GIT_HEAD_WATCH_PID=$!
|
||||
}
|
||||
|
||||
_cmux_preexec() {
|
||||
if [[ -z "$_CMUX_TTY_NAME" ]]; then
|
||||
local t
|
||||
|
|
@ -169,9 +229,12 @@ _cmux_preexec() {
|
|||
# Register TTY + kick batched port scan for foreground commands (servers).
|
||||
_cmux_report_tty_once
|
||||
_cmux_ports_kick
|
||||
_cmux_start_git_head_watch
|
||||
}
|
||||
|
||||
_cmux_precmd() {
|
||||
_cmux_stop_git_head_watch
|
||||
|
||||
# Skip if socket doesn't exist yet
|
||||
[[ -S "$CMUX_SOCKET_PATH" ]] || return 0
|
||||
[[ -n "$CMUX_TAB_ID" ]] || return 0
|
||||
|
|
@ -227,6 +290,8 @@ _cmux_precmd() {
|
|||
fi
|
||||
|
||||
# Git branch/dirty: update immediately on directory change, otherwise every ~3s.
|
||||
# While a foreground command is running, _cmux_start_git_head_watch probes HEAD
|
||||
# once per second so agent-initiated git checkouts still surface quickly.
|
||||
local should_git=0
|
||||
|
||||
# Git branch can change without a `git ...`-prefixed command (aliases like `gco`,
|
||||
|
|
@ -280,16 +345,7 @@ _cmux_precmd() {
|
|||
_CMUX_GIT_LAST_PWD="$pwd"
|
||||
_CMUX_GIT_LAST_RUN=$now
|
||||
{
|
||||
local branch dirty_opt=""
|
||||
branch=$(git branch --show-current 2>/dev/null)
|
||||
if [[ -n "$branch" ]]; then
|
||||
local first
|
||||
first=$(git status --porcelain -uno 2>/dev/null | head -1)
|
||||
[[ -n "$first" ]] && dirty_opt="--status=dirty"
|
||||
_cmux_send "report_git_branch $branch $dirty_opt --tab=$CMUX_TAB_ID --panel=$CMUX_PANEL_ID"
|
||||
else
|
||||
_cmux_send "clear_git_branch --tab=$CMUX_TAB_ID --panel=$CMUX_PANEL_ID"
|
||||
fi
|
||||
_cmux_report_git_branch_for_path "$pwd"
|
||||
} >/dev/null 2>&1 &!
|
||||
_CMUX_GIT_JOB_PID=$!
|
||||
_CMUX_GIT_JOB_STARTED_AT=$now
|
||||
|
|
@ -387,7 +443,12 @@ _cmux_fix_path() {
|
|||
add-zsh-hook -d precmd _cmux_fix_path
|
||||
}
|
||||
|
||||
_cmux_zshexit() {
|
||||
_cmux_stop_git_head_watch
|
||||
}
|
||||
|
||||
autoload -Uz add-zsh-hook
|
||||
add-zsh-hook preexec _cmux_preexec
|
||||
add-zsh-hook precmd _cmux_precmd
|
||||
add-zsh-hook precmd _cmux_fix_path
|
||||
add-zsh-hook zshexit _cmux_zshexit
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ def _wait_for_git_branch(
|
|||
expected: str,
|
||||
timeout: float = 12.0,
|
||||
interval: float = 0.15,
|
||||
allow_force_fallback: bool = True,
|
||||
) -> dict[str, str]:
|
||||
def pred():
|
||||
state = _parse_sidebar_state(client.sidebar_state())
|
||||
|
|
@ -82,6 +83,8 @@ def _wait_for_git_branch(
|
|||
try:
|
||||
return _wait_for(pred, timeout=timeout, interval=interval, label=f"git_branch={expected!r}")
|
||||
except AssertionError as original_error:
|
||||
if not allow_force_fallback:
|
||||
raise original_error
|
||||
# VM shells can occasionally skip a prompt hook; force a one-shot report so
|
||||
# the remainder of the flow can still validate transition behavior.
|
||||
try:
|
||||
|
|
@ -180,6 +183,18 @@ def main() -> int:
|
|||
_send_cd_and_wait(client, repo)
|
||||
_wait_for_git_branch(client, "main")
|
||||
|
||||
# Branch changes during a long-running foreground command should still
|
||||
# propagate before the prompt returns (agent-style workflows).
|
||||
client.send("bash -lc 'git checkout -b feature/agent-live >/dev/null 2>&1; sleep 6'\n")
|
||||
_wait_for_git_branch(
|
||||
client,
|
||||
"feature/agent-live",
|
||||
timeout=3.5,
|
||||
interval=0.1,
|
||||
allow_force_fallback=False,
|
||||
)
|
||||
time.sleep(6.3)
|
||||
|
||||
# Branch change should update.
|
||||
# Cover alias/non-`git ...` command paths too (regression: branch could
|
||||
# stick for ~3s when switching via alias/tools like `gh pr checkout`).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue