@@ -84,6 +84,18 @@ variable "experiment_post_install_script" {
84
84
default = null
85
85
}
86
86
87
+ variable "experiment_tmux_session_persistence" {
88
+ type = bool
89
+ description = " Whether to enable tmux session persistence across workspace restarts."
90
+ default = false
91
+ }
92
+
93
+ variable "experiment_tmux_session_save_interval" {
94
+ type = string
95
+ description = " How often to save tmux sessions in minutes."
96
+ default = " 15"
97
+ }
98
+
87
99
locals {
88
100
encoded_pre_install_script = var. experiment_pre_install_script != null ? base64encode (var. experiment_pre_install_script ) : " "
89
101
encoded_post_install_script = var. experiment_post_install_script != null ? base64encode (var. experiment_post_install_script ) : " "
@@ -98,12 +110,28 @@ resource "coder_script" "claude_code" {
98
110
#!/bin/bash
99
111
set -e
100
112
101
- # Function to check if a command exists
102
113
command_exists() {
103
114
command -v "$1" >/dev/null 2>&1
104
115
}
105
116
106
- # Check if the specified folder exists
117
+ install_tmux() {
118
+ echo "Installing tmux..."
119
+ if command_exists apt-get; then
120
+ sudo apt-get update && sudo apt-get install -y tmux
121
+ elif command_exists yum; then
122
+ sudo yum install -y tmux
123
+ elif command_exists dnf; then
124
+ sudo dnf install -y tmux
125
+ elif command_exists pacman; then
126
+ sudo pacman -S --noconfirm tmux
127
+ elif command_exists apk; then
128
+ sudo apk add tmux
129
+ else
130
+ echo "Error: Unable to install tmux automatically. Package manager not recognized."
131
+ exit 1
132
+ fi
133
+ }
134
+
107
135
if [ ! -d "${ var . folder } " ]; then
108
136
echo "Warning: The specified folder '${ var . folder } ' does not exist."
109
137
echo "Creating the folder..."
@@ -112,20 +140,37 @@ resource "coder_script" "claude_code" {
112
140
mkdir -p "${ var . folder } "
113
141
echo "Folder created successfully."
114
142
fi
115
-
116
- # Run pre-install script if provided
117
143
if [ -n "${ local . encoded_pre_install_script } " ]; then
118
144
echo "Running pre-install script..."
119
145
echo "${ local . encoded_pre_install_script } " | base64 -d > /tmp/pre_install.sh
120
146
chmod +x /tmp/pre_install.sh
121
147
/tmp/pre_install.sh
122
148
fi
123
149
124
- # Install Claude Code if enabled
125
150
if [ "${ var . install_claude_code } " = "true" ]; then
126
151
if ! command_exists npm; then
127
- echo "Error: npm is not installed. Please install Node.js and npm first."
128
- exit 1
152
+ echo "npm not found, checking for Node.js installation..."
153
+ if ! command_exists node; then
154
+ echo "Node.js not found, installing Node.js via NVM..."
155
+ export NVM_DIR="$HOME/.nvm"
156
+ if [ ! -d "$NVM_DIR" ]; then
157
+ mkdir -p "$NVM_DIR"
158
+ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
159
+ [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
160
+ else
161
+ [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
162
+ fi
163
+
164
+ nvm install --lts
165
+ nvm use --lts
166
+ nvm alias default node
167
+
168
+ echo "Node.js installed: $(node --version)"
169
+ echo "npm installed: $(npm --version)"
170
+ else
171
+ echo "Node.js is installed but npm is not available. Please install npm manually."
172
+ exit 1
173
+ fi
129
174
fi
130
175
echo "Installing Claude Code..."
131
176
npm install -g @anthropic-ai/claude-code@${ var . claude_code_version }
@@ -136,54 +181,104 @@ resource "coder_script" "claude_code" {
136
181
coder exp mcp configure claude-code ${ var . folder }
137
182
fi
138
183
139
- # Run post-install script if provided
140
184
if [ -n "${ local . encoded_post_install_script } " ]; then
141
185
echo "Running post-install script..."
142
186
echo "${ local . encoded_post_install_script } " | base64 -d > /tmp/post_install.sh
143
187
chmod +x /tmp/post_install.sh
144
188
/tmp/post_install.sh
145
189
fi
146
190
147
- # Handle terminal multiplexer selection (tmux or screen)
148
191
if [ "${ var . experiment_use_tmux } " = "true" ] && [ "${ var . experiment_use_screen } " = "true" ]; then
149
192
echo "Error: Both experiment_use_tmux and experiment_use_screen cannot be true simultaneously."
150
193
echo "Please set only one of them to true."
151
194
exit 1
152
195
fi
153
196
154
- # Run with tmux if enabled
155
- if [ "${ var . experiment_use_tmux } " = "true" ]; then
156
- echo "Running Claude Code in the background with tmux..."
197
+ if [ "${ var . experiment_tmux_session_persistence } " = "true" ] && [ "${ var . experiment_use_tmux } " != "true" ]; then
198
+ echo "Error: Session persistence requires tmux to be enabled."
199
+ echo "Please set experiment_use_tmux = true when using session persistence."
200
+ exit 1
201
+ fi
157
202
158
- # Check if tmux is installed
203
+ if [ " ${ var . experiment_use_tmux } " = "true" ]; then
159
204
if ! command_exists tmux; then
160
- echo "Error: tmux is not installed. Please install tmux manually."
161
- exit 1
205
+ install_tmux
162
206
fi
163
207
164
- touch "$HOME/.claude-code.log"
208
+ if [ "${ var . experiment_tmux_session_persistence } " = "true" ]; then
209
+ echo "Setting up tmux session persistence..."
210
+ if ! command_exists git; then
211
+ echo "Git not found, installing git..."
212
+ if command_exists apt-get; then
213
+ sudo apt-get update && sudo apt-get install -y git
214
+ elif command_exists yum; then
215
+ sudo yum install -y git
216
+ elif command_exists dnf; then
217
+ sudo dnf install -y git
218
+ elif command_exists pacman; then
219
+ sudo pacman -S --noconfirm git
220
+ elif command_exists apk; then
221
+ sudo apk add git
222
+ else
223
+ echo "Error: Unable to install git automatically. Package manager not recognized."
224
+ echo "Please install git manually to enable session persistence."
225
+ exit 1
226
+ fi
227
+ fi
228
+
229
+ mkdir -p ~/.tmux/plugins
230
+ if [ ! -d ~/.tmux/plugins/tpm ]; then
231
+ git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
232
+ fi
233
+
234
+ cat > ~/.tmux.conf << EOF
235
+ # Claude Code tmux persistence configuration
236
+ set -g @plugin 'tmux-plugins/tmux-resurrect'
237
+ set -g @plugin 'tmux-plugins/tmux-continuum'
238
+
239
+ # Configure session persistence
240
+ set -g @resurrect-processes ':all:'
241
+ set -g @resurrect-capture-pane-contents 'on'
242
+ set -g @resurrect-save-bash-history 'on'
243
+ set -g @continuum-restore 'on'
244
+ set -g @continuum-save-interval '${ var . experiment_tmux_session_save_interval } '
245
+ set -g @continuum-boot 'on'
246
+ set -g @continuum-save-on 'on'
247
+
248
+ # Initialize plugin manager
249
+ run '~/.tmux/plugins/tpm/tpm'
250
+ EOF
251
+
252
+ ~/.tmux/plugins/tpm/scripts/install_plugins.sh
253
+ fi
165
254
255
+ echo "Running Claude Code in the background with tmux..."
256
+ touch "$HOME/.claude-code.log"
166
257
export LANG=en_US.UTF-8
167
258
export LC_ALL=en_US.UTF-8
168
259
169
- # Create a new tmux session in detached mode
170
- tmux new-session -d -s claude-code -c ${ var . folder } "claude --dangerously-skip-permissions \"$CODER_MCP_CLAUDE_TASK_PROMPT\""
171
-
260
+ if [ "${ var . experiment_tmux_session_persistence } " = "true" ]; then
261
+ sleep 3
262
+
263
+ if ! tmux has-session -t claude-code 2>/dev/null; then
264
+ # Only create a new session if one doesn't exist
265
+ tmux new-session -d -s claude-code -c ${ var . folder } "claude --dangerously-skip-permissions \"$CODER_MCP_CLAUDE_TASK_PROMPT\""
266
+ fi
267
+ else
268
+
179B
if ! tmux has-session -t claude-code 2>/dev/null; then
269
+ tmux new-session -d -s claude-code -c ${ var . folder } "claude --dangerously-skip-permissions \"$CODER_MCP_CLAUDE_TASK_PROMPT\""
270
+ fi
271
+ fi
172
272
fi
173
273
174
- # Run with screen if enabled
175
274
if [ "${ var . experiment_use_screen } " = "true" ]; then
176
275
echo "Running Claude Code in the background..."
177
-
178
- # Check if screen is installed
179
276
if ! command_exists screen; then
180
277
echo "Error: screen is not installed. Please install screen manually."
181
278
exit 1
182
279
fi
183
280
184
281
touch "$HOME/.claude-code.log"
185
-
186
- # Ensure the screenrc exists
187
282
if [ ! -f "$HOME/.screenrc" ]; then
188
283
echo "Creating ~/.screenrc and adding multiuser settings..." | tee -a "$HOME/.claude-code.log"
189
284
echo -e "multiuser on\nacladd $(whoami)" > "$HOME/.screenrc"
@@ -198,6 +293,7 @@ resource "coder_script" "claude_code" {
198
293
echo "Adding 'acladd $(whoami)' to ~/.screenrc..." | tee -a "$HOME/.claude-code.log"
199
294
echo "acladd $(whoami)" >> "$HOME/.screenrc"
200
295
fi
296
+
201
297
export LANG=en_US.UTF-8
202
298
export LC_ALL=en_US.UTF-8
203
299
@@ -207,7 +303,6 @@ resource "coder_script" "claude_code" {
207
303
exec bash
208
304
'
209
305
else
210
- # Check if claude is installed before running
211
306
if ! command_exists claude; then
212
307
echo "Error: Claude Code is not installed. Please enable install_claude_code or install it manually."
213
308
exit 1
@@ -231,6 +326,10 @@ resource "coder_app" "claude_code" {
231
326
if [ "${ var . experiment_use_tmux } " = "true" ]; then
232
327
if tmux has-session -t claude-code 2>/dev/null; then
233
328
echo "Attaching to existing Claude Code tmux session." | tee -a "$HOME/.claude-code.log"
329
+ # If Claude isn't running in the session, start it without the prompt
330
+ if ! tmux list-panes -t claude-code -F '#{pane_current_command}' | grep -q "claude"; then
331
+ tmux send-keys -t claude-code "cd ${ var . folder } && claude -c --dangerously-skip-permissions" C-m
332
+ fi
234
333
tmux attach-session -t claude-code
235
334
else
236
335
echo "Starting a new Claude Code tmux session." | tee -a "$HOME/.claude-code.log"
0 commit comments