easy-devops 0.1.0

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.
Files changed (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +325 -0
  3. package/cli/index.js +91 -0
  4. package/cli/managers/domain-manager.js +451 -0
  5. package/cli/managers/nginx-manager.js +329 -0
  6. package/cli/managers/node-manager.js +275 -0
  7. package/cli/managers/ssl-manager.js +397 -0
  8. package/cli/menus/.gitkeep +0 -0
  9. package/cli/menus/dashboard.js +223 -0
  10. package/cli/menus/domains.js +5 -0
  11. package/cli/menus/nginx.js +5 -0
  12. package/cli/menus/nodejs.js +5 -0
  13. package/cli/menus/settings.js +83 -0
  14. package/cli/menus/ssl.js +5 -0
  15. package/core/config.js +37 -0
  16. package/core/db.js +30 -0
  17. package/core/detector.js +257 -0
  18. package/core/nginx-conf-generator.js +309 -0
  19. package/core/shell.js +151 -0
  20. package/dashboard/lib/.gitkeep +0 -0
  21. package/dashboard/lib/cert-reader.js +59 -0
  22. package/dashboard/lib/domains-db.js +51 -0
  23. package/dashboard/lib/nginx-conf-generator.js +16 -0
  24. package/dashboard/lib/nginx-service.js +282 -0
  25. package/dashboard/public/js/app.js +486 -0
  26. package/dashboard/routes/.gitkeep +0 -0
  27. package/dashboard/routes/auth.js +30 -0
  28. package/dashboard/routes/domains.js +300 -0
  29. package/dashboard/routes/nginx.js +151 -0
  30. package/dashboard/routes/settings.js +78 -0
  31. package/dashboard/routes/ssl.js +105 -0
  32. package/dashboard/server.js +79 -0
  33. package/dashboard/views/index.ejs +327 -0
  34. package/dashboard/views/partials/domain-form.ejs +229 -0
  35. package/dashboard/views/partials/domains-panel.ejs +66 -0
  36. package/dashboard/views/partials/login.ejs +50 -0
  37. package/dashboard/views/partials/nginx-panel.ejs +90 -0
  38. package/dashboard/views/partials/overview.ejs +67 -0
  39. package/dashboard/views/partials/settings-panel.ejs +37 -0
  40. package/dashboard/views/partials/sidebar.ejs +45 -0
  41. package/dashboard/views/partials/ssl-panel.ejs +53 -0
  42. package/data/.gitkeep +0 -0
  43. package/install.bat +41 -0
  44. package/install.ps1 +653 -0
  45. package/install.sh +452 -0
  46. package/lib/installer/.gitkeep +0 -0
  47. package/lib/installer/detect.sh +88 -0
  48. package/lib/installer/node-versions.sh +109 -0
  49. package/lib/installer/nvm-bootstrap.sh +77 -0
  50. package/lib/installer/picker.sh +163 -0
  51. package/lib/installer/progress.sh +25 -0
  52. package/package.json +67 -0
package/install.sh ADDED
@@ -0,0 +1,452 @@
1
+ #!/usr/bin/env bash
2
+ # install.sh — Easy DevOps Bootstrap Installer (Linux / macOS)
3
+ #
4
+ # Usage:
5
+ # bash install.sh [OPTIONS]
6
+ #
7
+ # Options:
8
+ # --help, -h Print this help and exit 0
9
+ # --version VERSION Skip picker; use the specified Node.js version
10
+ # --keep-node Skip Node.js management; proceed to dependency install
11
+ #
12
+ # Exit codes:
13
+ # 0 Installation completed successfully
14
+ # 1 Unrecoverable error
15
+ # 2 User cancelled
16
+
17
+ set -euo pipefail
18
+
19
+ # ---------------------------------------------------------------------------
20
+ # Resolve script and project directory
21
+ # ---------------------------------------------------------------------------
22
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
23
+ EASYDEVOPS_DIR="${EASYDEVOPS_DIR:-$SCRIPT_DIR}"
24
+
25
+ # ---------------------------------------------------------------------------
26
+ # Source lib modules
27
+ # ---------------------------------------------------------------------------
28
+ LIB_DIR="$SCRIPT_DIR/lib/installer"
29
+
30
+ for _module in progress.sh detect.sh node-versions.sh picker.sh nvm-bootstrap.sh; do
31
+ if [ ! -f "$LIB_DIR/$_module" ]; then
32
+ printf 'Error: Required module not found: %s/%s\n' "$LIB_DIR" "$_module" >&2
33
+ exit 1
34
+ fi
35
+ # shellcheck source=/dev/null
36
+ . "$LIB_DIR/$_module"
37
+ done
38
+
39
+ # ---------------------------------------------------------------------------
40
+ # Result tracking (mirrors install.ps1 summary table)
41
+ # ---------------------------------------------------------------------------
42
+ _RESULT_NAMES=()
43
+ _RESULT_STATUS=() # "ok" or "fail"
44
+ _RESULT_DETAILS=()
45
+
46
+ add_result() {
47
+ local name="$1" ok="$2" detail="${3:-}"
48
+ _RESULT_NAMES+=("$name")
49
+ _RESULT_STATUS+=("$ok")
50
+ _RESULT_DETAILS+=("$detail")
51
+ }
52
+
53
+ # ---------------------------------------------------------------------------
54
+ # Error / cancellation helpers
55
+ # ---------------------------------------------------------------------------
56
+
57
+ # die <step_name> <reason> [recovery_cmd...]
58
+ die() {
59
+ local step="$1"
60
+ local reason="$2"
61
+ shift 2
62
+ step_failed "$step"
63
+ add_result "$step" "fail" "$reason"
64
+ printf '\nInstallation failed: %s. See above for details.\n' "$reason" >&2
65
+ if [ "$#" -gt 0 ]; then
66
+ printf '\nManual recovery:\n' >&2
67
+ local cmd
68
+ for cmd in "$@"; do
69
+ printf ' %s\n' "$cmd" >&2
70
+ done
71
+ fi
72
+ exit 1
73
+ }
74
+
75
+ # check_error <exit_code> <step_name> <reason> [recovery_cmd...]
76
+ check_error() {
77
+ local code="$1"
78
+ shift
79
+ if [ "$code" -ne 0 ]; then
80
+ die "$@"
81
+ fi
82
+ }
83
+
84
+ # ---------------------------------------------------------------------------
85
+ # --help flag
86
+ # ---------------------------------------------------------------------------
87
+ print_help() {
88
+ cat <<'EOF'
89
+ Easy DevOps Bootstrap Installer
90
+
91
+ Usage:
92
+ bash install.sh [OPTIONS]
93
+
94
+ Options:
95
+ --help, -h Print this help and exit
96
+ --version VERSION Skip the version picker; install the specified Node.js
97
+ version directly (e.g., --version 20.11.1)
98
+ --keep-node Skip Node.js management entirely; proceed straight to
99
+ dependency installation with whatever Node.js is active
100
+
101
+ Exit codes:
102
+ 0 Installation completed successfully
103
+ 1 Unrecoverable error (network failure, permission denied, etc.)
104
+ 2 User cancelled / aborted at a prompt
105
+
106
+ Examples:
107
+ bash install.sh # Interactive install
108
+ bash install.sh --version 20 # Install Node.js 20.x (latest patch)
109
+ bash install.sh --keep-node # Skip Node.js management
110
+ EOF
111
+ }
112
+
113
+ # ---------------------------------------------------------------------------
114
+ # Parse CLI flags
115
+ # ---------------------------------------------------------------------------
116
+ FORCED_VERSION=""
117
+ KEEP_NODE=false
118
+
119
+ while [ "$#" -gt 0 ]; do
120
+ case "$1" in
121
+ --help|-h)
122
+ print_help
123
+ exit 0
124
+ ;;
125
+ --version)
126
+ if [ -z "${2:-}" ]; then
127
+ printf 'Error: --version requires a value (e.g., --version 20.11.1)\n' >&2
128
+ exit 1
129
+ fi
130
+ FORCED_VERSION="$2"
131
+ shift 2
132
+ ;;
133
+ --version=*)
134
+ FORCED_VERSION="${1#--version=}"
135
+ shift
136
+ ;;
137
+ --keep-node)
138
+ KEEP_NODE=true
139
+ shift
140
+ ;;
141
+ *)
142
+ printf 'Unknown option: %s\n' "$1" >&2
143
+ printf 'Run "bash install.sh --help" for usage.\n' >&2
144
+ exit 1
145
+ ;;
146
+ esac
147
+ done
148
+
149
+ # ---------------------------------------------------------------------------
150
+ # Source mode / package mode detection (mirrors install.ps1)
151
+ #
152
+ # Package mode: easy-devops already on PATH (installed via npm -g)
153
+ # -> skip npm install + npm link
154
+ # Source mode: running from cloned repo or fresh directory
155
+ # -> run all 7 steps
156
+ # ---------------------------------------------------------------------------
157
+ PACKAGE_MODE=false
158
+ EXISTING_CMD=""
159
+
160
+ if command -v easy-devops >/dev/null 2>&1; then
161
+ EXISTING_CMD="$(command -v easy-devops)"
162
+ PACKAGE_MODE=true
163
+ fi
164
+
165
+ # ---------------------------------------------------------------------------
166
+ # Banner
167
+ # ---------------------------------------------------------------------------
168
+ printf '\n'
169
+ printf '╔══════════════════════════════════════╗\n'
170
+ printf '║ Easy DevOps -- Bootstrap Installer ║\n'
171
+ printf '╚══════════════════════════════════════╝\n'
172
+ printf '\n'
173
+
174
+ if [ "$PACKAGE_MODE" = "true" ]; then
175
+ printf ' Mode: package (easy-devops already installed at %s)\n' "$EXISTING_CMD"
176
+ printf ' Skipping npm install / npm link steps.\n'
177
+ printf '\n'
178
+ else
179
+ printf ' Mode: source (installing from project directory)\n'
180
+ printf '\n'
181
+ fi
182
+
183
+ # ---------------------------------------------------------------------------
184
+ # 7-step install sequence
185
+ # ---------------------------------------------------------------------------
186
+ STEPS=(
187
+ "Detecting system"
188
+ "Fetching Node.js release list"
189
+ "Node.js version selection"
190
+ "Installing nvm"
191
+ "Installing Node.js via nvm"
192
+ "Installing Easy DevOps dependencies"
193
+ "Registering global command"
194
+ )
195
+
196
+ # Print all steps as pending initially
197
+ for _s in "${STEPS[@]}"; do
198
+ step_pending "$_s"
199
+ done
200
+ printf '\n'
201
+
202
+ # ---------------------------------------------------------------------------
203
+ # Step 1: Detect system
204
+ # ---------------------------------------------------------------------------
205
+ step_running "${STEPS[0]}"
206
+ detect_system
207
+ step_done "${STEPS[0]}"
208
+ add_result "System detection" "ok" "$SYSINFO_OS"
209
+
210
+ # Abort if no internet (unless --keep-node is set and we won't need the network)
211
+ if [ "$SYSINFO_HAS_INTERNET" = "false" ] && [ "$KEEP_NODE" = "false" ]; then
212
+ die "${STEPS[0]}" "No internet connectivity -- cannot reach nodejs.org" \
213
+ "Check your network connection and retry: bash install.sh"
214
+ fi
215
+
216
+ # ---------------------------------------------------------------------------
217
+ # Node.js decision tree
218
+ # ---------------------------------------------------------------------------
219
+
220
+ # NodeChoice variables
221
+ NODE_ACTION="" # keep | upgrade | switch
222
+ NODE_TARGET="" # version string or empty
223
+
224
+ if [ "$KEEP_NODE" = "true" ]; then
225
+ # --keep-node flag: skip all Node.js management steps
226
+ NODE_ACTION="keep"
227
+ NODE_TARGET=""
228
+ step_done "${STEPS[1]} (skipped -- --keep-node)"
229
+ add_result "Node.js release list" "ok" "Skipped (--keep-node)"
230
+ step_done "${STEPS[2]} (skipped -- --keep-node)"
231
+ add_result "Node.js selection" "ok" "Skipped (--keep-node)"
232
+ elif [ -n "$FORCED_VERSION" ]; then
233
+ # --version VERSION flag: version already known
234
+ NODE_ACTION="switch"
235
+ NODE_TARGET="$FORCED_VERSION"
236
+ step_done "${STEPS[1]} (skipped -- version specified)"
237
+ add_result "Node.js release list" "ok" "Skipped (--version $FORCED_VERSION)"
238
+ step_done "${STEPS[2]} (skipped -- version specified: $FORCED_VERSION)"
239
+ add_result "Node.js selection" "ok" "$FORCED_VERSION"
240
+ else
241
+ # ---------------------------------------------------------------------------
242
+ # Step 2: Fetch Node.js release list
243
+ # ---------------------------------------------------------------------------
244
+ step_running "${STEPS[1]}"
245
+ if ! fetch_node_versions; then
246
+ die "${STEPS[1]}" "Failed to fetch Node.js release list from nodejs.org" \
247
+ "Check internet connection and retry: bash install.sh"
248
+ fi
249
+ step_done "${STEPS[1]}"
250
+ add_result "Node.js release list" "ok" "${#NODE_RELEASES[@]} versions fetched"
251
+
252
+ # ---------------------------------------------------------------------------
253
+ # Step 3: Version selection
254
+ # ---------------------------------------------------------------------------
255
+ step_running "${STEPS[2]}"
256
+
257
+ if [ -n "$SYSINFO_NODE_VERSION" ]; then
258
+ # Node.js already installed -- present 3-option menu (matches install.ps1)
259
+ printf '\nNode.js %s is already installed.\n' "$SYSINFO_NODE_VERSION"
260
+ printf 'What would you like to do?\n\n'
261
+ printf ' 1) Keep current version (%s)\n' "$SYSINFO_NODE_VERSION"
262
+ printf ' 2) Upgrade to latest LTS automatically\n'
263
+ printf ' 3) Switch to a different version (opens picker)\n'
264
+ printf '\n'
265
+
266
+ local_choice=""
267
+ while true; do
268
+ printf 'Enter 1, 2, or 3 (q to quit): '
269
+ IFS= read -r local_choice
270
+ case "$local_choice" in
271
+ 1)
272
+ NODE_ACTION="keep"
273
+ NODE_TARGET=""
274
+ break
275
+ ;;
276
+ 2)
277
+ NODE_ACTION="upgrade"
278
+ NODE_TARGET=""
279
+ _upgrade_lts=""
280
+ for _upgrade_rel in "${NODE_RELEASES[@]}"; do
281
+ _upgrade_lts="$(printf '%s' "$_upgrade_rel" | cut -d'|' -f3)"
282
+ if [ "$_upgrade_lts" != "false" ]; then
283
+ NODE_TARGET="$(printf '%s' "$_upgrade_rel" | cut -d'|' -f1)"
284
+ break
285
+ fi
286
+ done
287
+ if [ -z "$NODE_TARGET" ]; then
288
+ die "${STEPS[2]}" "Could not determine latest LTS version" \
289
+ "Run: bash install.sh --version <version>"
290
+ fi
291
+ break
292
+ ;;
293
+ 3)
294
+ NODE_ACTION="switch"
295
+ _pick_rc=0
296
+ pick_version "$SYSINFO_NODE_VERSION" || _pick_rc=$?
297
+ if [ "$_pick_rc" -eq 2 ]; then
298
+ printf '\nInstallation cancelled by user.\n'
299
+ exit 2
300
+ fi
301
+ check_error "$_pick_rc" "${STEPS[2]}" "Version selection failed"
302
+ NODE_TARGET="$PICKED_VERSION"
303
+ break
304
+ ;;
305
+ q|Q)
306
+ printf '\nInstallation cancelled by user.\n'
307
+ exit 2
308
+ ;;
309
+ *)
310
+ printf 'Invalid choice. Please enter 1, 2, or 3.\n' >&2
311
+ ;;
312
+ esac
313
+ done
314
+ else
315
+ # No Node.js installed -- go straight to picker
316
+ _pick_rc=0
317
+ pick_version "" || _pick_rc=$?
318
+ if [ "$_pick_rc" -eq 2 ]; then
319
+ printf '\nInstallation cancelled by user.\n'
320
+ exit 2
321
+ fi
322
+ check_error "$_pick_rc" "${STEPS[2]}" "Version selection failed"
323
+ NODE_ACTION="switch"
324
+ NODE_TARGET="$PICKED_VERSION"
325
+ fi
326
+
327
+ step_done "${STEPS[2]}"
328
+ add_result "Node.js selection" "ok" "${NODE_ACTION}${NODE_TARGET:+ -> $NODE_TARGET}"
329
+ fi
330
+
331
+ # ---------------------------------------------------------------------------
332
+ # Steps 4 + 5: nvm bootstrap + Node.js install
333
+ # ---------------------------------------------------------------------------
334
+ if [ "$NODE_ACTION" = "keep" ]; then
335
+ step_done "${STEPS[3]} (skipped -- keeping current Node.js)"
336
+ add_result "nvm" "ok" "Skipped (keep)"
337
+ step_done "${STEPS[4]} (skipped -- keeping current Node.js)"
338
+ add_result "Node.js install" "ok" "Skipped (keep)"
339
+ else
340
+ # Step 4: bootstrap nvm
341
+ step_running "${STEPS[3]}"
342
+ if ! bootstrap_nvm; then
343
+ die "${STEPS[3]}" "nvm installation failed" \
344
+ "curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/HEAD/install.sh | bash" \
345
+ "source ~/.nvm/nvm.sh" \
346
+ "bash install.sh --version $NODE_TARGET"
347
+ fi
348
+ step_done "${STEPS[3]}"
349
+ add_result "nvm" "ok" ""
350
+
351
+ # Step 5: install chosen Node.js version
352
+ step_running "${STEPS[4]}"
353
+ printf 'Installing Node.js %s via nvm...\n' "$NODE_TARGET"
354
+ if ! nvm install "$NODE_TARGET" 2>&1; then
355
+ die "${STEPS[4]}" "Failed to install Node.js $NODE_TARGET via nvm" \
356
+ "nvm install $NODE_TARGET" \
357
+ "nvm use $NODE_TARGET" \
358
+ "npm install" \
359
+ "npm link"
360
+ fi
361
+ if ! nvm use "$NODE_TARGET" 2>&1; then
362
+ die "${STEPS[4]}" "Failed to activate Node.js $NODE_TARGET" \
363
+ "nvm use $NODE_TARGET" \
364
+ "npm install" \
365
+ "npm link"
366
+ fi
367
+ step_done "${STEPS[4]}"
368
+ add_result "Node.js install" "ok" "$NODE_TARGET"
369
+ fi
370
+
371
+ # ---------------------------------------------------------------------------
372
+ # Step 6: npm install
373
+ # ---------------------------------------------------------------------------
374
+ if [ "$PACKAGE_MODE" = "true" ]; then
375
+ step_done "${STEPS[5]} (skipped -- package mode)"
376
+ add_result "npm install" "ok" "Skipped (package mode)"
377
+ else
378
+ step_running "${STEPS[5]}"
379
+ printf 'Running npm install in %s...\n' "$EASYDEVOPS_DIR"
380
+ if ! npm install --prefix "$EASYDEVOPS_DIR" 2>&1; then
381
+ die "${STEPS[5]}" "npm install failed" \
382
+ "cd $EASYDEVOPS_DIR && npm install" \
383
+ "npm link"
384
+ fi
385
+ step_done "${STEPS[5]}"
386
+ add_result "npm install" "ok" ""
387
+ fi
388
+
389
+ # ---------------------------------------------------------------------------
390
+ # Step 7: npm link -- register global command
391
+ # ---------------------------------------------------------------------------
392
+ if [ "$PACKAGE_MODE" = "true" ]; then
393
+ step_done "${STEPS[6]} (skipped -- package mode)"
394
+ add_result "CLI registered" "ok" "Skipped (package mode)"
395
+ else
396
+ step_running "${STEPS[6]}"
397
+ printf 'Registering global command via npm link...\n'
398
+ _link_ok=false
399
+ if npm link --prefix "$EASYDEVOPS_DIR" 2>&1; then
400
+ _link_ok=true
401
+ elif (cd "$EASYDEVOPS_DIR" && npm link 2>&1); then
402
+ _link_ok=true
403
+ fi
404
+
405
+ if [ "$_link_ok" = "false" ]; then
406
+ die "${STEPS[6]}" "npm link failed -- could not register global command" \
407
+ "cd $EASYDEVOPS_DIR && npm link" \
408
+ "If permission denied, try: sudo npm link"
409
+ fi
410
+
411
+ # Verify the command is on PATH
412
+ if ! command -v easy-devops >/dev/null 2>&1; then
413
+ printf 'Warning: easy-devops command not found on PATH yet.\n' >&2
414
+ printf 'You may need to open a new terminal or run:\n' >&2
415
+ printf ' export PATH="$(npm bin -g):$PATH"\n' >&2
416
+ fi
417
+
418
+ step_done "${STEPS[6]}"
419
+ add_result "CLI registered" "ok" ""
420
+ fi
421
+
422
+ # ---------------------------------------------------------------------------
423
+ # Summary (mirrors install.ps1 summary table)
424
+ # ---------------------------------------------------------------------------
425
+ printf '\n'
426
+ printf '=== Installation Summary ===\n\n'
427
+
428
+ _allOK=true
429
+ for _i in "${!_RESULT_NAMES[@]}"; do
430
+ if [ "${_RESULT_STATUS[$_i]}" = "ok" ]; then
431
+ _icon=" OK "
432
+ else
433
+ _icon="FAIL"
434
+ _allOK=false
435
+ fi
436
+ _d="${_RESULT_DETAILS[$_i]}"
437
+ if [ -n "$_d" ]; then _d=" ($_d)"; fi
438
+ printf ' [%s] %s%s\n' "$_icon" "${_RESULT_NAMES[$_i]}" "$_d"
439
+ done
440
+ printf '\n'
441
+
442
+ if [ "$_allOK" = "true" ]; then
443
+ printf ' All steps completed successfully!\n\n'
444
+ printf ' Run the CLI:\n'
445
+ printf ' easy-devops\n'
446
+ else
447
+ printf ' Some steps need attention -- see warnings above.\n\n'
448
+ printf ' Fallback:\n'
449
+ printf ' node cli/index.js\n'
450
+ fi
451
+ printf '\n'
452
+ exit 0
File without changes
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env bash
2
+ # detect.sh — System detection helpers
3
+ # Sourced by install.sh; not executed directly.
4
+ #
5
+ # Exports (as shell variables):
6
+ # SYSINFO_OS — OS name + version string
7
+ # SYSINFO_ARCH — CPU architecture
8
+ # SYSINFO_SHELL — Shell name
9
+ # SYSINFO_SHELL_VERSION — Shell version
10
+ # SYSINFO_NODE_VERSION — Installed Node.js version, or ""
11
+ # SYSINFO_NPM_VERSION — Installed npm version, or ""
12
+ # SYSINFO_NVM_INSTALLED — "true" or "false"
13
+ # SYSINFO_HAS_INTERNET — "true" or "false"
14
+ # SYSINFO_IS_ROOT — "true" or "false"
15
+ #
16
+ # Functions:
17
+ # detect_system — populate all SYSINFO_* vars and print a summary block
18
+
19
+ detect_system() {
20
+ # OS name + version
21
+ if [ -f /etc/os-release ]; then
22
+ # shellcheck source=/dev/null
23
+ . /etc/os-release
24
+ SYSINFO_OS="${NAME:-unknown} ${VERSION_ID:-}"
25
+ SYSINFO_OS="${SYSINFO_OS%% }" # trim trailing space when VERSION_ID is empty
26
+ elif [ "$(uname -s)" = "Darwin" ]; then
27
+ SYSINFO_OS="macOS $(sw_vers -productVersion 2>/dev/null || echo '')"
28
+ else
29
+ SYSINFO_OS="$(uname -s) $(uname -r)"
30
+ fi
31
+
32
+ # CPU architecture
33
+ SYSINFO_ARCH="$(uname -m)"
34
+
35
+ # Shell name + version
36
+ SYSINFO_SHELL="${SHELL##*/}"
37
+ # shellcheck disable=SC2016
38
+ SYSINFO_SHELL_VERSION="$("$SHELL" --version 2>&1 | head -1 | grep -oE '[0-9]+\.[0-9]+(\.[0-9]+)?' | head -1 || true)"
39
+
40
+ # Node.js version (empty if not installed)
41
+ if command -v node >/dev/null 2>&1; then
42
+ SYSINFO_NODE_VERSION="$(node --version 2>/dev/null | tr -d 'v' || true)"
43
+ else
44
+ SYSINFO_NODE_VERSION=""
45
+ fi
46
+
47
+ # npm version (empty if not installed)
48
+ if command -v npm >/dev/null 2>&1; then
49
+ SYSINFO_NPM_VERSION="$(npm --version 2>/dev/null || true)"
50
+ else
51
+ SYSINFO_NPM_VERSION=""
52
+ fi
53
+
54
+ # nvm installed?
55
+ local nvm_dir="${NVM_DIR:-$HOME/.nvm}"
56
+ if [ -d "$nvm_dir" ] && [ -f "$nvm_dir/nvm.sh" ]; then
57
+ SYSINFO_NVM_INSTALLED="true"
58
+ else
59
+ SYSINFO_NVM_INSTALLED="false"
60
+ fi
61
+
62
+ # Internet connectivity (reach nodejs.org)
63
+ if curl -s --max-time 5 --head https://nodejs.org >/dev/null 2>&1 \
64
+ || ping -c 1 -W 3 nodejs.org >/dev/null 2>&1; then
65
+ SYSINFO_HAS_INTERNET="true"
66
+ else
67
+ SYSINFO_HAS_INTERNET="false"
68
+ fi
69
+
70
+ # Root / Administrator check
71
+ if [ "$(id -u)" = "0" ]; then
72
+ SYSINFO_IS_ROOT="true"
73
+ else
74
+ SYSINFO_IS_ROOT="false"
75
+ fi
76
+
77
+ # Print formatted summary block
78
+ printf '\n=== System Information ===\n'
79
+ printf ' OS : %s\n' "$SYSINFO_OS"
80
+ printf ' Architecture: %s\n' "$SYSINFO_ARCH"
81
+ printf ' Shell : %s %s\n' "$SYSINFO_SHELL" "$SYSINFO_SHELL_VERSION"
82
+ printf ' Node.js : %s\n' "${SYSINFO_NODE_VERSION:-not installed}"
83
+ printf ' npm : %s\n' "${SYSINFO_NPM_VERSION:-not installed}"
84
+ printf ' nvm : %s\n' "$SYSINFO_NVM_INSTALLED"
85
+ printf ' Internet : %s\n' "$SYSINFO_HAS_INTERNET"
86
+ printf ' Root : %s\n' "$SYSINFO_IS_ROOT"
87
+ printf '==========================\n\n'
88
+ }
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env bash
2
+ # node-versions.sh — Fetch and parse Node.js release list from nodejs.org
3
+ # Sourced by install.sh; not executed directly.
4
+ #
5
+ # Functions:
6
+ # fetch_node_versions — populate NODE_RELEASES array
7
+ #
8
+ # Exports:
9
+ # NODE_RELEASES — indexed array, each element: "version|major|lts_label|display_label"
10
+ # Up to 3 most-recent LTS majors (latest patch each) + 1 latest Current.
11
+ # Sorted descending by version.
12
+
13
+ fetch_node_versions() {
14
+ local url="https://nodejs.org/dist/index.json"
15
+ local raw=""
16
+
17
+ # Fetch release index
18
+ if command -v curl >/dev/null 2>&1; then
19
+ raw="$(curl -fsSL --max-time 30 "$url" 2>/dev/null || true)"
20
+ fi
21
+ if [ -z "$raw" ] && command -v wget >/dev/null 2>&1; then
22
+ raw="$(wget -qO- --timeout=30 "$url" 2>/dev/null || true)"
23
+ fi
24
+
25
+ if [ -z "$raw" ]; then
26
+ printf 'Error: Failed to fetch Node.js release list from %s\n' "$url" >&2
27
+ return 1
28
+ fi
29
+
30
+ # Parse JSON using awk (no jq dependency).
31
+ # Strategy: normalise the JSON blob to one object per line, then extract
32
+ # "version" and "lts" fields with awk string operations.
33
+ #
34
+ # Output format (one release per line): version|major|lts_label|display_label
35
+ local parsed
36
+ parsed="$(
37
+ printf '%s' "$raw" \
38
+ | tr -d '\n\r' \
39
+ | sed 's/},{/}\n{/g' \
40
+ | awk '
41
+ BEGIN { lts_count = 0; current_done = 0; seen_majors = " " }
42
+ {
43
+ line = $0
44
+
45
+ # --- extract "version":"vX.Y.Z" ---
46
+ ver = ""
47
+ tmp = line
48
+ n = split(tmp, dummy, "\"version\":\"")
49
+ if (n >= 2) {
50
+ seg = dummy[2]
51
+ ver_end = index(seg, "\"")
52
+ if (ver_end > 0) ver = substr(seg, 1, ver_end - 1)
53
+ }
54
+ if (ver == "") next
55
+
56
+ # strip leading "v"
57
+ ver_bare = ver
58
+ sub(/^v/, "", ver_bare)
59
+
60
+ # major version number
61
+ split(ver_bare, vparts, ".")
62
+ major = vparts[1]
63
+
64
+ # --- extract "lts":"CodeName" or "lts":false ---
65
+ lts_val = "false"
66
+ tmp2 = line
67
+ m = split(tmp2, dummy2, "\"lts\":")
68
+ if (m >= 2) {
69
+ seg2 = dummy2[2]
70
+ # Remove leading whitespace
71
+ gsub(/^[ \t]+/, "", seg2)
72
+ if (substr(seg2, 1, 1) == "\"") {
73
+ # String value: "CodeName"
74
+ seg2 = substr(seg2, 2)
75
+ q_end = index(seg2, "\"")
76
+ if (q_end > 0) lts_val = substr(seg2, 1, q_end - 1)
77
+ }
78
+ # else lts_val stays "false"
79
+ }
80
+
81
+ # --- accumulate up to 3 LTS majors + 1 Current ---
82
+ if (lts_val != "false" && lts_val != "") {
83
+ # LTS release — only first occurrence of each major
84
+ if (index(seen_majors, " " major " ") == 0 && lts_count < 3) {
85
+ seen_majors = seen_majors major " "
86
+ lts_count++
87
+ print ver_bare "|" major "|" lts_val "|" ver " LTS (" lts_val ")"
88
+ }
89
+ } else if (current_done == 0) {
90
+ current_done = 1
91
+ print ver_bare "|" major "|false|" ver " (Current)"
92
+ }
93
+
94
+ if (lts_count >= 3 && current_done == 1) exit
95
+ }
96
+ '
97
+ )"
98
+
99
+ # Load into NODE_RELEASES array
100
+ NODE_RELEASES=()
101
+ while IFS= read -r line; do
102
+ [ -n "$line" ] && NODE_RELEASES+=("$line")
103
+ done <<< "$parsed"
104
+
105
+ if [ "${#NODE_RELEASES[@]}" -eq 0 ]; then
106
+ printf 'Error: Could not parse any Node.js releases from the release index.\n' >&2
107
+ return 1
108
+ fi
109
+ }