1616# USAGE:
1717# ./scripts/tmux/tmux-send.sh SESSION_NAME "your text here"
1818# ./scripts/tmux/tmux-send.sh SESSION_NAME --key KEY
19+ # ./scripts/tmux/tmux-send.sh SESSION_NAME --paste
1920#
2021# ARGUMENTS:
2122# SESSION_NAME Name of the tmux session
2425# OPTIONS:
2526# --key KEY Send a special key instead of text
2627# Supported: Enter, Escape, Up, Down, Left, Right,
27- # C-c, C-u, C-d, Tab
28+ # C-c, C-u, C-d, C-v, Tab
29+ # --paste Paste current clipboard content using bracketed paste
30+ # mode. This triggers the CLI's paste handler correctly,
31+ # unlike --key C-v which just sends the raw keystroke.
32+ # By default, Enter is pressed after pasting. Use with
33+ # --no-enter to paste without submitting (useful for
34+ # testing attachment UI before sending).
2835# --no-enter Don't automatically press Enter after text
36+ # --retry N Retry session detection N times (default: 3)
2937# --help Show this help message
3038#
3139# EXAMPLES:
4149# # Send Ctrl+C to interrupt
4250# ./scripts/tmux/tmux-send.sh cli-test-123 --key C-c
4351#
52+ # # Paste clipboard content and submit immediately
53+ # ./scripts/tmux/tmux-send.sh cli-test-123 --paste
54+ #
55+ # # Paste clipboard content but don't submit (view attachment card first)
56+ # ./scripts/tmux/tmux-send.sh cli-test-123 --paste --no-enter
57+ #
4458# WHY BRACKETED PASTE?
4559# The Codebuff CLI uses OpenTUI for rendering, which processes keyboard
4660# input character-by-character. When tmux sends characters rapidly,
@@ -62,6 +76,9 @@ PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
6276# Defaults
6377AUTO_ENTER=true
6478SPECIAL_KEY=" "
79+ PASTE_CLIPBOARD=false
80+ RETRY_COUNT=3
81+ RETRY_DELAY=0.3
6582
6683# Check minimum arguments
6784if [[ $# -lt 1 ]]; then
@@ -89,10 +106,18 @@ while [[ $# -gt 0 ]]; do
89106 SPECIAL_KEY=" $2 "
90107 shift 2
91108 ;;
109+ --paste)
110+ PASTE_CLIPBOARD=true
111+ shift
112+ ;;
92113 --no-enter)
93114 AUTO_ENTER=false
94115 shift
95116 ;;
117+ --retry)
118+ RETRY_COUNT=" $2 "
119+ shift 2
120+ ;;
96121 --help)
97122 head -n 55 " $0 " | tail -n +2 | sed ' s/^# //' | sed ' s/^#//'
98123 exit 0
@@ -104,9 +129,21 @@ while [[ $# -gt 0 ]]; do
104129 esac
105130done
106131
107- # Verify session exists
108- if ! tmux has-session -t " $SESSION_NAME " 2> /dev/null; then
109- echo " ❌ Session '$SESSION_NAME ' not found" >&2
132+ # Verify session exists with retry logic
133+ # Sometimes sessions take a moment to be fully registered
134+ SESSION_FOUND=false
135+ for (( i= 1 ; i<= RETRY_COUNT; i++ )) ; do
136+ if tmux has-session -t " $SESSION_NAME " 2> /dev/null; then
137+ SESSION_FOUND=true
138+ break
139+ fi
140+ if [[ $i -lt $RETRY_COUNT ]]; then
141+ sleep " $RETRY_DELAY "
142+ fi
143+ done
144+
145+ if [[ " $SESSION_FOUND " != true ]]; then
146+ echo " ❌ Session '$SESSION_NAME ' not found after $RETRY_COUNT attempts" >&2
110147 echo " Run: tmux list-sessions" >&2
111148 exit 1
112149fi
130167 exit 0
131168fi
132169
170+ # Paste clipboard content if --paste flag is set
171+ if [[ " $PASTE_CLIPBOARD " == true ]]; then
172+ # Get clipboard content using pbpaste (macOS) or xclip (Linux)
173+ if command -v pbpaste & > /dev/null; then
174+ CLIPBOARD_CONTENT=$( pbpaste)
175+ elif command -v xclip & > /dev/null; then
176+ CLIPBOARD_CONTENT=$( xclip -selection clipboard -o)
177+ elif command -v xsel & > /dev/null; then
178+ CLIPBOARD_CONTENT=$( xsel --clipboard --output)
179+ else
180+ echo " ❌ No clipboard utility found (pbpaste, xclip, or xsel)" >&2
181+ exit 1
182+ fi
183+
184+ if [[ -z " $CLIPBOARD_CONTENT " ]]; then
185+ echo " ❌ Clipboard is empty" >&2
186+ exit 1
187+ fi
188+
189+ # Send clipboard content using bracketed paste mode
190+ tmux send-keys -t " $SESSION_NAME " $' \e [200~' " $CLIPBOARD_CONTENT " $' \e [201~'
191+
192+ # Optionally press Enter
193+ if [[ " $AUTO_ENTER " == true ]]; then
194+ tmux send-keys -t " $SESSION_NAME " Enter
195+ fi
196+
197+ # Log the paste as YAML
198+ SESSION_DIR=" $PROJECT_ROOT /debug/tmux-sessions/$SESSION_NAME "
199+ if [[ -d " $SESSION_DIR " ]]; then
200+ TIMESTAMP=$( date -u +%Y-%m-%dT%H:%M:%SZ)
201+ CONTENT_LENGTH=${# CLIPBOARD_CONTENT}
202+ cat >> " $SESSION_DIR /commands.yaml" << EOF
203+ - timestamp: $TIMESTAMP
204+ type: paste
205+ content_length: $CONTENT_LENGTH
206+ auto_enter: $AUTO_ENTER
207+ EOF
208+ fi
209+
210+ exit 0
211+ fi
212+
133213# Check if text was provided
134214if [[ -z " $TEXT " ]]; then
135215 echo " ❌ No text or --key specified" >&2
0 commit comments