flake-update-20260201
  1{ pkgs }:
  2
  3let
  4  # Helper script to run a command in a specific directory with proper environment
  5  # Usage: run-in-dir <command> <directory> [model]
  6  # If model is provided, adds --model <model> to the command
  7  run-in-dir = pkgs.writeShellScript "run-in-dir" ''
  8    CMD="''${1:-}"
  9    DIR="''${2:-}"
 10    MODEL="''${3:-}"
 11
 12    # Set TERM for proper color support
 13    export TERM=xterm-256color
 14
 15    # Command is required
 16    if [ -z "$CMD" ]; then
 17      echo "Error: command argument is required" >&2
 18      exit 1
 19    fi
 20
 21    # Directory is required
 22    if [ -z "$DIR" ]; then
 23      echo "Error: directory argument is required" >&2
 24      exit 1
 25    fi
 26
 27    # Check if directory exists
 28    if [ ! -d "$DIR" ]; then
 29      echo "Error: directory does not exist: $DIR" >&2
 30      exit 1
 31    fi
 32
 33    # Change to specified directory
 34    cd "$DIR"
 35
 36    # Build command with optional model flag
 37    if [ -n "$MODEL" ]; then
 38      FULL_CMD="$CMD --model $MODEL"
 39    else
 40      FULL_CMD="$CMD"
 41    fi
 42
 43    # Execute through zsh with proper environment
 44    # zshenv sets up PATH and other environment variables
 45    exec ${pkgs.zsh}/bin/zsh -c "source ~/.zshenv; exec $FULL_CMD"
 46  '';
 47
 48in
 49
 50pkgs.writeScriptBin "shpool-ssh-wrapper" ''
 51  #!${pkgs.bash}/bin/bash
 52  # Shpool SSH wrapper - automatically runs commands for specific session patterns
 53  #
 54  # Syntax: session-name=directory (e.g., "claude/home=src/home")
 55  #
 56  # Supported session patterns:
 57  #   claude/*        - Claude Code with Vertex AI (cr command)
 58  #   copilot/*       - GitHub Copilot CLI
 59  #   opencode/*      - OpenCode CLI
 60  #   oco/*           - OpenCode with Vertex AI
 61  #   review-<tool>/* - Review sessions with specified tool (cr, copilot, opencode, oco)
 62  #
 63  # Model selection (optional):
 64  #   claude:opus/home      - Use opus model
 65  #   oco:sonnet/project    - Use sonnet model
 66  #
 67  # Examples:
 68  #   ssh host/claude/home                    # Claude in ~/src/home
 69  #   ssh host/claude:opus/home               # Claude with opus in ~/src/home
 70  #   ssh host/review-copilot/pr-123="prompt" # Review with copilot
 71
 72  set -euo pipefail
 73
 74  # Parse session spec: "claude/home=src/home" -> session="claude/home", dir="src/home"
 75  SESSION_SPEC="''${1}"
 76  if [[ "$SESSION_SPEC" =~ ^([^=]+)=(.+)$ ]]; then
 77      SESSION_NAME="''${BASH_REMATCH[1]}"
 78      WORK_DIR="''${BASH_REMATCH[2]}"
 79  else
 80      SESSION_NAME="$SESSION_SPEC"
 81      WORK_DIR=""
 82  fi
 83
 84  # Function to run shpool with a specific command
 85  run_with_command() {
 86      local session="$1"
 87      local cmd="$2"
 88      shift 2
 89      exec ${pkgs.shpool}/bin/shpool attach -f -c "$cmd $*" "$session"
 90  }
 91
 92  # Function to parse tool:model from prefix
 93  # e.g., "claude:opus" -> TOOL=claude, MODEL=opus
 94  #       "claude" -> TOOL=claude, MODEL=""
 95  parse_tool_model() {
 96      local prefix="$1"
 97      if [[ "$prefix" =~ ^([^:]+):(.+)$ ]]; then
 98          TOOL="''${BASH_REMATCH[1]}"
 99          MODEL="''${BASH_REMATCH[2]}"
100      else
101          TOOL="$prefix"
102          MODEL=""
103      fi
104  }
105
106  # Function to get default directory from session suffix
107  # e.g., "claude/home" -> "src/home", "claude:opus/home" -> "src/home"
108  get_default_dir() {
109      local session="$1"
110      local prefix="$2"
111      # Remove prefix (which may include :model)
112      local suffix="''${session#$prefix/}"
113      echo "src/$suffix"
114  }
115
116  # Function to run an AI tool session
117  # Args: session_name, tool_prefix, tool_command
118  run_ai_session() {
119      local session="$1"
120      local prefix_pattern="$2"
121      local default_cmd="$3"
122
123      # Extract the prefix part (before first /)
124      local prefix="''${session%%/*}"
125
126      # Parse tool:model from prefix
127      parse_tool_model "$prefix"
128
129      # Use default command if TOOL matches expected pattern
130      local cmd="$default_cmd"
131
132      # Get work directory
133      if [ -z "$WORK_DIR" ]; then
134          WORK_DIR=$(get_default_dir "$session" "$prefix")
135      fi
136
137      run_with_command "$session" "${run-in-dir}" "$cmd" "$WORK_DIR" "$MODEL"
138  }
139
140  # Check session name patterns and run appropriate commands
141  case "$SESSION_NAME" in
142      claude:*/*)
143          # Claude Code with model selection
144          run_ai_session "$SESSION_NAME" "claude" "cr"
145          ;;
146      claude/*)
147          # Claude Code session - run with Vertex AI environment via cr
148          run_ai_session "$SESSION_NAME" "claude" "cr"
149          ;;
150      copilot:*/*)
151          # GitHub Copilot CLI with model selection
152          run_ai_session "$SESSION_NAME" "copilot" "copilot"
153          ;;
154      copilot/*)
155          # GitHub Copilot CLI session
156          run_ai_session "$SESSION_NAME" "copilot" "copilot"
157          ;;
158      opencode:*/*)
159          # OpenCode CLI with model selection
160          run_ai_session "$SESSION_NAME" "opencode" "opencode"
161          ;;
162      opencode/*)
163          # OpenCode CLI session
164          run_ai_session "$SESSION_NAME" "opencode" "opencode"
165          ;;
166      oco:*/*)
167          # OpenCode with Vertex AI and model selection
168          run_ai_session "$SESSION_NAME" "oco" "oco"
169          ;;
170      oco/*)
171          # OpenCode with Vertex AI session
172          run_ai_session "$SESSION_NAME" "oco" "oco"
173          ;;
174      review-cr/*|review-claude/*)
175          # Review with Claude Code (cr)
176          if [ -z "$WORK_DIR" ]; then
177              if ${pkgs.shpool}/bin/shpool list 2>/dev/null | grep -q "^$SESSION_NAME "; then
178                  exec ${pkgs.shpool}/bin/shpool attach -f "$SESSION_NAME"
179              else
180                  echo "Error: new review sessions require a prompt (use session=prompt syntax)" >&2
181                  echo "Example: ssh host/review-cr/pr-123=\"Review https://github.com/...\"" >&2
182                  exit 1
183              fi
184          fi
185          run_with_command "$SESSION_NAME" "cr" "$WORK_DIR"
186          ;;
187      review-copilot/*)
188          # Review with GitHub Copilot
189          if [ -z "$WORK_DIR" ]; then
190              if ${pkgs.shpool}/bin/shpool list 2>/dev/null | grep -q "^$SESSION_NAME "; then
191                  exec ${pkgs.shpool}/bin/shpool attach -f "$SESSION_NAME"
192              else
193                  echo "Error: new review sessions require a prompt (use session=prompt syntax)" >&2
194                  echo "Example: ssh host/review-copilot/pr-123=\"Review https://github.com/...\"" >&2
195                  exit 1
196              fi
197          fi
198          run_with_command "$SESSION_NAME" "copilot" "$WORK_DIR"
199          ;;
200      review-opencode/*)
201          # Review with OpenCode
202          if [ -z "$WORK_DIR" ]; then
203              if ${pkgs.shpool}/bin/shpool list 2>/dev/null | grep -q "^$SESSION_NAME "; then
204                  exec ${pkgs.shpool}/bin/shpool attach -f "$SESSION_NAME"
205              else
206                  echo "Error: new review sessions require a prompt (use session=prompt syntax)" >&2
207                  echo "Example: ssh host/review-opencode/pr-123=\"Review https://github.com/...\"" >&2
208                  exit 1
209              fi
210          fi
211          run_with_command "$SESSION_NAME" "opencode" "$WORK_DIR"
212          ;;
213      review-oco/*)
214          # Review with OpenCode Vertex
215          if [ -z "$WORK_DIR" ]; then
216              if ${pkgs.shpool}/bin/shpool list 2>/dev/null | grep -q "^$SESSION_NAME "; then
217                  exec ${pkgs.shpool}/bin/shpool attach -f "$SESSION_NAME"
218              else
219                  echo "Error: new review sessions require a prompt (use session=prompt syntax)" >&2
220                  echo "Example: ssh host/review-oco/pr-123=\"Review https://github.com/...\"" >&2
221                  exit 1
222              fi
223          fi
224          run_with_command "$SESSION_NAME" "oco" "$WORK_DIR"
225          ;;
226      *)
227          # If work directory specified, cd into it before attaching
228          if [ -n "$WORK_DIR" ]; then
229              # Start shell and cd into directory
230              exec ${pkgs.shpool}/bin/shpool attach -f -c "${pkgs.zsh}/bin/zsh -c 'cd $WORK_DIR && exec ${pkgs.zsh}/bin/zsh'" "$SESSION_NAME"
231          else
232              # Default: just attach to session with default shell
233              exec ${pkgs.shpool}/bin/shpool attach -f "$SESSION_NAME"
234          fi
235          ;;
236  esac
237''