@lark-apaas/fullstack-cli 1.1.9-alpha.0 → 1.1.9-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/fullstack-cli",
3
- "version": "1.1.9-alpha.0",
3
+ "version": "1.1.9-alpha.1",
4
4
  "description": "CLI tool for fullstack template management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -31,7 +31,7 @@
31
31
  "access": "public"
32
32
  },
33
33
  "dependencies": {
34
- "@lark-apaas/devtool-kits": "^1.2.11",
34
+ "@lark-apaas/devtool-kits": "1.2.12-alpha.0",
35
35
  "@vercel/nft": "^0.30.3",
36
36
  "cac": "^6.7.14",
37
37
  "dotenv": "^16.0.0",
@@ -1,41 +1,241 @@
1
1
  #!/usr/bin/env bash
2
2
  # This file is auto-generated by @lark-apaas/fullstack-cli
3
3
 
4
- set -euo pipefail
4
+ set -uo pipefail
5
5
 
6
6
  # Ensure the script always runs from the project root
7
7
  cd "$(dirname "${BASH_SOURCE[0]}")/.."
8
8
 
9
- # Split and clean logs for server and client
10
- split_logs() {
11
- local log_dir=$1
12
-
13
- awk -v server_log="${log_dir}/server.std.log" -v client_log="${log_dir}/client.std.log" '
14
- {
15
- # Remove all ANSI escape sequences (not just colors)
16
- gsub(/\x1b\[[0-9;]*[a-zA-Z]/, "") # CSI sequences (colors, cursor movement, etc.)
17
- gsub(/\x1b\][^\x07]*\x07/, "") # OSC sequences
18
- gsub(/\x1b[=>]/, "") # Other escape sequences
19
-
20
- # Write to appropriate log file and stdout
21
- if ($0 ~ /\[server\]/) {
22
- print $0 >> server_log
23
- fflush(server_log)
24
- } else if ($0 ~ /\[client\]/) {
25
- print $0 >> client_log
26
- fflush(client_log)
27
- }
28
-
29
- # Always print to stdout (terminal)
30
- print $0
31
- fflush()
32
- }
33
- '
34
- }
35
-
9
+ # Configuration
36
10
  LOG_DIR=${LOG_DIR:-logs}
11
+ DEV_LOG="${LOG_DIR}/dev.log"
12
+ MAX_RESTART_COUNT=${MAX_RESTART_COUNT:-10}
13
+ RESTART_DELAY=${RESTART_DELAY:-2}
14
+
15
+ # Process tracking
16
+ SERVER_PID=""
17
+ CLIENT_PID=""
18
+ PARENT_PID=$$
19
+ STOP_FLAG_FILE="/tmp/dev_sh_stop_$$"
20
+ CLEANUP_DONE=false
21
+
37
22
  mkdir -p "${LOG_DIR}"
38
23
 
39
- concurrently -p "[{time}] [{name}]" -t "yyyy-MM-dd HH:mm:ss" -n "server,client" -c "blue,green" \
40
- "npm run dev:server" \
41
- "npm run dev:client" 2>&1 | split_logs "${LOG_DIR}"
24
+ # Log event to dev.log with timestamp
25
+ log_event() {
26
+ local level=$1
27
+ local process_name=$2
28
+ local message=$3
29
+ local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [${level}] [${process_name}] ${message}"
30
+ echo "$msg"
31
+ echo "$msg" >> "${DEV_LOG}"
32
+ }
33
+
34
+ # Check if PID is valid (positive integer and process exists)
35
+ is_valid_pid() {
36
+ local pid=$1
37
+ [[ -n "$pid" ]] && [[ "$pid" =~ ^[0-9]+$ ]] && [[ "$pid" -gt 0 ]] && kill -0 "$pid" 2>/dev/null
38
+ }
39
+
40
+ # Check if parent process is still alive
41
+ is_parent_alive() {
42
+ kill -0 "$PARENT_PID" 2>/dev/null
43
+ }
44
+
45
+ # Check if should stop (parent exited or stop flag exists)
46
+ should_stop() {
47
+ [[ -f "$STOP_FLAG_FILE" ]] || ! is_parent_alive
48
+ }
49
+
50
+ # Kill entire process tree (process and all descendants)
51
+ kill_tree() {
52
+ local pid=$1
53
+ local signal=${2:-TERM}
54
+
55
+ # Get all descendant PIDs
56
+ local children
57
+ children=$(pgrep -P "$pid" 2>/dev/null) || true
58
+
59
+ # Recursively kill children first
60
+ for child in $children; do
61
+ kill_tree "$child" "$signal"
62
+ done
63
+
64
+ # Kill the process itself
65
+ if kill -0 "$pid" 2>/dev/null; then
66
+ kill -"$signal" "$pid" 2>/dev/null || true
67
+ fi
68
+ }
69
+
70
+ # Start a process with supervision
71
+ # $1: name
72
+ # $2: command
73
+ # $3: cleanup port for orphan processes (optional)
74
+ start_supervised_process() {
75
+ local name=$1
76
+ local cmd=$2
77
+ local cleanup_port=${3:-""}
78
+ local log_file="${LOG_DIR}/${name}.std.log"
79
+
80
+ (
81
+ local restart_count=0
82
+ local child_pid=""
83
+ local max_delay=60 # Maximum delay in seconds
84
+
85
+ # Handle signals to kill child process tree
86
+ trap 'if [[ -n "$child_pid" ]]; then kill_tree "$child_pid" TERM; fi' TERM INT
87
+
88
+ while true; do
89
+ # Check if we should stop (parent exited or stop flag)
90
+ if should_stop; then
91
+ log_event "INFO" "$name" "Process stopped (parent exited or user requested)"
92
+ break
93
+ fi
94
+
95
+ # Start command in background and capture output with timestamps
96
+ eval "$cmd" > >(
97
+ while IFS= read -r line; do
98
+ local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [${name}] ${line}"
99
+ echo "$msg"
100
+ echo "$msg" >> "$log_file"
101
+ done
102
+ ) 2>&1 &
103
+ child_pid=$!
104
+
105
+ log_event "INFO" "$name" "Process started (PID: ${child_pid}): ${cmd}"
106
+
107
+ # Wait for child to exit
108
+ set +e
109
+ wait "$child_pid"
110
+ exit_code=$?
111
+ set -e
112
+
113
+ # Kill entire process tree to avoid orphans
114
+ if [[ -n "$child_pid" ]]; then
115
+ kill_tree "$child_pid" TERM
116
+ sleep 0.5
117
+ kill_tree "$child_pid" KILL
118
+ fi
119
+ child_pid=""
120
+
121
+ # Cleanup orphan processes by port (for processes that escaped kill_tree)
122
+ if [[ -n "$cleanup_port" ]]; then
123
+ local orphan_pids
124
+ orphan_pids=$(lsof -ti ":${cleanup_port}" 2>/dev/null) || true
125
+ if [[ -n "$orphan_pids" ]]; then
126
+ log_event "WARN" "$name" "Killing orphan processes on port ${cleanup_port}: $(echo $orphan_pids | tr '\n' ' ')"
127
+ echo "$orphan_pids" | xargs kill -9 2>/dev/null || true
128
+ sleep 0.5
129
+ fi
130
+ fi
131
+
132
+ # Check if we should stop (parent exited or stop flag)
133
+ if should_stop; then
134
+ log_event "INFO" "$name" "Process stopped (parent exited or user requested)"
135
+ break
136
+ fi
137
+
138
+ # Process exited unexpectedly, restart
139
+ restart_count=$((restart_count + 1))
140
+
141
+ if [[ $restart_count -ge $MAX_RESTART_COUNT ]]; then
142
+ log_event "ERROR" "$name" "Max restart count (${MAX_RESTART_COUNT}) reached, giving up"
143
+ break
144
+ fi
145
+
146
+ # Exponential backoff: delay = RESTART_DELAY * 2^(restart_count-1), capped at max_delay
147
+ local delay=$((RESTART_DELAY * (1 << (restart_count - 1))))
148
+ if [[ $delay -gt $max_delay ]]; then
149
+ delay=$max_delay
150
+ fi
151
+
152
+ log_event "WARN" "$name" "Process exited with code ${exit_code}, restarting (${restart_count}/${MAX_RESTART_COUNT}) in ${delay}s..."
153
+ sleep "$delay"
154
+ done
155
+ ) &
156
+ }
157
+
158
+ # Cleanup function
159
+ cleanup() {
160
+ # Prevent multiple cleanup calls
161
+ if [[ "$CLEANUP_DONE" == "true" ]]; then
162
+ return
163
+ fi
164
+ CLEANUP_DONE=true
165
+
166
+ log_event "INFO" "main" "Shutting down all processes..."
167
+
168
+ # Create stop flag to signal child processes
169
+ touch "$STOP_FLAG_FILE"
170
+
171
+ # Kill entire process trees (TERM first)
172
+ for pid in $SERVER_PID $CLIENT_PID; do
173
+ if is_valid_pid "$pid"; then
174
+ log_event "INFO" "main" "Stopping process tree (PID: ${pid})"
175
+ kill_tree "$pid" TERM
176
+ fi
177
+ done
178
+
179
+ # Kill any remaining background jobs
180
+ local bg_pids
181
+ bg_pids=$(jobs -p 2>/dev/null) || true
182
+ if [[ -n "$bg_pids" ]]; then
183
+ for pid in $bg_pids; do
184
+ kill_tree "$pid" TERM
185
+ done
186
+ fi
187
+
188
+ # Wait for processes to terminate
189
+ sleep 1
190
+
191
+ # Force kill if still running
192
+ for pid in $SERVER_PID $CLIENT_PID; do
193
+ if is_valid_pid "$pid"; then
194
+ log_event "WARN" "main" "Force killing process tree (PID: ${pid})"
195
+ kill_tree "$pid" KILL
196
+ fi
197
+ done
198
+
199
+ # Cleanup stop flag
200
+ rm -f "$STOP_FLAG_FILE"
201
+
202
+ log_event "INFO" "main" "All processes stopped"
203
+ }
204
+
205
+ # Set up signal handlers
206
+ trap cleanup EXIT INT TERM HUP
207
+
208
+ # Remove any stale stop flag
209
+ rm -f "$STOP_FLAG_FILE"
210
+
211
+ # Initialize dev.log
212
+ echo "" >> "${DEV_LOG}"
213
+ log_event "INFO" "main" "========== Dev session started =========="
214
+
215
+ # Initialize action plugins before starting dev servers
216
+ echo "🔌 Initializing action plugins..."
217
+ if npx fullstack-cli action-plugin init; then
218
+ echo "✅ Action plugins initialized"
219
+ else
220
+ echo "⚠️ Action plugin initialization failed, continuing anyway..."
221
+ fi
222
+ echo ""
223
+
224
+ # Start server (cleanup orphan processes on SERVER_PORT)
225
+ start_supervised_process "server" "npm run dev:server" "${SERVER_PORT:-3000}"
226
+ SERVER_PID=$!
227
+ log_event "INFO" "server" "Supervisor started with PID ${SERVER_PID}"
228
+
229
+ # Start client (cleanup orphan processes on CLIENT_DEV_PORT)
230
+ start_supervised_process "client" "npm run dev:client" "${CLIENT_DEV_PORT:-8080}"
231
+ CLIENT_PID=$!
232
+ log_event "INFO" "client" "Supervisor started with PID ${CLIENT_PID}"
233
+
234
+ log_event "INFO" "main" "All processes started, monitoring..."
235
+ echo ""
236
+ echo "📋 Dev processes running. Press Ctrl+C to stop."
237
+ echo "📄 Logs: ${DEV_LOG}"
238
+ echo ""
239
+
240
+ # Wait for all background processes
241
+ wait