auto-update-daily-20260202
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 # pi/* - Pi coding agent
62 # review-<tool>/* - Review sessions with specified tool (cr, copilot, opencode, oco, pi)
63 #
64 # Model selection (optional):
65 # claude:opus/home - Use opus model
66 # oco:sonnet/project - Use sonnet model
67 #
68 # Examples:
69 # ssh host/claude/home # Claude in ~/src/home
70 # ssh host/claude:opus/home # Claude with opus in ~/src/home
71 # ssh host/pi/home # Pi coding agent in ~/src/home
72 # ssh host/pi:sonnet/home # Pi with sonnet in ~/src/home
73 # ssh host/review-copilot/pr-123="prompt" # Review with copilot
74
75 set -euo pipefail
76
77 # Parse session spec: "claude/home=src/home" -> session="claude/home", dir="src/home"
78 SESSION_SPEC="''${1}"
79 if [[ "$SESSION_SPEC" =~ ^([^=]+)=(.+)$ ]]; then
80 SESSION_NAME="''${BASH_REMATCH[1]}"
81 WORK_DIR="''${BASH_REMATCH[2]}"
82 else
83 SESSION_NAME="$SESSION_SPEC"
84 WORK_DIR=""
85 fi
86
87 # Function to run shpool with a specific command
88 run_with_command() {
89 local session="$1"
90 local cmd="$2"
91 shift 2
92 exec ${pkgs.shpool}/bin/shpool attach -f -c "$cmd $*" "$session"
93 }
94
95 # Function to parse tool:model from prefix
96 # e.g., "claude:opus" -> TOOL=claude, MODEL=opus
97 # "claude" -> TOOL=claude, MODEL=""
98 parse_tool_model() {
99 local prefix="$1"
100 if [[ "$prefix" =~ ^([^:]+):(.+)$ ]]; then
101 TOOL="''${BASH_REMATCH[1]}"
102 MODEL="''${BASH_REMATCH[2]}"
103 else
104 TOOL="$prefix"
105 MODEL=""
106 fi
107 }
108
109 # Function to get default directory from session suffix
110 # e.g., "claude/home" -> "src/home", "claude:opus/home" -> "src/home"
111 get_default_dir() {
112 local session="$1"
113 local prefix="$2"
114 # Remove prefix (which may include :model)
115 local suffix="''${session#$prefix/}"
116 echo "src/$suffix"
117 }
118
119 # Function to run an AI tool session
120 # Args: session_name, tool_prefix, tool_command
121 run_ai_session() {
122 local session="$1"
123 local prefix_pattern="$2"
124 local default_cmd="$3"
125
126 # Extract the prefix part (before first /)
127 local prefix="''${session%%/*}"
128
129 # Parse tool:model from prefix
130 parse_tool_model "$prefix"
131
132 # Use default command if TOOL matches expected pattern
133 local cmd="$default_cmd"
134
135 # Get work directory
136 if [ -z "$WORK_DIR" ]; then
137 WORK_DIR=$(get_default_dir "$session" "$prefix")
138 fi
139
140 run_with_command "$session" "${run-in-dir}" "$cmd" "$WORK_DIR" "$MODEL"
141 }
142
143 # Check session name patterns and run appropriate commands
144 case "$SESSION_NAME" in
145 claude:*/*)
146 # Claude Code with model selection
147 run_ai_session "$SESSION_NAME" "claude" "cr"
148 ;;
149 claude/*)
150 # Claude Code session - run with Vertex AI environment via cr
151 run_ai_session "$SESSION_NAME" "claude" "cr"
152 ;;
153 copilot:*/*)
154 # GitHub Copilot CLI with model selection
155 run_ai_session "$SESSION_NAME" "copilot" "copilot"
156 ;;
157 copilot/*)
158 # GitHub Copilot CLI session
159 run_ai_session "$SESSION_NAME" "copilot" "copilot"
160 ;;
161 opencode:*/*)
162 # OpenCode CLI with model selection
163 run_ai_session "$SESSION_NAME" "opencode" "opencode"
164 ;;
165 opencode/*)
166 # OpenCode CLI session
167 run_ai_session "$SESSION_NAME" "opencode" "opencode"
168 ;;
169 oco:*/*)
170 # OpenCode with Vertex AI and model selection
171 run_ai_session "$SESSION_NAME" "oco" "oco"
172 ;;
173 oco/*)
174 # OpenCode with Vertex AI session
175 run_ai_session "$SESSION_NAME" "oco" "oco"
176 ;;
177 pi:*/*)
178 # Pi coding agent with model selection
179 run_ai_session "$SESSION_NAME" "pi" "pi"
180 ;;
181 pi/*)
182 # Pi coding agent session
183 run_ai_session "$SESSION_NAME" "pi" "pi"
184 ;;
185 review-cr/*|review-claude/*)
186 # Review with Claude Code (cr)
187 if [ -z "$WORK_DIR" ]; then
188 if ${pkgs.shpool}/bin/shpool list 2>/dev/null | grep -q "^$SESSION_NAME "; then
189 exec ${pkgs.shpool}/bin/shpool attach -f "$SESSION_NAME"
190 else
191 echo "Error: new review sessions require a prompt (use session=prompt syntax)" >&2
192 echo "Example: ssh host/review-cr/pr-123=\"Review https://github.com/...\"" >&2
193 exit 1
194 fi
195 fi
196 run_with_command "$SESSION_NAME" "cr" "$WORK_DIR"
197 ;;
198 review-copilot/*)
199 # Review with GitHub Copilot
200 if [ -z "$WORK_DIR" ]; then
201 if ${pkgs.shpool}/bin/shpool list 2>/dev/null | grep -q "^$SESSION_NAME "; then
202 exec ${pkgs.shpool}/bin/shpool attach -f "$SESSION_NAME"
203 else
204 echo "Error: new review sessions require a prompt (use session=prompt syntax)" >&2
205 echo "Example: ssh host/review-copilot/pr-123=\"Review https://github.com/...\"" >&2
206 exit 1
207 fi
208 fi
209 run_with_command "$SESSION_NAME" "copilot" "$WORK_DIR"
210 ;;
211 review-opencode/*)
212 # Review with OpenCode
213 if [ -z "$WORK_DIR" ]; then
214 if ${pkgs.shpool}/bin/shpool list 2>/dev/null | grep -q "^$SESSION_NAME "; then
215 exec ${pkgs.shpool}/bin/shpool attach -f "$SESSION_NAME"
216 else
217 echo "Error: new review sessions require a prompt (use session=prompt syntax)" >&2
218 echo "Example: ssh host/review-opencode/pr-123=\"Review https://github.com/...\"" >&2
219 exit 1
220 fi
221 fi
222 run_with_command "$SESSION_NAME" "opencode" "$WORK_DIR"
223 ;;
224 review-oco/*)
225 # Review with OpenCode Vertex
226 if [ -z "$WORK_DIR" ]; then
227 if ${pkgs.shpool}/bin/shpool list 2>/dev/null | grep -q "^$SESSION_NAME "; then
228 exec ${pkgs.shpool}/bin/shpool attach -f "$SESSION_NAME"
229 else
230 echo "Error: new review sessions require a prompt (use session=prompt syntax)" >&2
231 echo "Example: ssh host/review-oco/pr-123=\"Review https://github.com/...\"" >&2
232 exit 1
233 fi
234 fi
235 run_with_command "$SESSION_NAME" "oco" "$WORK_DIR"
236 ;;
237 review-pi/*)
238 # Review with Pi coding agent
239 if [ -z "$WORK_DIR" ]; then
240 if ${pkgs.shpool}/bin/shpool list 2>/dev/null | grep -q "^$SESSION_NAME "; then
241 exec ${pkgs.shpool}/bin/shpool attach -f "$SESSION_NAME"
242 else
243 echo "Error: new review sessions require a prompt (use session=prompt syntax)" >&2
244 echo "Example: ssh host/review-pi/pr-123=\"Review https://github.com/...\"" >&2
245 exit 1
246 fi
247 fi
248 run_with_command "$SESSION_NAME" "pi" "$WORK_DIR"
249 ;;
250 *)
251 # If work directory specified, cd into it before attaching
252 if [ -n "$WORK_DIR" ]; then
253 # Start shell and cd into directory
254 exec ${pkgs.shpool}/bin/shpool attach -f -c "${pkgs.zsh}/bin/zsh -c 'cd $WORK_DIR && exec ${pkgs.zsh}/bin/zsh'" "$SESSION_NAME"
255 else
256 # Default: just attach to session with default shell
257 exec ${pkgs.shpool}/bin/shpool attach -f "$SESSION_NAME"
258 fi
259 ;;
260 esac
261''