esprit-cli 0.7.13 → 0.7.15

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.
@@ -14,10 +14,19 @@ const installerPath = path.resolve(
14
14
  isWindows ? "install.ps1" : "install.sh"
15
15
  );
16
16
 
17
+ const majorNode = Number.parseInt(process.versions.node.split(".")[0], 10);
18
+ if (!Number.isFinite(majorNode) || majorNode < 18) {
19
+ console.error(
20
+ `Node.js 18+ is required for esprit-cli npm install (detected ${process.versions.node}).`
21
+ );
22
+ process.exit(1);
23
+ }
24
+
17
25
  const installEnv = {
18
26
  ...process.env,
19
27
  // npm installs should be fast/predictable; sandbox image is pulled at first scan.
20
28
  ESPRIT_SKIP_DOCKER_WARM: "1",
29
+ ESPRIT_INSTALL_CHANNEL: "npm",
21
30
  };
22
31
 
23
32
  const result = isWindows
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "esprit-cli",
3
- "version": "0.7.13",
3
+ "version": "0.7.15",
4
4
  "description": "AI-powered penetration testing agent",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://esprit.dev",
@@ -27,6 +27,7 @@ $RUNTIME_DIR = Join-Path $INSTALL_ROOT 'runtime'
27
27
  $VENV_DIR = Join-Path $INSTALL_ROOT 'venv'
28
28
  $LAUNCHER_CMD = Join-Path $BIN_DIR 'esprit.cmd'
29
29
  $ESPRIT_IMAGE = if ($env:ESPRIT_IMAGE) { $env:ESPRIT_IMAGE } else { 'improdead/esprit-sandbox:latest' }
30
+ $INSTALL_CHANNEL = if ($env:ESPRIT_INSTALL_CHANNEL) { $env:ESPRIT_INSTALL_CHANNEL } else { 'manual' }
30
31
 
31
32
  function Print-Message {
32
33
  param([string]$Level, [string]$Message)
@@ -85,6 +86,30 @@ function Invoke-Python {
85
86
  }
86
87
  }
87
88
 
