From 24e992246ddcdf4daf9fafc4e32dabe7e4cb31ef Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Tue, 10 Feb 2026 12:13:49 -0600 Subject: feat(aix): add windows to existing session, fix special char handling Allow calling aix from within the ai tmux session to add new project windows. Already-open projects are filtered from the selection list. Use tmux window IDs instead of names to fix errors with dots in directory names (e.g. chime.el). --- dotfiles/common/.local/bin/aix | 109 ++++++++++++++++++++++++++++------------- 1 file changed, 76 insertions(+), 33 deletions(-) (limited to 'dotfiles') diff --git a/dotfiles/common/.local/bin/aix b/dotfiles/common/.local/bin/aix index 35cab64..9f689eb 100755 --- a/dotfiles/common/.local/bin/aix +++ b/dotfiles/common/.local/bin/aix @@ -3,16 +3,6 @@ SESSION="ai" -# If session exists, attach or switch to it -if tmux has-session -t "$SESSION" 2>/dev/null; then - if [ -n "$TMUX" ]; then - tmux switch-client -t "$SESSION" - else - tmux attach-session -t "$SESSION" - fi - exit 0 -fi - # Dependency checks for cmd in fzf tmux claude; do if ! command -v "$cmd" &>/dev/null; then @@ -21,29 +11,82 @@ for cmd in fzf tmux claude; do fi done +# Claude command — separated for safe editing +AI_CMD="claude" +AI_INSTRUCTIONS='Read docs/protocols.org and follow all instructions.' + # Build candidate directory list -candidates=() -[ -d "$HOME/.emacs.d" ] && candidates+=("~/.emacs.d") -if [ -d "$HOME/code" ]; then - while IFS= read -r d; do - candidates+=("~/${d#"$HOME"/}") - done < <(find "$HOME/code" -maxdepth 1 -mindepth 1 -type d | sort) -fi -if [ -d "$HOME/projects" ]; then - while IFS= read -r d; do - candidates+=("~/${d#"$HOME"/}") - done < <(find "$HOME/projects" -maxdepth 1 -mindepth 1 -type d | sort) +build_candidates() { + candidates=() + [ -d "$HOME/.emacs.d" ] && candidates+=("~/.emacs.d") + if [ -d "$HOME/code" ]; then + while IFS= read -r d; do + candidates+=("~/${d#"$HOME"/}") + done < <(find "$HOME/code" -maxdepth 1 -mindepth 1 -type d | sort) + fi + if [ -d "$HOME/projects" ]; then + while IFS= read -r d; do + candidates+=("~/${d#"$HOME"/}") + done < <(find "$HOME/projects" -maxdepth 1 -mindepth 1 -type d | sort) + fi +} + +# If session exists, add new windows to it +if tmux has-session -t "$SESSION" 2>/dev/null; then + # Get existing window names to filter duplicates + existing=$(tmux list-windows -t "$SESSION" -F '#{window_name}') + + build_candidates + + # Filter out candidates that already have a window open + filtered=() + for c in "${candidates[@]}"; do + name="$(basename "${c/#\~/$HOME}")" + if ! echo "$existing" | grep -qxF "$name"; then + filtered+=("$c") + fi + done + + if [ ${#filtered[@]} -eq 0 ]; then + echo "All projects already have windows open." + else + selections=$(printf '%s\n' "${filtered[@]}" | fzf --multi --height=70% --reverse) + + if [ -n "$selections" ]; then + selected=() + while IFS= read -r line; do + selected+=("$line") + done <<<"$selections" + + first_wid="" + for entry in "${selected[@]}"; do + dir="${entry/#\~/$HOME}" + name="$(basename "$dir")" + wid=$(tmux new-window -t "$SESSION" -n "$name" -c "$dir" -P -F '#{window_id}') + sleep 0.1 + tmux send-keys -t "$wid" "$AI_CMD \"$AI_INSTRUCTIONS\"" Enter + [ -z "$first_wid" ] && first_wid="$wid" + done + + tmux select-window -t "$first_wid" + fi + fi + + # Attach or switch to session + if [ -n "$TMUX" ]; then + tmux switch-client -t "$SESSION" + else + tmux attach-session -t "$SESSION" + fi + exit 0 fi -# Present fzf for multi-select +# New session: select projects and create session +build_candidates + selections=$(printf '%s\n' "${candidates[@]}" | fzf --multi --height=70% --reverse) [ -z "$selections" ] && exit 0 -# Claude command — separated for safe editing -AI_CMD="claude" -AI_INSTRUCTIONS='Read docs/protocols.org and follow all instructions.' - -# Read selections into array selected=() while IFS= read -r line; do selected+=("$line") @@ -53,20 +96,20 @@ done <<<"$selections" first="${selected[0]}" dir="${first/#\~/$HOME}" name="$(basename "$dir")" -tmux new-session -d -s "$SESSION" -n "$name" -c "$dir" -tmux send-keys -t "$SESSION:$name" "$AI_CMD \"$AI_INSTRUCTIONS\"" Enter +tmux new-session -d -s "$SESSION" -n "$name" -c "$dir" -P -F '#{window_id}' > /dev/null +first_wid=$(tmux list-windows -t "$SESSION" -F '#{window_id}' | head -1) +tmux send-keys -t "$first_wid" "$AI_CMD \"$AI_INSTRUCTIONS\"" Enter # Create remaining windows for entry in "${selected[@]:1}"; do dir="${entry/#\~/$HOME}" name="$(basename "$dir")" - tmux new-window -t "$SESSION" -n "$name" -c "$dir" - tmux send-keys -t "$SESSION:$name" "$AI_CMD \"$AI_INSTRUCTIONS\"" Enter + wid=$(tmux new-window -t "$SESSION" -n "$name" -c "$dir" -P -F '#{window_id}') + tmux send-keys -t "$wid" "$AI_CMD \"$AI_INSTRUCTIONS\"" Enter done # Select first window and attach or switch -first_name="$(basename "${selected[0]/#\~/$HOME}")" -tmux select-window -t "$SESSION:$first_name" +tmux select-window -t "$first_wid" if [ -n "$TMUX" ]; then tmux switch-client -t "$SESSION" else -- cgit v1.2.3