Commit 6e5008e2ba53
Changed files (1)
tools
shpool-ssh-wrapper
tools/shpool-ssh-wrapper/default.nix
@@ -1,33 +1,48 @@
{ pkgs }:
let
- # Helper script to start Claude Code with Vertex AI environment
- # Takes required directory argument: claude-vertex <directory>
- claude-vertex = pkgs.writeShellScript "claude-vertex" ''
- export CLAUDE_CODE_USE_VERTEX=1
- export CLOUD_ML_REGION=us-east5
- export ANTHROPIC_VERTEX_PROJECT_ID=itpc-gcp-pnd-pe-eng-claude
+ # Helper script to run a command in a specific directory with proper environment
+ # Usage: run-in-dir <command> <directory> [model]
+ # If model is provided, adds --model <model> to the command
+ run-in-dir = pkgs.writeShellScript "run-in-dir" ''
+ CMD="''${1:-}"
+ DIR="''${2:-}"
+ MODEL="''${3:-}"
+
# Set TERM for proper color support
export TERM=xterm-256color
+ # Command is required
+ if [ -z "$CMD" ]; then
+ echo "Error: command argument is required" >&2
+ exit 1
+ fi
+
# Directory is required
- if [ -z "''${1:-}" ]; then
+ if [ -z "$DIR" ]; then
echo "Error: directory argument is required" >&2
exit 1
fi
# Check if directory exists
- if [ ! -d "$1" ]; then
- echo "Error: directory does not exist: $1" >&2
+ if [ ! -d "$DIR" ]; then
+ echo "Error: directory does not exist: $DIR" >&2
exit 1
fi
# Change to specified directory
- cd "$1"
+ cd "$DIR"
+
+ # Build command with optional model flag
+ if [ -n "$MODEL" ]; then
+ FULL_CMD="$CMD --model $MODEL"
+ else
+ FULL_CMD="$CMD"
+ fi
# Execute through zsh with proper environment
# zshenv sets up PATH and other environment variables
- exec ${pkgs.zsh}/bin/zsh -c "source ~/.zshenv; exec /etc/profiles/per-user/vincent/bin/claude"
+ exec ${pkgs.zsh}/bin/zsh -c "source ~/.zshenv; exec $FULL_CMD"
'';
in
@@ -35,7 +50,24 @@ in
pkgs.writeScriptBin "shpool-ssh-wrapper" ''
#!${pkgs.bash}/bin/bash
# Shpool SSH wrapper - automatically runs commands for specific session patterns
- # Supports syntax: session-name=directory (e.g., "claude/home=src/home")
+ #
+ # Syntax: session-name=directory (e.g., "claude/home=src/home")
+ #
+ # Supported session patterns:
+ # claude/* - Claude Code with Vertex AI (cr command)
+ # copilot/* - GitHub Copilot CLI
+ # opencode/* - OpenCode CLI
+ # oco/* - OpenCode with Vertex AI
+ # review-<tool>/* - Review sessions with specified tool (cr, copilot, opencode, oco)
+ #
+ # Model selection (optional):
+ # claude:opus/home - Use opus model
+ # oco:sonnet/project - Use sonnet model
+ #
+ # Examples:
+ # ssh host/claude/home # Claude in ~/src/home
+ # ssh host/claude:opus/home # Claude with opus in ~/src/home
+ # ssh host/review-copilot/pr-123="prompt" # Review with copilot
set -euo pipefail
@@ -57,36 +89,140 @@ pkgs.writeScriptBin "shpool-ssh-wrapper" ''
exec ${pkgs.shpool}/bin/shpool attach -f -c "$cmd $*" "$session"
}
+ # Function to parse tool:model from prefix
+ # e.g., "claude:opus" -> TOOL=claude, MODEL=opus
+ # "claude" -> TOOL=claude, MODEL=""
+ parse_tool_model() {
+ local prefix="$1"
+ if [[ "$prefix" =~ ^([^:]+):(.+)$ ]]; then
+ TOOL="''${BASH_REMATCH[1]}"
+ MODEL="''${BASH_REMATCH[2]}"
+ else
+ TOOL="$prefix"
+ MODEL=""
+ fi
+ }
+
+ # Function to get default directory from session suffix
+ # e.g., "claude/home" -> "src/home", "claude:opus/home" -> "src/home"
+ get_default_dir() {
+ local session="$1"
+ local prefix="$2"
+ # Remove prefix (which may include :model)
+ local suffix="''${session#$prefix/}"
+ echo "src/$suffix"
+ }
+
+ # Function to run an AI tool session
+ # Args: session_name, tool_prefix, tool_command
+ run_ai_session() {
+ local session="$1"
+ local prefix_pattern="$2"
+ local default_cmd="$3"
+
+ # Extract the prefix part (before first /)
+ local prefix="''${session%%/*}"
+
+ # Parse tool:model from prefix
+ parse_tool_model "$prefix"
+
+ # Use default command if TOOL matches expected pattern
+ local cmd="$default_cmd"
+
+ # Get work directory
+ if [ -z "$WORK_DIR" ]; then
+ WORK_DIR=$(get_default_dir "$session" "$prefix")
+ fi
+
+ run_with_command "$session" "${run-in-dir}" "$cmd" "$WORK_DIR" "$MODEL"
+ }
+
# Check session name patterns and run appropriate commands
case "$SESSION_NAME" in
- claude/*)
- # Claude Code session - run with Vertex AI environment
- # If no directory specified, default to src/{session-name}
- if [ -z "$WORK_DIR" ]; then
- # Extract session name part after "claude/"
- SESSION_SUFFIX="''${SESSION_NAME#claude/}"
- WORK_DIR="src/$SESSION_SUFFIX"
- fi
- # Use helper script since shpool -c expects a binary, not a shell command
- run_with_command "$SESSION_NAME" "${claude-vertex}" "$WORK_DIR"
+ claude:*/*)
+ # Claude Code with model selection
+ run_ai_session "$SESSION_NAME" "claude" "cr"
;;
- review-*)
- # Claude Code review session - run with prompt
- # Usage: ssh host/review-pull-123="Review https://github.com/..."
- # The WORK_DIR variable holds the prompt (after =)
- # Uses 'cr' script from PATH (pkgs/my/scripts/bin/cr)
+ claude/*)
+ # Claude Code session - run with Vertex AI environment via cr
+ run_ai_session "$SESSION_NAME" "claude" "cr"
+ ;;
+ copilot:*/*)
+ # GitHub Copilot CLI with model selection
+ run_ai_session "$SESSION_NAME" "copilot" "copilot"
+ ;;
+ copilot/*)
+ # GitHub Copilot CLI session
+ run_ai_session "$SESSION_NAME" "copilot" "copilot"
+ ;;
+ opencode:*/*)
+ # OpenCode CLI with model selection
+ run_ai_session "$SESSION_NAME" "opencode" "opencode"
+ ;;
+ opencode/*)
+ # OpenCode CLI session
+ run_ai_session "$SESSION_NAME" "opencode" "opencode"
+ ;;
+ oco:*/*)
+ # OpenCode with Vertex AI and model selection
+ run_ai_session "$SESSION_NAME" "oco" "oco"
+ ;;
+ oco/*)
+ # OpenCode with Vertex AI session
+ run_ai_session "$SESSION_NAME" "oco" "oco"
+ ;;
+ review-cr/*|review-claude/*)
+ # Review with Claude Code (cr)
if [ -z "$WORK_DIR" ]; then
- # No prompt - check if session already exists and just attach
if ${pkgs.shpool}/bin/shpool list 2>/dev/null | grep -q "^$SESSION_NAME "; then
exec ${pkgs.shpool}/bin/shpool attach -f "$SESSION_NAME"
else
echo "Error: new review sessions require a prompt (use session=prompt syntax)" >&2
- echo "Example: ssh host/review-pull-123=\"Review https://github.com/...\"" >&2
+ echo "Example: ssh host/review-cr/pr-123=\"Review https://github.com/...\"" >&2
exit 1
fi
fi
run_with_command "$SESSION_NAME" "cr" "$WORK_DIR"
;;
+ review-copilot/*)
+ # Review with GitHub Copilot
+ if [ -z "$WORK_DIR" ]; then
+ if ${pkgs.shpool}/bin/shpool list 2>/dev/null | grep -q "^$SESSION_NAME "; then
+ exec ${pkgs.shpool}/bin/shpool attach -f "$SESSION_NAME"
+ else
+ echo "Error: new review sessions require a prompt (use session=prompt syntax)" >&2
+ echo "Example: ssh host/review-copilot/pr-123=\"Review https://github.com/...\"" >&2
+ exit 1
+ fi
+ fi
+ run_with_command "$SESSION_NAME" "copilot" "$WORK_DIR"
+ ;;
+ review-opencode/*)
+ # Review with OpenCode
+ if [ -z "$WORK_DIR" ]; then
+ if ${pkgs.shpool}/bin/shpool list 2>/dev/null | grep -q "^$SESSION_NAME "; then
+ exec ${pkgs.shpool}/bin/shpool attach -f "$SESSION_NAME"
+ else
+ echo "Error: new review sessions require a prompt (use session=prompt syntax)" >&2
+ echo "Example: ssh host/review-opencode/pr-123=\"Review https://github.com/...\"" >&2
+ exit 1
+ fi
+ fi
+ run_with_command "$SESSION_NAME" "opencode" "$WORK_DIR"
+ ;;
+ review-oco/*)
+ # Review with OpenCode Vertex
+ if [ -z "$WORK_DIR" ]; then
+ if ${pkgs.shpool}/bin/shpool list 2>/dev/null | grep -q "^$SESSION_NAME "; then
+ exec ${pkgs.shpool}/bin/shpool attach -f "$SESSION_NAME"
+ else
+ echo "Error: new review sessions require a prompt (use session=prompt syntax)" >&2
+ echo "Example: ssh host/review-oco/pr-123=\"Review https://github.com/...\"" >&2
+ exit 1
+ fi
+ fi
+ run_with_command "$SESSION_NAME" "oco" "$WORK_DIR"
+ ;;
*)
# If work directory specified, cd into it before attaching
if [ -n "$WORK_DIR" ]; then