89
+ function Validate-PythonRuntime {
90
+ param([string]$PyBin)
91
+
92
+ $parts = $PyBin -split ' ', 2
93
+ $exe = $parts[0]
94
+ $prefix = @()
95
+ if ($parts.Length -gt 1) { $prefix += $parts[1] }
96
+
97
+ $moduleCheck = @()
98
+ $moduleCheck += $prefix
99
+ $moduleCheck += '-c'
100
+ $moduleCheck += 'import importlib.util; required=("venv","ensurepip","ssl"); missing=[m for m in required if importlib.util.find_spec(m) is None]; print(",".join(missing)); raise SystemExit(0 if not missing else 1)'
101
+
102
+ $missingModules = (& $exe @moduleCheck 2>$null | Out-String).Trim()
103
+ if ($LASTEXITCODE -ne 0) {
104
+ if (-not $missingModules) { $missingModules = 'unknown' }
105
+ Print-Message 'error' "Python runtime is missing required stdlib modules: $missingModules."
106
+ Print-Message 'info' 'Install a full Python 3.12+ build (with venv + ensurepip) and retry.'
107
+ exit 1
108
+ }
109
+
110
+ Invoke-Python $PyBin @('-m', 'pip', '--version')
111
+ }
112
+
88
113
  function Sync-RuntimeRepo {
89
114
  Print-Message 'info' 'Syncing Esprit runtime source...'
90
115
 
@@ -202,14 +227,22 @@ function Warm-DockerImage {
202
227
  # ── Main ──────────────────────────────────────────────────────────────────────
203
228
 
204
229
  try {
230
+ Print-Message 'info' 'Running install preflight checks...'
205
231
  Require-Command 'git' 'Install git and re-run the installer.'
206
232
 
233
+ if ($INSTALL_CHANNEL -eq 'npm') {
234
+ Require-Command 'node' 'Install Node.js 18+ and re-run npm install.'
235
+ Require-Command 'npm' 'Install npm and re-run npm install.'
236
+ }
237
+
207
238
  $pyBin = Choose-Python
208
239
  if (-not $pyBin) {
209
240
  Print-Message 'error' 'Python 3.12+ is required.'
210
241
  Print-Message 'info' 'Install Python 3.12 and re-run this installer.'
211
242
  exit 1
212
243
  }
244
+ Validate-PythonRuntime -PyBin $pyBin
245
+ Print-Message 'success' '✓ Preflight checks passed'
213
246
 
214
247
  Print-Message 'info' "Installing Esprit (source mode)"
215
248
  Print-Message 'info' "Runtime source: $REPO_URL@$REPO_REF"
@@ -48,6 +48,61 @@ require_command() {
48
48
  fi
49
49
  }
50
50
 
51
+ validate_python_runtime() {
52
+ local py_bin="$1"
53
+ local missing_modules
54
+
55
+ if ! missing_modules=$("$py_bin" - <<'PY'
56
+ import importlib.util
57
+ required = ("venv", "ensurepip", "ssl")
58
+ missing = [name for name in required if importlib.util.find_spec(name) is None]
59
+ if missing:
60
+ print(",".join(missing))
61
+ raise SystemExit(1)
62
+ print("")
63
+ PY
64
+ ); then
65
+ print_message error "Python runtime is missing required stdlib modules: ${missing_modules:-unknown}."
66
+ print_message info "Install a full Python 3.12+ build (with venv + ensurepip) and retry."
67
+ exit 1
68
+ fi
69
+
70
+ if ! "$py_bin" -m pip --version >/dev/null 2>&1; then
71
+ print_message error "pip is unavailable for ${py_bin}."
72
+ print_message info "Install pip/ensurepip for your Python distribution and retry."
73
+ exit 1
74
+ fi
75
+ }
76
+
77
+ warn_if_musl_build_toolchain_missing() {
78
+ if [ "$(uname -s)" != "Linux" ]; then
79
+ return
80
+ fi
81
+
82
+ if ! command -v ldd >/dev/null 2>&1; then
83
+ return
84
+ fi
85
+
86
+ if ! ldd --version 2>&1 | grep -qi "musl"; then
87
+ return
88
+ fi
89
+
90
+ local missing=()
91
+ local cmd
92
+ for cmd in gcc g++ make cargo rustc; do
93
+ if ! command -v "$cmd" >/dev/null 2>&1; then
94
+ missing+=("$cmd")
95
+ fi
96
+ done
97
+
98
+ if [ "${#missing[@]}" -gt 0 ]; then
99
+ print_message warning "Detected musl-based Linux (for example Alpine)."
100
+ print_message warning "Some Python dependencies may compile from source."
101
+ print_message info "Missing build tools: ${missing[*]}"
102
+ print_message info "Recommended: apk add --no-cache build-base linux-headers rust cargo"
103
+ fi
104
+ }
105
+
51
106
  verify_signature() {
52
107
  if ! command -v gpg &> /dev/null; then
53
108
  echo "⚠ gpg not found — skipping signature verification"
@@ -259,9 +314,16 @@ warm_docker_image() {
259
314
  }
260
315
 
261
316
  main() {
317
+ local install_channel="${ESPRIT_INSTALL_CHANNEL:-curl}"
318
+ print_message info "${MUTED}Running install preflight checks...${NC}"
262
319
  require_command git "Install git and re-run the installer."
263
320
  require_command curl "Install curl and re-run the installer."
264
321
 
322
+ if [ "$install_channel" = "npm" ]; then
323
+ require_command node "Install Node.js 18+ and re-run npm install."
324
+ require_command npm "Install npm and re-run npm install."
325
+ fi
326
+
265
327
  local py_bin
266
328
  py_bin=$(choose_python || true)
267
329
  if [ -z "$py_bin" ]; then
@@ -269,6 +331,9 @@ main() {
269
331
  print_message info "Install Python 3.12 and re-run this installer."
270
332
  exit 1
271
333
  fi
334
+ validate_python_runtime "$py_bin"
335
+ warn_if_musl_build_toolchain_missing
336
+ print_message success "✓ Preflight checks passed"
272
337
 
273
338
  print_message info "${CYAN}Installing Esprit${NC} ${MUTED}(source mode)${NC}"
274
339
  print_message info "${MUTED}Runtime source:${NC} $REPO_URL@$REPO_REF"