framework tools/tmux: agent-send socket default resolution + ambiguity guard (B1) (#1466)
ci/woodpecker/push/publish Pipeline failed
ci/woodpecker/push/publish Pipeline failed
Co-authored-by: marcie <[email protected]>
This commit was merged in pull request #1466.
This commit is contained in:
@@ -35,6 +35,9 @@
|
||||
#
|
||||
# OPTIONS
|
||||
# -L NAME tmux socket name passed to `tmux -L NAME` on the target host
|
||||
#
|
||||
# Exit 4: local target session exists on multiple socket servers and no
|
||||
# -L / MOSAIC_TMUX_SOCKET disambiguated it (B1 stale-twin guard).
|
||||
# -s DST_SESSION target tmux session (or session:window.pane) [required]
|
||||
# -H SSH_TARGET ssh target (user@host) for a remote pane; omit for local
|
||||
# -n DST_HOST hostname to show in the preamble for the target.
|
||||
@@ -63,8 +66,10 @@
|
||||
# group 1 = src label group 2 = dst host:session
|
||||
# group 3 = class (absent => actionable) group 4 = message body
|
||||
#
|
||||
# EXIT CODES (passed through from send-message.sh)
|
||||
# EXIT CODES (passed through from send-message.sh, except 4)
|
||||
# 0 delivered/queued · 1 target not found · 2 still draft · 3 usage error
|
||||
# 4 agent-send refusal: local target session exists on multiple socket
|
||||
# servers and no -L / MOSAIC_TMUX_SOCKET disambiguated it (B1)
|
||||
set -uo pipefail
|
||||
|
||||
SELF_DIR=$(cd -- "$(dirname -- "$0")" && pwd)
|
||||
@@ -154,6 +159,61 @@ FULL="${PREAMBLE} ${MSG}"
|
||||
B64=$(printf '%s' "$FULL" | base64 -w0)
|
||||
|
||||
vflag=""; [ "$VERBOSE" = 1 ] && vflag="-v"
|
||||
|
||||
# Exact session matching for the sender target (codex PR #1466): without
|
||||
# '=', tmux target syntax accepts an unambiguous PREFIX, so a delivery
|
||||
# aimed at session X can land in X-old. Compound targets (session:win.pane)
|
||||
# and already-exact ('=...') forms pass through untouched. Computed BEFORE
|
||||
# socket discovery so the discovery probes use the same target semantics
|
||||
# (probing '==name' for an already-exact input was a false-negative hit).
|
||||
DST_TARGET="$DST_SESSION"
|
||||
case "$DST_SESSION" in
|
||||
=*) ;;
|
||||
*:*)
|
||||
# Compound target (session:win.pane): pin the SESSION component exact
|
||||
# (=session:win.pane); unpinned, the session part still prefix-matches
|
||||
# (codex PR #1466: 'agent:0.0' can resolve into 'agent-old').
|
||||
DST_TARGET="=${DST_SESSION%%:*}:${DST_SESSION#*:}"
|
||||
;;
|
||||
*) DST_TARGET="=$DST_SESSION" ;;
|
||||
esac
|
||||
|
||||
# Socket default resolution (B1, 2026-08-29). Precedence: explicit -L >
|
||||
# launcher-exported MOSAIC_TMUX_SOCKET > unique socket hit > refusal on
|
||||
# ambiguity > tmux default socket. The ambiguity refusal fires ONLY when
|
||||
# no explicit or env choice exists and the session name lives on multiple
|
||||
# servers (measured 2026-08-28/29: tasking sends landed in a stale
|
||||
# default-socket twin; rc 0 reported honest delivery to the wrong pane).
|
||||
# Socket discovery scans tmux's own socket dir, ${TMUX_TMPDIR:-/tmp}/tmux-UID
|
||||
# (codex PR #1466: TMPDIR is not where tmux keeps -L sockets).
|
||||
# MOSAIC_TMUX_SOCKET is LOCAL-host state (launcher-exported): it must not
|
||||
# leak into remote sends, where -L would target a socket on the remote
|
||||
# host (codex PR #1466).
|
||||
if [ -z "$SOCKET_NAME" ] && [ -z "$SSH_TARGET" ] && [ -n "${MOSAIC_TMUX_SOCKET:-}" ]; then
|
||||
SOCKET_NAME="$MOSAIC_TMUX_SOCKET"
|
||||
fi
|
||||
if [ -z "$SOCKET_NAME" ] && [ -z "$SSH_TARGET" ]; then
|
||||
socket_dir="${TMUX_TMPDIR:-/tmp}/tmux-$(id -u)"
|
||||
hits=""
|
||||
for sf in "$socket_dir"/*; do
|
||||
[ -S "$sf" ] || continue
|
||||
sname="${sf##*/}"
|
||||
# '=' forces exact session-name matching: tmux target syntax otherwise
|
||||
# accepts an unambiguous PREFIX, so a session named X-old on a socket
|
||||
# would count as a false hit for target X (codex PR #1466).
|
||||
tmux -L "$sname" has-session -t "$DST_TARGET" 2>/dev/null && hits="$hits$sname"$'\n'
|
||||
done
|
||||
hit_count=$(printf '%s' "$hits" | grep -c . || true)
|
||||
if [ "$hit_count" -gt 1 ]; then
|
||||
echo "agent-send.sh: REFUSING - session '$DST_SESSION' exists on multiple sockets:" >&2
|
||||
printf ' %s\n' $hits >&2
|
||||
echo " Pass -L <socket> explicitly (or export MOSAIC_TMUX_SOCKET to disambiguate)." >&2
|
||||
exit 4
|
||||
elif [ "$hit_count" -eq 1 ]; then
|
||||
SOCKET_NAME="$(printf '%s' "$hits")"
|
||||
fi
|
||||
fi
|
||||
|
||||
socket_args=()
|
||||
if [ -n "$SOCKET_NAME" ]; then
|
||||
socket_args=(-L "$SOCKET_NAME")
|
||||
@@ -161,9 +221,9 @@ fi
|
||||
|
||||
if [ -z "$SSH_TARGET" ]; then
|
||||
# Local pane: call the canonical sender directly.
|
||||
exec "$SENDER" "${socket_args[@]}" -t "$DST_SESSION" -b "$B64" -r "$RETRIES" $vflag
|
||||
exec "$SENDER" "${socket_args[@]}" -t "$DST_TARGET" -b "$B64" -r "$RETRIES" $vflag
|
||||
else
|
||||
# Remote pane: ship the sender over ssh and run it local to the target.
|
||||
ssh -o ConnectTimeout=10 "$SSH_TARGET" \
|
||||
"bash -s -- ${socket_args[*]@Q} -t '$DST_SESSION' -b '$B64' -r '$RETRIES' $vflag" < "$SENDER"
|
||||
"bash -s -- ${socket_args[*]@Q} -t '$DST_TARGET' -b '$B64' -r '$RETRIES' $vflag" < "$SENDER"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user