nterminal 1.2.15 → 1.2.17
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/README.md +1 -0
- package/bin/nterminal.js +1 -0
- package/dist/client/assets/{MarkdownPreview-CPwwNmWh.js → MarkdownPreview-fAU63YUT.js} +1 -1
- package/dist/client/assets/{index-BgwRhgr0.js → index-CzfRb88C.js} +24 -24
- package/dist/client/index.html +1 -1
- package/dist/server/agent/agentProxy.d.ts +1 -0
- package/dist/server/agent/agentProxy.js +3 -0
- package/dist/server/agent/agentProxy.js.map +1 -1
- package/dist/server/routes/agentManagementRoutes.js +75 -4
- package/dist/server/routes/agentManagementRoutes.js.map +1 -1
- package/dist/server/storage/fileStore.d.ts +1 -0
- package/dist/server/storage/fileStore.js +17 -2
- package/dist/server/storage/fileStore.js.map +1 -1
- package/dist/server/update/manualUpdateState.d.ts +3 -0
- package/dist/server/update/manualUpdateState.js +21 -0
- package/dist/server/update/manualUpdateState.js.map +1 -1
- package/dist/server/update/packageUpdate.d.ts +0 -1
- package/dist/server/update/packageUpdate.js +4 -14
- package/dist/server/update/packageUpdate.js.map +1 -1
- package/dist/shared/manualUpdate.d.ts +4 -0
- package/dist/shared/manualUpdate.js +13 -0
- package/dist/shared/manualUpdate.js.map +1 -0
- package/docs/configuration.md +1 -0
- package/docs/onboarding.md +1 -1
- package/docs/operations.md +2 -2
- package/package.json +1 -1
- package/scripts/nterminalctl +253 -53
package/scripts/nterminalctl
CHANGED
|
@@ -68,6 +68,7 @@ load_env_file
|
|
|
68
68
|
|
|
69
69
|
DEFAULT_STATE_PATH="$DEFAULT_RUNTIME_DIR/state.json"
|
|
70
70
|
DEFAULT_PID_PATH="$DEFAULT_RUNTIME_DIR/nterminal.pid"
|
|
71
|
+
DEFAULT_MONITOR_PID_PATH="$DEFAULT_RUNTIME_DIR/nterminal.monitor.pid"
|
|
71
72
|
DEFAULT_LOG_PATH="$DEFAULT_RUNTIME_DIR/nterminal.log"
|
|
72
73
|
|
|
73
74
|
HOST="${NTERMINAL_HOST:-127.0.0.1}"
|
|
@@ -75,6 +76,7 @@ PORT="${NTERMINAL_PORT:-3107}"
|
|
|
75
76
|
NODE_BIN="${NTERMINAL_NODE_BIN:-node}"
|
|
76
77
|
NPM_BIN="${NTERMINAL_NPM_BIN:-npm}"
|
|
77
78
|
PID_PATH="$(resolve_path "${NTERMINAL_PID_PATH:-${NTERMINAL_RUNTIME_PID_PATH:-$DEFAULT_PID_PATH}}")"
|
|
79
|
+
MONITOR_PID_PATH="$(resolve_path "${NTERMINAL_MONITOR_PID_PATH:-${NTERMINAL_RUNTIME_MONITOR_PID_PATH:-$DEFAULT_MONITOR_PID_PATH}}")"
|
|
78
80
|
LOG_PATH="$(resolve_path "${NTERMINAL_LOG_PATH:-${NTERMINAL_RUNTIME_LOG_PATH:-$DEFAULT_LOG_PATH}}")"
|
|
79
81
|
STATE_PATH="$(resolve_path "${NTERMINAL_STATE_PATH:-${NTERMINAL_RUNTIME_STATE_PATH:-$DEFAULT_STATE_PATH}}")"
|
|
80
82
|
HEALTH_TIMEOUT_SECONDS="${NTERMINAL_HEALTH_TIMEOUT_SECONDS:-15}"
|
|
@@ -100,6 +102,7 @@ export NTERMINAL_APP_DIR="$APP_DIR"
|
|
|
100
102
|
export NTERMINAL_ENV_FILE="$ENV_FILE"
|
|
101
103
|
export NTERMINAL_STATE_PATH="$STATE_PATH"
|
|
102
104
|
export NTERMINAL_PID_PATH="$PID_PATH"
|
|
105
|
+
export NTERMINAL_MONITOR_PID_PATH="$MONITOR_PID_PATH"
|
|
103
106
|
export NTERMINAL_LOG_PATH="$LOG_PATH"
|
|
104
107
|
|
|
105
108
|
health_url() {
|
|
@@ -130,7 +133,7 @@ ensure_runtime() {
|
|
|
130
133
|
}
|
|
131
134
|
|
|
132
135
|
ensure_directories() {
|
|
133
|
-
mkdir -p "$(dirname "$PID_PATH")" "$(dirname "$LOG_PATH")"
|
|
136
|
+
mkdir -p "$(dirname "$PID_PATH")" "$(dirname "$MONITOR_PID_PATH")" "$(dirname "$LOG_PATH")"
|
|
134
137
|
: >> "$LOG_PATH"
|
|
135
138
|
chmod 600 "$LOG_PATH" 2>/dev/null || true
|
|
136
139
|
}
|
|
@@ -152,6 +155,11 @@ read_pid() {
|
|
|
152
155
|
read_pid_file "$PID_PATH"
|
|
153
156
|
}
|
|
154
157
|
|
|
158
|
+
read_monitor_pid() {
|
|
159
|
+
[[ -f "$MONITOR_PID_PATH" ]] || return 1
|
|
160
|
+
read_pid_file "$MONITOR_PID_PATH"
|
|
161
|
+
}
|
|
162
|
+
|
|
155
163
|
read_pid_file() {
|
|
156
164
|
local pid_path="$1"
|
|
157
165
|
[[ -f "$pid_path" ]] || return 1
|
|
@@ -166,6 +174,19 @@ is_running() {
|
|
|
166
174
|
kill -0 "$pid" 2>/dev/null
|
|
167
175
|
}
|
|
168
176
|
|
|
177
|
+
parent_pid() {
|
|
178
|
+
local pid="$1"
|
|
179
|
+
if [[ -r "/proc/$pid/status" ]]; then
|
|
180
|
+
awk '/^PPid:/ { print $2; exit }' "/proc/$pid/status" 2>/dev/null
|
|
181
|
+
return
|
|
182
|
+
fi
|
|
183
|
+
if command -v ps >/dev/null 2>&1; then
|
|
184
|
+
ps -o ppid= -p "$pid" 2>/dev/null | tr -d '[:space:]'
|
|
185
|
+
return
|
|
186
|
+
fi
|
|
187
|
+
return 1
|
|
188
|
+
}
|
|
189
|
+
|
|
169
190
|
pid_controls_app() {
|
|
170
191
|
local pid="$1"
|
|
171
192
|
is_running "$pid" || return 1
|
|
@@ -176,7 +197,6 @@ pid_controls_app() {
|
|
|
176
197
|
local cwd=""
|
|
177
198
|
cwd="$(readlink "/proc/$pid/cwd" 2>/dev/null || true)"
|
|
178
199
|
if [[ "$cmdline" == *"$RUNTIME_ENTRY"* ]]; then
|
|
179
|
-
[[ -z "$cwd" || "$cwd" == "$APP_DIR" ]] || return 1
|
|
180
200
|
return 0
|
|
181
201
|
fi
|
|
182
202
|
if [[ "$cwd" == "$APP_DIR" && "$cmdline" == *"dist/server/index.js"* ]]; then
|
|
@@ -194,6 +214,26 @@ pid_controls_app() {
|
|
|
194
214
|
return 1
|
|
195
215
|
}
|
|
196
216
|
|
|
217
|
+
monitor_controls_app() {
|
|
218
|
+
local pid="$1"
|
|
219
|
+
is_running "$pid" || return 1
|
|
220
|
+
|
|
221
|
+
local cmdline=""
|
|
222
|
+
if [[ -r "/proc/$pid/cmdline" ]]; then
|
|
223
|
+
cmdline="$(tr '\0' ' ' < "/proc/$pid/cmdline" 2>/dev/null || true)"
|
|
224
|
+
[[ "$cmdline" == *"$SCRIPT_DIR/nterminalctl"* && "$cmdline" == *" supervise"* ]]
|
|
225
|
+
return
|
|
226
|
+
fi
|
|
227
|
+
|
|
228
|
+
if command -v ps >/dev/null 2>&1; then
|
|
229
|
+
cmdline="$(ps -p "$pid" -o command= 2>/dev/null || true)"
|
|
230
|
+
[[ "$cmdline" == *"$SCRIPT_DIR/nterminalctl"* && "$cmdline" == *" supervise"* ]]
|
|
231
|
+
return
|
|
232
|
+
fi
|
|
233
|
+
|
|
234
|
+
return 1
|
|
235
|
+
}
|
|
236
|
+
|
|
197
237
|
current_pid() {
|
|
198
238
|
local pid
|
|
199
239
|
pid="$(read_pid || true)"
|
|
@@ -201,6 +241,35 @@ current_pid() {
|
|
|
201
241
|
printf '%s' "$pid"
|
|
202
242
|
return 0
|
|
203
243
|
fi
|
|
244
|
+
|
|
245
|
+
# npm can replace the package directory while the old Node process is still
|
|
246
|
+
# listening. If the pid file is missing, recover by recognizing the port owner
|
|
247
|
+
# as this package runtime before deciding the app is stopped.
|
|
248
|
+
pid="$(port_owner_pid || true)"
|
|
249
|
+
if [[ -n "$pid" && "$(pid_controls_app "$pid" && echo yes || echo no)" == yes ]]; then
|
|
250
|
+
printf '%s' "$pid"
|
|
251
|
+
return 0
|
|
252
|
+
fi
|
|
253
|
+
return 1
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
current_monitor_pid() {
|
|
257
|
+
local pid
|
|
258
|
+
pid="$(read_monitor_pid || true)"
|
|
259
|
+
if [[ -n "$pid" && "$(monitor_controls_app "$pid" && echo yes || echo no)" == yes ]]; then
|
|
260
|
+
printf '%s' "$pid"
|
|
261
|
+
return 0
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
local child_pid parent
|
|
265
|
+
child_pid="$(current_pid || true)"
|
|
266
|
+
if [[ -n "$child_pid" ]]; then
|
|
267
|
+
parent="$(parent_pid "$child_pid" || true)"
|
|
268
|
+
if [[ -n "$parent" && "$(monitor_controls_app "$parent" && echo yes || echo no)" == yes ]]; then
|
|
269
|
+
printf '%s' "$parent"
|
|
270
|
+
return 0
|
|
271
|
+
fi
|
|
272
|
+
fi
|
|
204
273
|
return 1
|
|
205
274
|
}
|
|
206
275
|
|
|
@@ -259,6 +328,14 @@ remove_stale_pid() {
|
|
|
259
328
|
fi
|
|
260
329
|
}
|
|
261
330
|
|
|
331
|
+
remove_stale_monitor_pid() {
|
|
332
|
+
local pid
|
|
333
|
+
pid="$(read_monitor_pid || true)"
|
|
334
|
+
if [[ -n "$pid" && ! "$(monitor_controls_app "$pid" && echo yes || echo no)" == yes ]]; then
|
|
335
|
+
rm -f "$MONITOR_PID_PATH"
|
|
336
|
+
fi
|
|
337
|
+
}
|
|
338
|
+
|
|
262
339
|
node_health_check() {
|
|
263
340
|
"$NODE_BIN" -e '
|
|
264
341
|
const http = require("node:http");
|
|
@@ -273,15 +350,90 @@ request.on("error", () => process.exit(1));
|
|
|
273
350
|
}
|
|
274
351
|
|
|
275
352
|
start_daemon() {
|
|
276
|
-
cd "$APP_DIR"
|
|
277
353
|
if command -v setsid >/dev/null 2>&1; then
|
|
278
|
-
nohup setsid
|
|
354
|
+
nohup setsid bash "$SCRIPT_DIR/nterminalctl" supervise >> "$LOG_PATH" 2>&1 &
|
|
279
355
|
else
|
|
280
|
-
nohup
|
|
356
|
+
nohup bash "$SCRIPT_DIR/nterminalctl" supervise >> "$LOG_PATH" 2>&1 &
|
|
281
357
|
fi
|
|
282
|
-
local
|
|
283
|
-
disown "$
|
|
284
|
-
echo "$
|
|
358
|
+
local monitor_pid="$!"
|
|
359
|
+
disown "$monitor_pid" 2>/dev/null || true
|
|
360
|
+
echo "$monitor_pid" > "$MONITOR_PID_PATH"
|
|
361
|
+
chmod 600 "$MONITOR_PID_PATH" 2>/dev/null || true
|
|
362
|
+
|
|
363
|
+
local pid=""
|
|
364
|
+
local deadline=$((SECONDS + HEALTH_TIMEOUT_SECONDS))
|
|
365
|
+
while (( SECONDS <= deadline )); do
|
|
366
|
+
if ! is_running "$monitor_pid"; then
|
|
367
|
+
return 1
|
|
368
|
+
fi
|
|
369
|
+
pid="$(current_pid || true)"
|
|
370
|
+
[[ -n "$pid" ]] && return 0
|
|
371
|
+
sleep 0.25
|
|
372
|
+
done
|
|
373
|
+
return 1
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
stop_supervised_child() {
|
|
377
|
+
local pid="$1"
|
|
378
|
+
[[ -n "$pid" ]] || return 0
|
|
379
|
+
if ! is_running "$pid"; then
|
|
380
|
+
rm -f "$PID_PATH"
|
|
381
|
+
return 0
|
|
382
|
+
fi
|
|
383
|
+
kill -TERM "$pid" 2>/dev/null || true
|
|
384
|
+
local deadline=$((SECONDS + STOP_TIMEOUT_SECONDS))
|
|
385
|
+
while (( SECONDS <= deadline )); do
|
|
386
|
+
if ! is_running "$pid"; then
|
|
387
|
+
rm -f "$PID_PATH"
|
|
388
|
+
return 0
|
|
389
|
+
fi
|
|
390
|
+
sleep 0.25
|
|
391
|
+
done
|
|
392
|
+
kill -KILL "$pid" 2>/dev/null || true
|
|
393
|
+
rm -f "$PID_PATH"
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
cmd_supervise() {
|
|
397
|
+
ensure_app_dir
|
|
398
|
+
ensure_env_file
|
|
399
|
+
ensure_runtime
|
|
400
|
+
validate_required_env || die "generate real secrets before starting"
|
|
401
|
+
ensure_directories
|
|
402
|
+
echo "$$" > "$MONITOR_PID_PATH"
|
|
403
|
+
chmod 600 "$MONITOR_PID_PATH" 2>/dev/null || true
|
|
404
|
+
|
|
405
|
+
local child_pid=""
|
|
406
|
+
local stop_requested=0
|
|
407
|
+
supervisor_shutdown() {
|
|
408
|
+
stop_requested=1
|
|
409
|
+
trap - TERM INT
|
|
410
|
+
stop_supervised_child "$child_pid"
|
|
411
|
+
rm -f "$MONITOR_PID_PATH"
|
|
412
|
+
exit 0
|
|
413
|
+
}
|
|
414
|
+
trap supervisor_shutdown TERM INT
|
|
415
|
+
|
|
416
|
+
while true; do
|
|
417
|
+
cd "$APP_DIR"
|
|
418
|
+
"$NODE_BIN" "$RUNTIME_ENTRY" >> "$LOG_PATH" 2>&1 &
|
|
419
|
+
child_pid="$!"
|
|
420
|
+
echo "$child_pid" > "$PID_PATH"
|
|
421
|
+
chmod 600 "$PID_PATH" 2>/dev/null || true
|
|
422
|
+
|
|
423
|
+
set +e
|
|
424
|
+
wait "$child_pid"
|
|
425
|
+
local status="$?"
|
|
426
|
+
set -e
|
|
427
|
+
|
|
428
|
+
rm -f "$PID_PATH"
|
|
429
|
+
if (( stop_requested == 1 )); then
|
|
430
|
+
rm -f "$MONITOR_PID_PATH"
|
|
431
|
+
exit 0
|
|
432
|
+
fi
|
|
433
|
+
|
|
434
|
+
printf '[%s] NTerminal process exited status=%s; restarting in 2s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$status" >> "$LOG_PATH"
|
|
435
|
+
sleep 2
|
|
436
|
+
done
|
|
285
437
|
}
|
|
286
438
|
|
|
287
439
|
start_launchd() {
|
|
@@ -321,8 +473,15 @@ wait_for_health() {
|
|
|
321
473
|
}
|
|
322
474
|
|
|
323
475
|
port_owner_pid() {
|
|
324
|
-
command -v lsof >/dev/null 2>&1
|
|
325
|
-
|
|
476
|
+
if command -v lsof >/dev/null 2>&1; then
|
|
477
|
+
lsof -nP -iTCP:"$PORT" -sTCP:LISTEN -t 2>/dev/null | head -n 1
|
|
478
|
+
return
|
|
479
|
+
fi
|
|
480
|
+
if command -v ss >/dev/null 2>&1; then
|
|
481
|
+
ss -ltnp "sport = :$PORT" 2>/dev/null | sed -n 's/.*pid=\([0-9]\+\).*/\1/p' | head -n 1
|
|
482
|
+
return
|
|
483
|
+
fi
|
|
484
|
+
return 1
|
|
326
485
|
}
|
|
327
486
|
|
|
328
487
|
assert_port_available() {
|
|
@@ -337,12 +496,19 @@ assert_port_available() {
|
|
|
337
496
|
|
|
338
497
|
cmd_status() {
|
|
339
498
|
remove_stale_pid
|
|
499
|
+
remove_stale_monitor_pid
|
|
340
500
|
local pid
|
|
341
501
|
pid="$(current_pid || true)"
|
|
342
502
|
if [[ -n "$pid" ]]; then
|
|
343
503
|
info "NTerminal running pid=$pid url=$(public_url) log=$LOG_PATH"
|
|
344
504
|
return 0
|
|
345
505
|
fi
|
|
506
|
+
local monitor_pid
|
|
507
|
+
monitor_pid="$(current_monitor_pid || true)"
|
|
508
|
+
if [[ -n "$monitor_pid" ]]; then
|
|
509
|
+
info "NTerminal supervisor running pid=$monitor_pid; server is restarting url=$(public_url) log=$LOG_PATH"
|
|
510
|
+
return 4
|
|
511
|
+
fi
|
|
346
512
|
info "NTerminal stopped pid_file=$PID_PATH"
|
|
347
513
|
return 3
|
|
348
514
|
}
|
|
@@ -354,6 +520,7 @@ cmd_start() {
|
|
|
354
520
|
validate_required_env || die "generate real secrets before starting"
|
|
355
521
|
ensure_directories
|
|
356
522
|
remove_stale_pid
|
|
523
|
+
remove_stale_monitor_pid
|
|
357
524
|
|
|
358
525
|
local pid
|
|
359
526
|
pid="$(current_pid || true)"
|
|
@@ -361,6 +528,12 @@ cmd_start() {
|
|
|
361
528
|
info "NTerminal already running pid=$pid url=$(public_url)"
|
|
362
529
|
return 0
|
|
363
530
|
fi
|
|
531
|
+
local monitor_pid
|
|
532
|
+
monitor_pid="$(current_monitor_pid || true)"
|
|
533
|
+
if [[ -n "$monitor_pid" ]]; then
|
|
534
|
+
info "NTerminal supervisor already running pid=$monitor_pid url=$(public_url)"
|
|
535
|
+
return 0
|
|
536
|
+
fi
|
|
364
537
|
|
|
365
538
|
if launchd_controls_app; then
|
|
366
539
|
start_launchd
|
|
@@ -368,12 +541,28 @@ cmd_start() {
|
|
|
368
541
|
fi
|
|
369
542
|
|
|
370
543
|
assert_port_available
|
|
371
|
-
start_daemon
|
|
544
|
+
if ! start_daemon; then
|
|
545
|
+
rm -f "$MONITOR_PID_PATH"
|
|
546
|
+
echo "NTerminal failed to start supervisor. Last log lines:" >&2
|
|
547
|
+
tail -n 40 "$LOG_PATH" >&2 || true
|
|
548
|
+
return 1
|
|
549
|
+
fi
|
|
372
550
|
chmod 600 "$PID_PATH" 2>/dev/null || true
|
|
373
|
-
pid="$(
|
|
551
|
+
pid="$(current_pid || true)"
|
|
552
|
+
if [[ -z "$pid" ]]; then
|
|
553
|
+
rm -f "$MONITOR_PID_PATH"
|
|
554
|
+
echo "NTerminal failed to start supervisor. Last log lines:" >&2
|
|
555
|
+
tail -n 40 "$LOG_PATH" >&2 || true
|
|
556
|
+
return 1
|
|
557
|
+
fi
|
|
374
558
|
|
|
375
559
|
if wait_for_health "$pid"; then
|
|
376
|
-
|
|
560
|
+
monitor_pid="$(current_monitor_pid || true)"
|
|
561
|
+
if [[ -n "$monitor_pid" ]]; then
|
|
562
|
+
info "NTerminal started pid=$pid supervisor=$monitor_pid url=$(public_url) log=$LOG_PATH"
|
|
563
|
+
else
|
|
564
|
+
info "NTerminal started pid=$pid url=$(public_url) log=$LOG_PATH"
|
|
565
|
+
fi
|
|
377
566
|
return 0
|
|
378
567
|
fi
|
|
379
568
|
|
|
@@ -381,7 +570,11 @@ cmd_start() {
|
|
|
381
570
|
if ! is_running "$pid"; then
|
|
382
571
|
exit_hint="process exited during startup"
|
|
383
572
|
fi
|
|
384
|
-
|
|
573
|
+
monitor_pid="$(current_monitor_pid || true)"
|
|
574
|
+
if [[ -n "$monitor_pid" ]]; then
|
|
575
|
+
kill -TERM "$monitor_pid" 2>/dev/null || true
|
|
576
|
+
fi
|
|
577
|
+
rm -f "$PID_PATH" "$MONITOR_PID_PATH"
|
|
385
578
|
echo "NTerminal $exit_hint. Last log lines:" >&2
|
|
386
579
|
tail -n 40 "$LOG_PATH" >&2 || true
|
|
387
580
|
return 1
|
|
@@ -389,13 +582,44 @@ cmd_start() {
|
|
|
389
582
|
|
|
390
583
|
cmd_stop() {
|
|
391
584
|
remove_stale_pid
|
|
585
|
+
remove_stale_monitor_pid
|
|
392
586
|
local pid
|
|
393
587
|
pid="$(current_pid || true)"
|
|
394
|
-
|
|
588
|
+
local monitor_pid
|
|
589
|
+
monitor_pid="$(current_monitor_pid || true)"
|
|
590
|
+
if [[ -z "$pid" && -z "$monitor_pid" ]]; then
|
|
395
591
|
info "NTerminal already stopped"
|
|
396
592
|
return 0
|
|
397
593
|
fi
|
|
398
594
|
|
|
595
|
+
if [[ -n "$monitor_pid" ]]; then
|
|
596
|
+
kill -TERM "$monitor_pid" 2>/dev/null || true
|
|
597
|
+
local monitor_deadline=$((SECONDS + STOP_TIMEOUT_SECONDS))
|
|
598
|
+
while (( SECONDS <= monitor_deadline )); do
|
|
599
|
+
if ! is_running "$monitor_pid"; then
|
|
600
|
+
rm -f "$MONITOR_PID_PATH"
|
|
601
|
+
break
|
|
602
|
+
fi
|
|
603
|
+
sleep 0.25
|
|
604
|
+
done
|
|
605
|
+
if is_running "$monitor_pid"; then
|
|
606
|
+
kill -KILL "$monitor_pid" 2>/dev/null || true
|
|
607
|
+
rm -f "$MONITOR_PID_PATH"
|
|
608
|
+
fi
|
|
609
|
+
|
|
610
|
+
if [[ -n "$pid" && "$(is_running "$pid" && echo yes || echo no)" == yes ]]; then
|
|
611
|
+
stop_supervised_child "$pid"
|
|
612
|
+
fi
|
|
613
|
+
|
|
614
|
+
rm -f "$PID_PATH" "$MONITOR_PID_PATH"
|
|
615
|
+
if [[ -n "$pid" ]]; then
|
|
616
|
+
info "NTerminal stopped pid=$pid supervisor=$monitor_pid"
|
|
617
|
+
else
|
|
618
|
+
info "NTerminal stopped supervisor=$monitor_pid"
|
|
619
|
+
fi
|
|
620
|
+
return 0
|
|
621
|
+
fi
|
|
622
|
+
|
|
399
623
|
kill -TERM "$pid" 2>/dev/null || true
|
|
400
624
|
local deadline=$((SECONDS + STOP_TIMEOUT_SECONDS))
|
|
401
625
|
while (( SECONDS <= deadline )); do
|
|
@@ -453,43 +677,17 @@ cmd_logs() {
|
|
|
453
677
|
fi
|
|
454
678
|
}
|
|
455
679
|
|
|
456
|
-
stop_pid_file() {
|
|
457
|
-
local pid_path="$1"
|
|
458
|
-
local pid
|
|
459
|
-
pid="$(read_pid_file "$pid_path" || true)"
|
|
460
|
-
if [[ -z "$pid" ]]; then
|
|
461
|
-
return 0
|
|
462
|
-
fi
|
|
463
|
-
if ! is_running "$pid"; then
|
|
464
|
-
rm -f "$pid_path"
|
|
465
|
-
return 0
|
|
466
|
-
fi
|
|
467
|
-
if ! pid_controls_app "$pid"; then
|
|
468
|
-
rm -f "$pid_path"
|
|
469
|
-
return 0
|
|
470
|
-
fi
|
|
471
|
-
|
|
472
|
-
kill -TERM "$pid" 2>/dev/null || true
|
|
473
|
-
local deadline=$((SECONDS + STOP_TIMEOUT_SECONDS))
|
|
474
|
-
while (( SECONDS <= deadline )); do
|
|
475
|
-
if ! is_running "$pid"; then
|
|
476
|
-
rm -f "$pid_path"
|
|
477
|
-
return 0
|
|
478
|
-
fi
|
|
479
|
-
sleep 0.25
|
|
480
|
-
done
|
|
481
|
-
|
|
482
|
-
kill -KILL "$pid" 2>/dev/null || true
|
|
483
|
-
rm -f "$pid_path"
|
|
484
|
-
}
|
|
485
|
-
|
|
486
680
|
clean_state_paths() {
|
|
487
681
|
local state_path="$1"
|
|
488
682
|
local pid_path="$2"
|
|
489
683
|
local log_path="$3"
|
|
684
|
+
local monitor_pid_path="${4:-}"
|
|
490
685
|
local state_dir
|
|
491
686
|
state_dir="$(dirname "$state_path")"
|
|
492
687
|
rm -f "$state_path" "$pid_path" "$log_path" "$state_dir/update.lock"
|
|
688
|
+
if [[ -n "$monitor_pid_path" ]]; then
|
|
689
|
+
rm -f "$monitor_pid_path"
|
|
690
|
+
fi
|
|
493
691
|
rm -rf "$state_dir/notification-assets"
|
|
494
692
|
}
|
|
495
693
|
|
|
@@ -519,7 +717,7 @@ cmd_clean() {
|
|
|
519
717
|
|
|
520
718
|
local state_dir
|
|
521
719
|
state_dir="$(dirname "$STATE_PATH")"
|
|
522
|
-
clean_state_paths "$STATE_PATH" "$PID_PATH" "$LOG_PATH"
|
|
720
|
+
clean_state_paths "$STATE_PATH" "$PID_PATH" "$LOG_PATH" "$MONITOR_PID_PATH"
|
|
523
721
|
if (( remove_env == 1 )); then
|
|
524
722
|
rm -f "$ENV_FILE"
|
|
525
723
|
fi
|
|
@@ -545,11 +743,11 @@ cmd_uninstall() {
|
|
|
545
743
|
|
|
546
744
|
ensure_app_dir
|
|
547
745
|
unload_launchd_if_controlled
|
|
548
|
-
|
|
746
|
+
cmd_stop >/dev/null
|
|
549
747
|
if (( kill_tmux == 1 )) && command -v tmux >/dev/null 2>&1; then
|
|
550
748
|
tmux -L nterminal kill-server >/dev/null 2>&1 || true
|
|
551
749
|
fi
|
|
552
|
-
clean_state_paths "$STATE_PATH" "$PID_PATH" "$LOG_PATH"
|
|
750
|
+
clean_state_paths "$STATE_PATH" "$PID_PATH" "$LOG_PATH" "$MONITOR_PID_PATH"
|
|
553
751
|
rm -f "$ENV_FILE"
|
|
554
752
|
remove_owned_launchd_plist
|
|
555
753
|
|
|
@@ -610,10 +808,10 @@ cmd_doctor() {
|
|
|
610
808
|
fi
|
|
611
809
|
|
|
612
810
|
ensure_directories
|
|
613
|
-
if [[ -w "$(dirname "$PID_PATH")" && -w "$(dirname "$LOG_PATH")" ]]; then
|
|
614
|
-
echo "ok writable: pid/log directories"
|
|
811
|
+
if [[ -w "$(dirname "$PID_PATH")" && -w "$(dirname "$MONITOR_PID_PATH")" && -w "$(dirname "$LOG_PATH")" ]]; then
|
|
812
|
+
echo "ok writable: pid/monitor/log directories"
|
|
615
813
|
else
|
|
616
|
-
echo "fail writable: pid/log directories"
|
|
814
|
+
echo "fail writable: pid/monitor/log directories"
|
|
617
815
|
failed=1
|
|
618
816
|
fi
|
|
619
817
|
|
|
@@ -635,9 +833,9 @@ cmd_help() {
|
|
|
635
833
|
Usage: nterminal <command>
|
|
636
834
|
|
|
637
835
|
Commands:
|
|
638
|
-
status Show process status. Exit 0 when running, 3 when stopped.
|
|
836
|
+
status Show process status. Exit 0 when running, 3 when stopped, 4 when the supervisor is restarting it.
|
|
639
837
|
start Start the built server in the background.
|
|
640
|
-
stop Stop the managed server with SIGTERM, then SIGKILL after timeout.
|
|
838
|
+
stop Stop the managed server and supervisor with SIGTERM, then SIGKILL after timeout.
|
|
641
839
|
restart Stop and start the server.
|
|
642
840
|
build No-op for package installs; verifies the bundled runtime exists.
|
|
643
841
|
deploy Restart the installed package using the bundled runtime.
|
|
@@ -658,6 +856,7 @@ Environment:
|
|
|
658
856
|
NTERMINAL_ENV_FILE Override .env path.
|
|
659
857
|
NTERMINAL_STATE_PATH Default ~/.nterminal/state.json.
|
|
660
858
|
NTERMINAL_PID_PATH Default ~/.nterminal/nterminal.pid.
|
|
859
|
+
NTERMINAL_MONITOR_PID_PATH Default ~/.nterminal/nterminal.monitor.pid.
|
|
661
860
|
NTERMINAL_LOG_PATH Default ~/.nterminal/nterminal.log.
|
|
662
861
|
NTERMINAL_HEALTH_TIMEOUT_SECONDS Default 15.
|
|
663
862
|
NTERMINAL_STOP_TIMEOUT_SECONDS Default 20.
|
|
@@ -668,6 +867,7 @@ EOF
|
|
|
668
867
|
case "$COMMAND" in
|
|
669
868
|
status) cmd_status "$@" ;;
|
|
670
869
|
start) cmd_start "$@" ;;
|
|
870
|
+
supervise) cmd_supervise "$@" ;;
|
|
671
871
|
stop) cmd_stop "$@" ;;
|
|
672
872
|
restart|reload) cmd_restart "$@" ;;
|
|
673
873
|
build) cmd_build "$@" ;;
|