@lark-apaas/fullstack-cli 1.1.9-alpha.0 → 1.1.9
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 +2 -2
- package/templates/scripts/dev.sh +231 -31
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lark-apaas/fullstack-cli",
|
|
3
|
-
"version": "1.1.9
|
|
3
|
+
"version": "1.1.9",
|
|
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.
|
|
34
|
+
"@lark-apaas/devtool-kits": "^1.2.12",
|
|
35
35
|
"@vercel/nft": "^0.30.3",
|
|
36
36
|
"cac": "^6.7.14",
|
|
37
37
|
"dotenv": "^16.0.0",
|
package/templates/scripts/dev.sh
CHANGED
|
@@ -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 -
|
|
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
|
-
#
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|