malt666 commited on
Commit
8768d9b
·
verified ·
1 Parent(s): 00d7978

Upload 2 files

Browse files
Files changed (2) hide show
  1. Dockerfile +14 -204
  2. health.sh +201 -0
Dockerfile CHANGED
@@ -8,7 +8,7 @@ ARG PLUGINS="" # Comma-separated list of plugin git URLs
8
  # Add unzip for extracting the application code
9
  # Keep git for potential use by scripts or future plugin updates
10
  # Add wget to download the zip file
11
- # Add curl for the keep-alive script
12
  RUN apk add --no-cache gcompat tini git unzip wget curl
13
 
14
  # Create app directory
@@ -60,214 +60,24 @@ RUN \
60
  echo "build-lib.js not found, skipping Webpack build."; \
61
  fi
62
 
 
 
 
 
 
 
63
  # Fix potential git safe.directory issues if git commands are run later by scripts
64
  RUN git config --global --add safe.directory "${APP_HOME}"
65
 
66
  # Ensure the node user owns the application directory and its contents
67
  RUN chown -R node:node ${APP_HOME}
68
 
69
- EXPOSE 8000
70
-
71
- # --- BEGIN: Create love.sh script ---
72
- RUN printf '#!/bin/sh\n\n\
73
- # --- BEGIN: Update SillyTavern Core at Runtime ---\n\
74
- echo "--- Attempting to update SillyTavern Core from GitHub (staging branch) ---"\n\
75
- if [ -d ".git" ] && [ "$(git rev-parse --abbrev-ref HEAD)" = "staging" ]; then\n\
76
- echo "Existing staging branch found. Resetting and pulling latest changes..."\n\
77
- git reset --hard HEAD && \\\n\
78
- git pull origin staging || echo "WARN: git pull failed, continuing with code from build time."\n\
79
- echo "--- SillyTavern Core update check finished. ---"\n\
80
- else\n\
81
- echo "WARN: .git directory not found or not on staging branch. Skipping runtime update. Code from build time will be used."\n\
82
- fi;\n\
83
- # --- END: Update SillyTavern Core at Runtime ---\n\
84
- \n\
85
- echo "--- Checking for CONFIG_YAML environment variable ---"\n\
86
- # Ensure the CWD has correct permissions for writing config.yaml\n\
87
- # mkdir -p ./config && chown node:node ./config; # Removed mkdir\n\
88
- if [ -n "$CONFIG_YAML" ]; then\n\
89
- echo "Environment variable CONFIG_YAML found. Writing to ./config.yaml (root directory)..."\n\
90
- # Write directly to ./config.yaml in the CWD\n\
91
- printf "%%s\\n" "$CONFIG_YAML" > ./config.yaml && \\\n\
92
- chown node:node ./config.yaml && \\\n\
93
- echo "Config written to ./config.yaml and permissions set successfully."\n\
94
- # --- BEGIN DEBUG: Print the written config file ---\n\
95
- echo '--- Verifying written ./config.yaml --- (Printing removed) '\n\
96
- # --- END DEBUG ---\n\
97
- else\n\
98
- echo "Warning: Environment variable CONFIG_YAML is not set or empty. Attempting to copy default config..."\n\
99
- # Copy default if ENV VAR is missing and the example exists\n\
100
- if [ -f "./public/config.yaml.example" ]; then\n\
101
- # Copy default to ./config.yaml in the CWD\n\
102
- cp "./public/config.yaml.example" "./config.yaml" && \\\n\
103
- chown node:node ./config.yaml && \\\n\
104
- echo "Copied default config to ./config.yaml"\n\
105
- else\n\
106
- echo "Warning: Default config ./public/config.yaml.example not found."\n\
107
- fi;\n\
108
- fi;\n\
109
- \n\
110
- # --- BEGIN: Configure Git default identity at Runtime ---\n\
111
- echo "--- Configuring Git default user identity at runtime ---"\n\
112
- git config --global user.name "SillyTavern Sync" && \\\n\
113
- git config --global user.email "[email protected]";\n\
114
- echo "--- Git identity configured for runtime user. ---\n\
115
- # --- END: Configure Git default identity at Runtime ---\n\
116
- \n\
117
- # --- BEGIN: Dynamically Install Plugins at Runtime ---\n\
118
- echo "--- Checking for PLUGINS environment variable ---"\n\
119
- if [ -n "$PLUGINS" ]; then\n\
120
- echo "*** Installing Plugins specified in PLUGINS environment variable: $PLUGINS ***" && \\\n\
121
- # Ensure plugins directory exists\n\
122
- mkdir -p ./plugins && chown node:node ./plugins && \\\n\
123
- # Set comma as delimiter\n\
124
- IFS=',' && \\\n\
125
- # Loop through each plugin URL\n\
126
- for plugin_url in $PLUGINS; do\n\
127
- # Trim leading/trailing whitespace\n\
128
- plugin_url=$(echo "$plugin_url" | sed \'s/^[[:space:]]*//;s/[[:space:]]*$//\') && \\\n\
129
- if [ -z "$plugin_url" ]; then continue; fi && \\\n\
130
- # Extract plugin name\n\
131
- plugin_name_git=$(basename "$plugin_url") && \\\n\
132
- plugin_name=${plugin_name_git%.git} && \\\n\
133
- plugin_dir="./plugins/$plugin_name" && \\\n\
134
- echo "--- Installing plugin: $plugin_name from $plugin_url into $plugin_dir ---" && \\\n\
135
- # Remove existing dir if it exists\n\
136
- rm -rf "$plugin_dir" && \\\n\
137
- # Clone the plugin (run as root, fix perms later)\n\
138
- git clone --depth 1 "$plugin_url" "$plugin_dir" && \\\n\
139
- if [ -f "$plugin_dir/package.json" ]; then\n\
140
- echo "--- Installing dependencies for $plugin_name ---" && \\\n\
141
- (cd "$plugin_dir" && npm install --no-audit --no-fund --loglevel=error --no-progress --omit=dev --force && npm cache clean --force) || echo "WARN: Failed to install dependencies for $plugin_name";\n\
142
- else\n\
143
- echo "--- No package.json found for $plugin_name, skipping dependency install. ---";\n\
144
- fi || echo "WARN: Failed to clone $plugin_name from $plugin_url, skipping...";\n\
145
- done && \\\n\
146
- # Reset IFS\n\
147
- unset IFS && \\\n\
148
- # Fix permissions for plugins directory after installation\n\
149
- echo "--- Setting permissions for plugins directory ---" && \\\n\
150
- chown -R node:node ./plugins && \\\n\
151
- echo "*** Plugin installation finished. ***";\n\
152
- else\n\
153
- echo "PLUGINS environment variable is not set or empty, skipping runtime plugin installation."\n\
154
- fi;\n\
155
- # --- END: Dynamically Install Plugins at Runtime ---\n\
156
- \n\
157
- # --- BEGIN: Auto-configure cloud-saves plugin if secrets provided ---\n\
158
- echo "--- Checking for cloud-saves plugin auto-configuration ---"\n\
159
- if [ -d "./plugins/cloud-saves" ] && [ -n "$REPO_URL" ] && [ -n "$GITHUB_TOKEN" ]; then\n\
160
- config_file="./plugins/cloud-saves/config.json" && \\\n\
161
- echo "--- Creating config.json for cloud-saves plugin at $config_file ---" && \\\n\
162
- printf \'{\\\\n \\\"repo_url\\\": \\\"%%s\\\",\\\\n \\\"branch\\\": \\\"main\\\",\\\\n \\\"username\\\": \\\"\\\",\\\\n \\\"github_token\\\": \\\"%%s\\\",\\\\n \\\"display_name\\\": \\\"user\\\",\\\\n \\\"is_authorized\\\": true,\\\\n \\\"last_save\\\": null,\\\\n \\\"current_save\\\": null,\\\\n \\\"has_temp_stash\\\": false,\\\\n \\\"autoSaveEnabled\\\": false,\\\\n \\\"autoSaveInterval\\\": %%s,\\\\n \\\"autoSaveTargetTag\\\": \\\"%%s\\\"\\\\n}\\\\n\' \\"$REPO_URL\\" \\"$GITHUB_TOKEN\\" "${AUTOSAVE_INTERVAL:-30}" "${AUTOSAVE_TARGET_TAG:-}" > "$config_file" && \\\n\
163
- chown node:node "$config_file" && \\\n\
164
- echo "*** cloud-saves plugin auto-configuration completed ***";\n\
165
- # --- BEGIN DEBUG: Print the written config file ---\n\
166
- echo '--- Verifying written ./plugins/cloud-saves/config.json --- (Printing removed) '\n\
167
- # --- END DEBUG ---\n\
168
- else\n\
169
- if [ ! -d "./plugins/cloud-saves" ]; then\n\
170
- echo "cloud-saves plugin not found, skipping auto-configuration."\n\
171
- elif [ -z "$REPO_URL" ] || [ -z "$GITHUB_TOKEN" ]; then\n\
172
- echo "REPO_URL or GITHUB_TOKEN environment variables not provided, skipping cloud-saves auto-configuration."\n\
173
- fi;\n\
174
- fi;\n\
175
- # --- END: Auto-configure cloud-saves plugin ---\n\
176
- \n\
177
- # --- BEGIN: Dynamically Install Extensions at Runtime ---\n\
178
- echo "--- Checking for EXTENSIONS environment variable ---"\n\
179
- if [ -n "$EXTENSIONS" ]; then\n\
180
- echo "*** Installing Extensions specified in EXTENSIONS environment variable: $EXTENSIONS ***" && \\\n\
181
- # Determine extension installation directory based on INSTALL_FOR_ALL_USERS\n\
182
- if [ "$INSTALL_FOR_ALL_USERS" = "true" ]; then\n\
183
- ext_install_dir="./public/scripts/extensions/third-party" && \\\n\
184
- echo "--- Installing extensions for all users (system-wide) to $ext_install_dir ---";\n\
185
- else\n\
186
- ext_install_dir="./data/default-user/extensions" && \\\n\
187
- echo "--- Installing extensions for default user only to $ext_install_dir ---";\n\
188
- fi && \\\n\
189
- # Ensure extension directory exists\n\
190
- mkdir -p "$ext_install_dir" && chown node:node "$ext_install_dir" && \\\n\
191
- # Set comma as delimiter\n\
192
- IFS=',' && \\\n\
193
- # Loop through each extension URL\n\
194
- for ext_url in $EXTENSIONS; do\n\
195
- # Trim leading/trailing whitespace\n\
196
- ext_url=$(echo "$ext_url" | sed \'s/^[[:space:]]*//;s/[[:space:]]*$//\') && \\\n\
197
- if [ -z "$ext_url" ]; then continue; fi && \\\n\
198
- # Extract extension name\n\
199
- ext_name_git=$(basename "$ext_url") && \\\n\
200
- ext_name=${ext_name_git%.git} && \\\n\
201
- ext_dir="$ext_install_dir/$ext_name" && \\\n\
202
- echo "--- Installing extension: $ext_name from $ext_url into $ext_dir ---" && \\\n\
203
- # Remove existing dir if it exists\n\
204
- rm -rf "$ext_dir" && \\\n\
205
- # Clone the extension (run as root, fix perms later)\n\
206
- git clone --depth 1 "$ext_url" "$ext_dir" && \\\n\
207
- if [ -f "$ext_dir/package.json" ]; then\n\
208
- echo "--- Installing dependencies for extension $ext_name ---" && \\\n\
209
- (cd "$ext_dir" && npm install --no-audit --no-fund --loglevel=error --no-progress --omit=dev --force && npm cache clean --force) || echo "WARN: Failed to install dependencies for extension $ext_name";\n\
210
- else\n\
211
- echo "--- No package.json found for extension $ext_name, skipping dependency install. ---";\n\
212
- fi || echo "WARN: Failed to clone extension $ext_name from $ext_url, skipping...";\n\
213
- done && \\\n\
214
- # Reset IFS\n\
215
- unset IFS && \\\n\
216
- # Fix permissions for extensions directory after installation\n\
217
- echo "--- Setting permissions for extensions directory ---" && \\\n\
218
- chown -R node:node "$ext_install_dir" && \\\n\
219
- echo "*** Extension installation finished. ***";\n\
220
- else\n\
221
- echo "EXTENSIONS environment variable is not set or empty, skipping runtime extension installation."\n\
222
- fi;\n\
223
- # --- END: Dynamically Install Extensions at Runtime ---\n\
224
- \n\
225
- # --- BEGIN: Cleanup before start ---\n\
226
- # Remove .gitignore\n\
227
- echo "Attempting final removal of .gitignore..." && \\\n\
228
- rm -f .gitignore && \\\n\
229
- if [ ! -e .gitignore ]; then\n\
230
- echo ".gitignore successfully removed."\n\
231
- else\n\
232
- # This case is unlikely with rm -f unless permissions prevent removal\n\
233
- echo "WARN: .gitignore could not be removed or reappeared."\n\
234
- fi;\n\
235
- # Remove .git directory\n\
236
- echo "Attempting final removal of .git directory..." && \\\n\
237
- rm -rf .git && \\\n\
238
- if [ ! -d .git ]; then\n\
239
- echo ".git directory successfully removed."\n\
240
- else\n\
241
- # This case usually indicates a permission issue\n\
242
- echo "WARN: .git directory could not be removed."\n\
243
- fi;\n\
244
- # --- END: Cleanup before start ---\n\
245
- \n\
246
- echo "Starting SillyTavern server in background..."\n\
247
- # Execute node server directly, bypassing docker-entrypoint.sh and run in background\n\
248
- node server.js &\n\
249
- \n\
250
- echo "Waiting for SillyTavern server to be available at http://localhost:8000/"\n\
251
- # Wait for server to be up and running (health check)\n\
252
- until curl --output /dev/null --silent --head --fail http://localhost:8000/; do\n\
253
- echo "SillyTavern is still starting or not responding, waiting 5 seconds..."\n\
254
- sleep 5\n\
255
- done\n\
256
- echo "SillyTavern server started successfully!"\n\
257
- \n\
258
- echo "Starting periodic keep-alive (every 30 minutes)..."\n\
259
- # Keep-alive loop\n\
260
- while true; do\n\
261
- echo "Sending keep-alive request..."\n\
262
- curl http://localhost:8000/\n\
263
- echo "Keep-alive request sent."\n\
264
- sleep 1800 # 30 minutes in seconds\n\
265
- done\n\
266
- \n\
267
- ' > ./love.sh
268
  # Make the script executable
269
- RUN chmod +x ./love.sh
270
- # --- END: Create love.sh script ---
 
271
 
272
- # Entrypoint: Run the love.sh script using tini
273
- ENTRYPOINT ["tini", "--", "/home/node/app/love.sh"]
 
8
  # Add unzip for extracting the application code
9
  # Keep git for potential use by scripts or future plugin updates
10
  # Add wget to download the zip file
11
+ # Add curl for health checks and keep-alive
12
  RUN apk add --no-cache gcompat tini git unzip wget curl
13
 
14
  # Create app directory
 
60
  echo "build-lib.js not found, skipping Webpack build."; \
61
  fi
62
 
63
+ # Cleanup unnecessary files (like the docker dir if it exists in the zip) and make entrypoint executable
64
+ # This block is removed as we no longer use docker-entrypoint.sh
65
+ # RUN \
66
+ # echo "*** Cleanup and Permissions ***" && \
67
+ # ...
68
+
69
  # Fix potential git safe.directory issues if git commands are run later by scripts
70
  RUN git config --global --add safe.directory "${APP_HOME}"
71
 
72
  # Ensure the node user owns the application directory and its contents
73
  RUN chown -R node:node ${APP_HOME}
74
 
75
+ # Copy the health check and startup script into the container
76
+ COPY health.sh ${APP_HOME}/health.sh
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  # Make the script executable
78
+ RUN chmod +x ${APP_HOME}/health.sh
79
+
80
+ EXPOSE 8000
81
 
82
+ # Entrypoint: Execute the health check and startup script
83
+ ENTRYPOINT ["tini", "--", "/home/node/app/health.sh"]
health.sh ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+
3
+ # Ensure we are in the correct directory
4
+ cd /home/node/app
5
+
6
+ # --- BEGIN: SillyTavern Runtime Setup (copied from original Dockerfile ENTRYPOINT) ---
7
+
8
+ # Note: The git update logic from the original ENTRYPOINT is removed here as
9
+ # .git directory is removed at the end of the build process in the Dockerfile.
10
+
11
+ echo '--- Checking for CONFIG_YAML environment variable ---';
12
+ # Ensure the CWD has correct permissions for writing config.yaml
13
+ # mkdir -p ./config && chown node:node ./config; # Removed mkdir
14
+ if [ -n "$CONFIG_YAML" ]; then
15
+ echo 'Environment variable CONFIG_YAML found. Writing to ./config.yaml (root directory)...';
16
+ # Write directly to ./config.yaml in the CWD
17
+ printf '%s\n' "$CONFIG_YAML" > ./config.yaml && \
18
+ chown node:node ./config.yaml && \
19
+ echo 'Config written to ./config.yaml and permissions set successfully.';
20
+ else
21
+ echo 'Warning: Environment variable CONFIG_YAML is not set or empty. Attempting to copy default config...';
22
+ # Copy default if ENV VAR is missing and the example exists
23
+ if [ -f "./public/config.yaml.example" ]; then
24
+ # Copy default to ./config.yaml in the CWD
25
+ cp "./public/config.yaml.example" "./config.yaml" && \
26
+ chown node:node ./config.yaml && \
27
+ echo 'Copied default config to ./config.yaml';
28
+ else
29
+ echo 'Warning: Default config ./public/config.yaml.example not found.';
30
+ fi;
31
+ fi;
32
+
33
+ # --- BEGIN: Configure Git default identity at Runtime (Needed for some plugins/extensions) ---
34
+ echo '--- Configuring Git default user identity at runtime ---';
35
+ git config --global user.name "SillyTavern Sync" && \
36
+ git config --global user.email "[email protected]";
37
+ echo '--- Git identity configured for runtime user. ---';
38
+ # --- END: Configure Git default identity at Runtime ---
39
+
40
+ # --- BEGIN: Dynamically Install Plugins at Runtime ---
41
+ echo '--- Checking for PLUGINS environment variable ---';
42
+ if [ -n "$PLUGINS" ]; then
43
+ echo "*** Installing Plugins specified in PLUGINS environment variable: $PLUGINS ***" && \
44
+ # Ensure plugins directory exists
45
+ mkdir -p ./plugins && chown node:node ./plugins && \
46
+ # Set comma as delimiter
47
+ IFS=',' && \
48
+ # Loop through each plugin URL
49
+ for plugin_url in $PLUGINS; do \
50
+ # Trim leading/trailing whitespace
51
+ plugin_url=$(echo "$plugin_url" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') && \
52
+ if [ -z "$plugin_url" ]; then continue; fi && \
53
+ # Extract plugin name
54
+ plugin_name_git=$(basename "$plugin_url") && \
55
+ plugin_name=${plugin_name_git%.git} && \
56
+ plugin_dir="./plugins/$plugin_name" && \
57
+ echo "--- Installing plugin: $plugin_name from $plugin_url into $plugin_dir ---" && \
58
+ # Remove existing dir if it exists
59
+ rm -rf "$plugin_dir" && \
60
+ # Clone the plugin (run as root, fix perms later)
61
+ git clone --depth 1 "$plugin_url" "$plugin_dir" && \
62
+ if [ -f "$plugin_dir/package.json" ]; then \
63
+ echo "--- Installing dependencies for $plugin_name ---" && \
64
+ (cd "$plugin_dir" && npm install --no-audit --no-fund --loglevel=error --no-progress --omit=dev --force && npm cache clean --force) || echo "WARN: Failed to install dependencies for $plugin_name"; \
65
+ else \
66
+ echo "--- No package.json found for $plugin_name, skipping dependency install. ---"; \
67
+ fi || echo "WARN: Failed to clone $plugin_name from $plugin_url, skipping..."; \
68
+ done && \
69
+ # Reset IFS
70
+ unset IFS && \
71
+ # Fix permissions for plugins directory after installation
72
+ echo "--- Setting permissions for plugins directory ---" && \
73
+ chown -R node:node ./plugins && \
74
+ echo "*** Plugin installation finished. ***"; \
75
+ else
76
+ echo 'PLUGINS environment variable is not set or empty, skipping runtime plugin installation.';
77
+ fi;
78
+ # --- END: Dynamically Install Plugins at Runtime ---
79
+
80
+ # --- BEGIN: Auto-configure cloud-saves plugin if secrets provided ---
81
+ echo '--- Checking for cloud-saves plugin auto-configuration ---';
82
+ if [ -d "./plugins/cloud-saves" ] && [ -n "$REPO_URL" ] && [ -n "$GITHUB_TOKEN" ]; then
83
+ echo "*** Auto-configuring cloud-saves plugin with provided secrets ***" && \
84
+ config_file="./plugins/cloud-saves/config.json" && \
85
+ echo "--- Creating config.json for cloud-saves plugin at $config_file ---" && \
86
+ # Note: autoSaveEnabled is now defaulted to false
87
+ printf '{\n "repo_url": "%s",\n "branch": "main",\n "username": "",\n "github_token": "%s",\n "display_name": "user",\n "is_authorized": true,\n "last_save": null,\n "current_save": null,\n "has_temp_stash": false,\n "autoSaveEnabled": false,\n "autoSaveInterval": %s,\n "autoSaveTargetTag": "%s"\n}\n' "$REPO_URL" "$GITHUB_TOKEN" "${AUTOSAVE_INTERVAL:-30}" "${AUTOSAVE_TARGET_TAG:-}" > "$config_file" && \
88
+ chown node:node "$config_file" && \
89
+ echo "*** cloud-saves plugin auto-configuration completed ***";
90
+ else
91
+ if [ ! -d "./plugins/cloud-saves" ]; then
92
+ echo 'cloud-saves plugin not found, skipping auto-configuration.';
93
+ elif [ -z "$REPO_URL" ] || [ -z "$GITHUB_TOKEN" ]; then
94
+ echo 'REPO_URL or GITHUB_TOKEN environment variables not provided, skipping cloud-saves auto-configuration.';
95
+ fi;
96
+ fi;
97
+ # --- END: Auto-configure cloud-saves plugin ---
98
+
99
+ # --- BEGIN: Dynamically Install Extensions at Runtime ---
100
+ echo '--- Checking for EXTENSIONS environment variable ---';
101
+ if [ -n "$EXTENSIONS" ]; then
102
+ echo "*** Installing Extensions specified in EXTENSIONS environment variable: $EXTENSIONS ***" && \
103
+ # Determine extension installation directory based on INSTALL_FOR_ALL_USERS
104
+ if [ "$INSTALL_FOR_ALL_USERS" = "true" ]; then
105
+ ext_install_dir="./public/scripts/extensions/third-party" && \
106
+ echo "--- Installing extensions for all users (system-wide) to $ext_install_dir ---";
107
+ else
108
+ ext_install_dir="./data/default-user/extensions" && \
109
+ echo "--- Installing extensions for default user only to $ext_install_dir ---";
110
+ fi && \
111
+ # Ensure extension directory exists
112
+ mkdir -p "$ext_install_dir" && chown node:node "$ext_install_dir" && \
113
+ # Set comma as delimiter
114
+ IFS=',' && \
115
+ # Loop through each extension URL
116
+ for ext_url in $EXTENSIONS; do \
117
+ # Trim leading/trailing whitespace
118
+ ext_url=$(echo "$ext_url" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') && \
119
+ if [ -z "$ext_url" ]; then continue; fi && \
120
+ # Extract extension name
121
+ ext_name_git=$(basename "$ext_url") && \
122
+ ext_name=${ext_name_git%.git} && \
123
+ ext_dir="$ext_install_dir/$ext_name" && \
124
+ echo "--- Installing extension: $ext_name from $ext_url into $ext_dir ---" && \
125
+ # Remove existing dir if it exists
126
+ rm -rf "$ext_dir" && \
127
+ # Clone the extension (run as root, fix perms later)
128
+ git clone --depth 1 "$ext_url" "$ext_dir" && \
129
+ if [ -f "$ext_dir/package.json" ]; then \
130
+ echo "--- Installing dependencies for extension $ext_name ---" && \
131
+ (cd "$ext_dir" && npm install --no-audit --no-fund --loglevel=error --no-progress --omit=dev --force && npm cache clean --force) || echo "WARN: Failed to install dependencies for extension $ext_name"; \
132
+ else \
133
+ echo "--- No package.json found for extension $ext_name, skipping dependency install. ---"; \
134
+ fi || echo "WARN: Failed to clone extension $ext_name from $ext_url, skipping..."; \
135
+ done && \
136
+ # Reset IFS
137
+ unset IFS && \
138
+ # Fix permissions for extensions directory after installation
139
+ echo "--- Setting permissions for extensions directory ---" && \
140
+ chown -R node:node "$ext_install_dir" && \
141
+ echo "*** Extension installation finished. ***"; \
142
+ else
143
+ echo 'EXTENSIONS environment variable is not set or empty, skipping runtime extension installation.';
144
+ fi;
145
+ # --- END: Dynamically Install Extensions at Runtime ---
146
+
147
+ # --- BEGIN: Cleanup before start ---
148
+ # Remove .gitignore (already done in build, but safety check)
149
+ echo 'Attempting final removal of .gitignore...'
150
+ rm -f .gitignore
151
+ if [ ! -e .gitignore ]; then
152
+ echo '.gitignore successfully removed (if it existed).'
153
+ else
154
+ echo 'WARN: .gitignore could not be removed or reappeared.'
155
+ fi;
156
+ # Remove .git directory (already done in build, but safety check)
157
+ echo 'Attempting final removal of .git directory...'
158
+ rm -rf .git
159
+ if [ ! -d .git ]; then
160
+ echo '.git directory successfully removed (if it existed).'
161
+ else
162
+ echo 'WARN: .git directory could not be removed.'
163
+ fi;
164
+ # --- END: Cleanup before start ---
165
+
166
+ echo 'Starting SillyTavern server in background...';
167
+ # Execute node server directly in the background
168
+ node server.js &
169
+
170
+ # Get the PID of the background node process
171
+ NODE_PID=$!
172
+
173
+ echo "SillyTavern server started with PID $NODE_PID. Waiting for it to become responsive..."
174
+
175
+ # Wait for SillyTavern to be responsive (Health Check)
176
+ until curl --output /dev/null --silent --head --fail http://localhost:8000/; do
177
+ echo "SillyTavern is still starting or not responsive on port 8000, waiting 5 seconds..."
178
+ # Check if the node process is still running while waiting
179
+ if ! kill -0 $NODE_PID 2>/dev/null; then
180
+ echo "ERROR: SillyTavern node process (PID $NODE_PID) has exited unexpectedly."
181
+ exit 1
182
+ fi
183
+ sleep 5
184
+ done
185
+
186
+ echo "SillyTavern started successfully! Beginning periodic keep-alive..."
187
+
188
+ # Periodic Keep-Alive Loop
189
+ while true; do
190
+ echo "Sending keep-alive request to http://localhost:8000/"
191
+ # Send a simple GET request. Don't care about the output.
192
+ curl http://localhost:8000/ > /dev/null 2>&1
193
+ echo "Keep-alive request sent. Sleeping for 30 minutes."
194
+ sleep 1800 # Sleep for 30 minutes (30 * 60 = 1800 seconds)
195
+ done
196
+
197
+ # The script will ideally never reach here because of the infinite loop.
198
+ # However, if the loop somehow breaks or the node process exits,
199
+ # we might want to handle that. For now, the health check loop includes
200
+ # a check if the node process is still alive.
201
+ wait $NODE_PID # Wait for the node process if the loop ever exits (unlikely)