@akash-chowdhury-24/deployhub 2.0.20 → 2.0.22

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 CHANGED
@@ -31,17 +31,52 @@ Downloads the latest release from [GitHub Releases](https://github.com/Akash-Cho
31
31
  curl -fsSL https://raw.githubusercontent.com/Akash-Chowdhury-24/DeployHub/main/install.sh | sh
32
32
  ```
33
33
 
34
- Supported platforms: Linux x64, macOS x64, macOS ARM64. If the binary download fails, the script falls back to `npm install -g`.
34
+ Supported platforms: Linux x64, macOS x64, macOS ARM64. If the binary download fails, the script falls back to `npm install -g`. After install it warns if `deployhub` on PATH still resolves to a different (e.g. older npm-global) binary — see the Windows notes below for the same dual-channel conflict.
35
+
36
+ > **macOS `install.sh` — UNTESTED on real hardware in this project’s verification so far**
37
+ >
38
+ > Release assets `deployhub-macos-x64` and `deployhub-macos-arm64` are published and downloadable, and `install.sh` has `darwin` / `x86_64` / `arm64` branches that *should* select those names. The PATH-collision warning and clean/no-collision cases were proven on **Windows** (native) and **Linux** (Docker). They have **not** been run on a real Mac (Intel or Apple Silicon). Linux Docker proof does **not** cover macOS: different `uname` platform branch, different binary assets, BSD userland (`sed` / `readlink` / etc.), and default interactive shell is **zsh** (Catalina+) — the script does not edit `.zshrc` / `.zprofile` / `.bashrc` at all; for a non-sudo install it only prints that you must ensure `~/.local/bin` is on PATH. Treat first macOS binary install as unverified until someone pastes real Terminal output for collision + clean cases on both arch flavors (or at least the arch you use).
35
39
 
36
40
  ### Standalone binary (Windows)
37
41
 
38
- Run in PowerShell:
42
+ Run in **PowerShell** (does **not** require an elevated/Administrator session — installs under your user profile only):
39
43
 
40
44
  ```powershell
41
45
  irm https://raw.githubusercontent.com/Akash-Chowdhury-24/DeployHub/main/install.ps1 | iex
42
46
  ```
43
47
 
44
- Installs to `%LOCALAPPDATA%\Programs\DeployHub` and adds it to your user PATH. On Windows ARM64, the script installs via npm instead (no native binary yet).
48
+ **What the script actually does:**
49
+ - **x64:** downloads the GitHub Release asset `deployhub-win.exe` and saves it as `%LOCALAPPDATA%\Programs\DeployHub\deployhub.exe` (plain `deployhub` on PATH), then appends that folder to your **user** `PATH` (not machine-wide).
50
+ - **ARM64:** there is no Windows ARM64 binary yet — the script skips the download and runs `npm install -g @akash-chowdhury-24/deployhub@latest` immediately (**requires Node.js 18+**).
51
+ - **Failed x64 download:** the script **does** fall back to the same npm global install (also requires Node.js 18+). If you have neither a working download nor Node.js, installation fails.
52
+ - **No checksum/signature check in the script** — release assets include a `checksums.txt` (SHA-256), but `install.ps1` does not verify it automatically. Binaries are **not Authenticode code-signed**.
53
+ - **PATH collision warning:** if an older install (commonly `npm install -g`) still resolves first, the script prints a warning with `Get-Command deployhub -All` / `npm uninstall -g` guidance. `install.sh` on Linux/macOS does the same check (`type -a deployhub`).
54
+
55
+ > **Open a new PowerShell window after installing.** User `PATH` changes do not apply to the window that ran `iex`. Until you open a new session, `deployhub` may be “not recognized” even though the install succeeded.
56
+
57
+ > **Previously installed via npm?** Binary and npm installs can both put `deployhub` on PATH. After the binary installer finishes, if `deployhub --version` still shows an older version, run `Get-Command deployhub -All` (Windows) or `type -a deployhub` (Linux/macOS). Remove the stale npm copy with `npm uninstall -g @akash-chowdhury-24/deployhub`, or put `%LOCALAPPDATA%\Programs\DeployHub` (Windows) / `/usr/local/bin` or `~/.local/bin` (Unix) earlier in PATH. Then open a **new** terminal and re-check `--version`.
58
+
59
+ > **Windows `pkg` binary — what is and isn’t verified**
60
+ >
61
+ > DeployHub’s only native-adjacent dependency is **`ssh2`** (used by SSH / EC2 / Azure VM / GCP VM). It optionally uses `cpu-features` and an optional `sshcrypto.node` binding; both are try/catch’d and fall back to pure JS/`crypto` when missing. `cpu-features` is **not** listed in `pkg.assets` and is typically absent from installs — that is expected. Storage SDKs (`@aws-sdk/*`, `@azure/storage-blob`, `@google-cloud/storage`, `googleapis`, `dropbox`, `basic-ftp`) and `execa` (Docker / Kubernetes / cloud-CLI lookups) are pure JS / HTTP / process-spawn.
62
+ >
63
+ > **Exercised on the published `deployhub-win.exe` (module load / CLI spawn — not a full live deploy):**
64
+ > - CLI boot (`--version` / `--help`)
65
+ > - **SSH path:** `ssh2`/`node-ssh` load and attempt a real TCP connect (failed on missing key / `ECONNREFUSED` — i.e. past native-load risk)
66
+ > - **AWS S3 SDK** load (SDK warning + doctor AWS check ran)
67
+ > - **Azure / GCP / Google Drive / Dropbox / local** storage provider modules load (doctor checks ran; failures were credentials/API/ENOENT — not `MODULE_NOT_FOUND`)
68
+ > - **Docker** via `execa` → host `docker.exe` (daemon pipe missing is an environment issue; spawn worked)
69
+ > - **Kubernetes** via `execa` → host `kubectl` (cluster unreachable; spawn worked)
70
+ >
71
+ > **Still unproven end-to-end on Windows binary against real infrastructure:** a successful SSH session to a live host (auth + remote commands), a successful S3 (or other cloud) upload with real credentials, and a successful Docker/Kubernetes deploy. Those remain first-real-use risks for network/auth/config — not for missing native addons based on current evidence. If SSH from the `.exe` misbehaves oddly, compare with `npm install -g @akash-chowdhury-24/deployhub` (requires Node.js 18+).
72
+
73
+ Manual checksum check (optional, recommended for locked-down environments):
74
+
75
+ ```powershell
76
+ # After install, or after downloading deployhub-win.exe from the release page:
77
+ Get-FileHash "$env:LOCALAPPDATA\Programs\DeployHub\deployhub.exe" -Algorithm SHA256
78
+ # Compare to the deployhub-win.exe line in checksums.txt from the same release.
79
+ ```
45
80
 
46
81
  ### Manual download
47
82
 
@@ -1061,6 +1096,15 @@ Prefer `deployhub init` over hand-writing config — it sets adapters, workflow,
1061
1096
  | Tests fail in CI | Set `"pipeline": { "test": false }` temporarily, or fix tests |
1062
1097
  | Monorepo subfolders | Edit `buildCommand` paths in `deployhub.config.json` after init |
1063
1098
 
1099
+ ### Windows install (`install.ps1`)
1100
+
1101
+ | Problem | Fix |
1102
+ |---------|-----|
1103
+ | `irm` / `iex` blocked, or SmartScreen / Defender flags `deployhub.exe` | The Windows binary is **not Authenticode code-signed**, so SmartScreen often warns on first run. Click **More info → Run anyway**, or download `deployhub-win.exe` + `checksums.txt` from [Releases](https://github.com/Akash-Chowdhury-24/DeployHub/releases/latest) and verify the SHA-256 hash before running. If your org blocks unsigned binaries entirely, install via npm instead: `npm install -g @akash-chowdhury-24/deployhub` (requires Node.js 18+). |
1104
+ | `deployhub : The term 'deployhub' is not recognized` right after install | **Open a new PowerShell window** first — user `PATH` updates do not apply to the session that ran `iex`. Confirm the file exists at `%LOCALAPPDATA%\Programs\DeployHub\deployhub.exe`. If it is missing, re-run the install script or use the npm fallback. |
1105
+ | `deployhub --version` shows an unexpected / old version | Compare against the [latest release tag](https://github.com/Akash-Chowdhury-24/DeployHub/releases/latest). Run `Get-Command deployhub -All` (Windows) or `type -a deployhub` (Unix) — an older **npm global** install often wins PATH order. Fix: `npm uninstall -g @akash-chowdhury-24/deployhub`, or put the binary install dir first in PATH, then open a **new** terminal. Force a clean binary reinstall: delete `%LOCALAPPDATA%\Programs\DeployHub`, re-run `install.ps1`, open a new PowerShell window. |
1106
+ | Binary download fails and npm fallback errors | The x64 script falls back to `npm install -g …` when the GitHub download fails. That fallback **requires Node.js 18+ and npm on PATH**. Without Node, fix network access to GitHub Releases, or install Node and retry. |
1107
+
1064
1108
  Run `deployhub doctor` after any config change.
1065
1109
 
1066
1110
  ---
package/install.ps1 CHANGED
@@ -1,11 +1,19 @@
1
1
  # DeployHub install script for Windows
2
- # Author: Akash Chowdhury canonical source: src/utils/author.js
2
+ # Author: Akash Chowdhury - canonical source: src/utils/author.js
3
3
  # Repository: https://github.com/Akash-Chowdhury-24/DeployHub
4
+ #
5
+ # IMPORTANT: PowerShell variable names are CASE-INSENSITIVE.
6
+ # Never use $BinaryName / $binaryName as two different values - the second write
7
+ # overwrites the first (that bug previously saved deployhub-win.exe instead of deployhub.exe).
4
8
 
5
9
  $ErrorActionPreference = "Stop"
6
10
 
7
11
  $GitHubRepo = "Akash-Chowdhury-24/DeployHub"
8
- $BinaryName = "deployhub.exe"
12
+ # Filename on disk after install (what PATH resolves as `deployhub`)
13
+ $InstalledExeName = "deployhub.exe"
14
+ # GitHub Release asset name for Windows x64
15
+ $ReleaseAssetName = "deployhub-win.exe"
16
+ $NpmPackage = "@akash-chowdhury-24/deployhub"
9
17
 
10
18
  function Get-LatestVersion {
11
19
  $release = Invoke-RestMethod -Uri "https://api.github.com/repos/$GitHubRepo/releases/latest"
@@ -20,46 +28,163 @@ function Get-InstallDir {
20
28
  return $localBin
21
29
  }
22
30
 
31
+ function Refresh-SessionPathFromPersistent {
32
+ # Rebuild PATH the way a NEW PowerShell window would see it after our User PATH edit.
33
+ # Do NOT prepend the install dir here - that would hide npm-global collisions
34
+ # (user PATH appends DeployHub at the end; npm often wins earlier in PATH).
35
+ $machinePath = [Environment]::GetEnvironmentVariable("Path", "Machine")
36
+ $userPath = [Environment]::GetEnvironmentVariable("Path", "User")
37
+ if ($machinePath -and $userPath) {
38
+ $env:Path = "$machinePath;$userPath"
39
+ } elseif ($userPath) {
40
+ $env:Path = $userPath
41
+ } elseif ($machinePath) {
42
+ $env:Path = $machinePath
43
+ }
44
+ }
45
+
23
46
  function Add-ToPath {
24
47
  param([string]$Dir)
25
48
  $userPath = [Environment]::GetEnvironmentVariable("Path", "User")
26
49
  if ($userPath -notlike "*$Dir*") {
27
- [Environment]::SetEnvironmentVariable("Path", "$userPath;$Dir", "User")
28
- $env:Path = "$env:Path;$Dir"
50
+ if ([string]::IsNullOrWhiteSpace($userPath)) {
51
+ [Environment]::SetEnvironmentVariable("Path", $Dir, "User")
52
+ } else {
53
+ [Environment]::SetEnvironmentVariable("Path", "$userPath;$Dir", "User")
54
+ }
29
55
  Write-Host "Added $Dir to user PATH"
30
56
  }
57
+ Refresh-SessionPathFromPersistent
58
+ }
59
+
60
+ function Get-VersionFromOutput {
61
+ param([string]$Output)
62
+ if ([string]::IsNullOrWhiteSpace($Output)) { return $null }
63
+ $line = ($Output -split "`r?`n" | Where-Object { $_.Trim() -ne '' } | Select-Object -First 1)
64
+ if (-not $line) { return $null }
65
+ if ($line -match '(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)') {
66
+ return $Matches[1]
67
+ }
68
+ return $line.Trim()
69
+ }
70
+
71
+ function Warn-PathCollision {
72
+ param(
73
+ [string]$InstallDir,
74
+ [string]$InstalledExe,
75
+ [string]$ExpectedTag
76
+ )
77
+
78
+ $expectedVersion = $ExpectedTag.TrimStart('v')
79
+ $directOut = & $InstalledExe --version 2>&1 | Out-String
80
+ $directVersion = Get-VersionFromOutput $directOut
81
+
82
+ Write-Host ""
83
+ Write-Host "Installed binary reports: $(if ($directVersion) { $directVersion } else { '(unknown)' }) ($InstalledExe)"
84
+
85
+ # Re-sync PATH from Machine+User so this check matches a freshly opened shell.
86
+ Refresh-SessionPathFromPersistent
87
+
88
+ $resolved = $null
89
+ try {
90
+ $resolved = Get-Command deployhub -ErrorAction Stop
91
+ } catch {
92
+ Write-Host "Note: 'deployhub' is not yet visible on PATH in this session." -ForegroundColor Yellow
93
+ Write-Host "Open a NEW PowerShell window, then run: deployhub --version" -ForegroundColor Yellow
94
+ return
95
+ }
96
+
97
+ $resolvedPath = $resolved.Source
98
+ # Prefer .exe over .cmd/.ps1 shims when comparing versions of what PATH runs
99
+ $pathOut = & deployhub --version 2>&1 | Out-String
100
+ $pathVersion = Get-VersionFromOutput $pathOut
101
+
102
+ $installedFull = [System.IO.Path]::GetFullPath($InstalledExe)
103
+ $resolvedFull = [System.IO.Path]::GetFullPath($resolvedPath)
104
+
105
+ # npm global on Windows resolves to deployhub.cmd / deployhub.ps1, not our .exe
106
+ $sameFile = ($installedFull -ieq $resolvedFull)
107
+ $versionMatch = $pathVersion -and $expectedVersion -and ($pathVersion -eq $expectedVersion)
108
+
109
+ if ($sameFile -and $versionMatch) {
110
+ Write-Host "PATH resolves to the newly installed binary ($pathVersion). OK."
111
+ Write-Host "Still open a NEW PowerShell window before day-to-day use so user PATH updates apply cleanly."
112
+ return
113
+ }
114
+
115
+ if ((-not $sameFile) -or (-not $versionMatch)) {
116
+ Write-Host ""
117
+ Write-Host "WARNING: Installed DeployHub $expectedVersion to $InstallDir," -ForegroundColor Yellow
118
+ Write-Host " but running 'deployhub --version' currently resolves to a DIFFERENT" -ForegroundColor Yellow
119
+ Write-Host " installation reporting a different version (or path)." -ForegroundColor Yellow
120
+ Write-Host ""
121
+ Write-Host " Expected: $installedFull ($expectedVersion)"
122
+ Write-Host " Resolved: $resolvedFull ($(if ($pathVersion) { $pathVersion } else { 'unknown version' }))"
123
+ Write-Host ""
124
+ Write-Host " This usually means an older install (e.g. via 'npm install -g') is earlier in your PATH."
125
+ Write-Host ""
126
+ Write-Host " To see every 'deployhub' on your PATH, run:"
127
+ Write-Host " Get-Command deployhub -All"
128
+ Write-Host ""
129
+ Write-Host " To remove a conflicting npm install:"
130
+ Write-Host " npm uninstall -g $NpmPackage"
131
+ Write-Host ""
132
+ Write-Host " Or reorder your PATH so $InstallDir comes first."
133
+ Write-Host ""
134
+ Write-Host " This check rebuilds PATH from your saved Machine+User environment" -ForegroundColor Yellow
135
+ Write-Host " (same order a NEW PowerShell window would use). After fixing PATH," -ForegroundColor Yellow
136
+ Write-Host " open a NEW window and run: deployhub --version" -ForegroundColor Yellow
137
+ }
31
138
  }
32
139
 
33
140
  try {
34
141
  $arch = $env:PROCESSOR_ARCHITECTURE
35
142
  if ($arch -eq "ARM64") {
36
- $binaryName = "deployhub-macos-arm64" # no Windows ARM64 binary yet
37
- Write-Host "Windows ARM64 detected — no native binary available yet. Installing via npm instead..."
38
- npm install -g @akash-chowdhury-24/deployhub@latest
143
+ Write-Host "Windows ARM64 detected - no native binary available yet. Installing via npm instead..."
144
+ npm install -g "$NpmPackage@latest"
39
145
  exit 0
40
- } else {
41
- $binaryName = "deployhub-win.exe"
42
146
  }
43
147
 
44
148
  $version = Get-LatestVersion
45
- $assetName = $binaryName
46
- $url = "https://github.com/$GitHubRepo/releases/download/$version/$assetName"
149
+ $url = "https://github.com/$GitHubRepo/releases/download/$version/$ReleaseAssetName"
47
150
  $installDir = Get-InstallDir
48
- $dest = Join-Path $installDir $BinaryName
151
+ $dest = Join-Path $installDir $InstalledExeName
49
152
 
50
- Write-Host "Downloading DeployHub $version for Windows..."
51
- Invoke-WebRequest -Uri $url -OutFile $dest -UseBasicParsing
153
+ Write-Host "Downloading DeployHub $version for Windows ($ReleaseAssetName -> $InstalledExeName)..."
154
+ # Download to a temp name first, then rename - avoids leaving a half-written deployhub.exe
155
+ $tmpDest = Join-Path $installDir ("deployhub-download-" + [guid]::NewGuid().ToString("n") + ".exe")
156
+ try {
157
+ Invoke-WebRequest -Uri $url -OutFile $tmpDest -UseBasicParsing
158
+ if (-not (Test-Path $tmpDest) -or (Get-Item $tmpDest).Length -eq 0) {
159
+ throw "Binary download failed"
160
+ }
161
+ # Remove any legacy misnamed asset from older install.ps1 (PowerShell case-bug).
162
+ $legacy = Join-Path $installDir $ReleaseAssetName
163
+ if (Test-Path $legacy) {
164
+ Remove-Item -Force $legacy -ErrorAction SilentlyContinue
165
+ }
166
+ Move-Item -Force -Path $tmpDest -Destination $dest
167
+ } finally {
168
+ if (Test-Path $tmpDest) {
169
+ Remove-Item -Force $tmpDest -ErrorAction SilentlyContinue
170
+ }
171
+ }
52
172
 
53
173
  if (-not (Test-Path $dest) -or (Get-Item $dest).Length -eq 0) {
54
- throw "Binary download failed"
174
+ throw "Binary install failed - $InstalledExeName missing after download"
175
+ }
176
+
177
+ if ((Split-Path -Leaf $dest) -ne $InstalledExeName) {
178
+ throw "Internal error: installed file is not named $InstalledExeName"
55
179
  }
56
180
 
57
181
  Add-ToPath $installDir
58
182
  Write-Host "DeployHub $version installed to $dest"
59
- & $dest --version
183
+ Write-Host "On-disk filename: $(Split-Path -Leaf $dest)"
184
+ Warn-PathCollision -InstallDir $installDir -InstalledExe $dest -ExpectedTag $version
60
185
  }
61
186
  catch {
62
187
  Write-Host "Binary install failed ($($_.Exception.Message)). Falling back to npm..." -ForegroundColor Yellow
63
- npm install -g @akash-chowdhury-24/deployhub@latest
188
+ npm install -g "$NpmPackage@latest"
64
189
  Write-Host "DeployHub installed via npm."
65
190
  }
package/install.sh CHANGED
@@ -8,6 +8,8 @@ set -e
8
8
  GITHUB_REPO="Akash-Chowdhury-24/DeployHub"
9
9
  INSTALL_DIR="/usr/local/bin"
10
10
  BINARY_NAME="deployhub"
11
+ NPM_PACKAGE="@akash-chowdhury-24/deployhub"
12
+ INSTALLED_PATH=""
11
13
 
12
14
  detect_platform() {
13
15
  OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
@@ -50,7 +52,7 @@ fetch_latest_version() {
50
52
 
51
53
  if [ -z "$VERSION" ]; then
52
54
  echo "Could not determine latest release version. Falling back to npm install." >&2
53
- npm install -g @akash-chowdhury-24/deployhub@latest
55
+ npm install -g "${NPM_PACKAGE}@latest"
54
56
  echo "DeployHub installed via npm."
55
57
  exit 0
56
58
  fi
@@ -71,19 +73,22 @@ download_binary() {
71
73
  if [ ! -s "$TMP" ]; then
72
74
  echo "Binary download failed. Falling back to npm install." >&2
73
75
  rm -f "$TMP"
74
- npm install -g @akash-chowdhury-24/deployhub@latest
76
+ npm install -g "${NPM_PACKAGE}@latest"
75
77
  echo "DeployHub installed via npm."
76
78
  exit 0
77
79
  fi
78
80
 
79
81
  if [ "$(id -u)" -eq 0 ]; then
80
82
  install -m 755 "$TMP" "${INSTALL_DIR}/${BINARY_NAME}"
83
+ INSTALLED_PATH="${INSTALL_DIR}/${BINARY_NAME}"
81
84
  else
82
85
  if command -v sudo >/dev/null 2>&1; then
83
86
  sudo install -m 755 "$TMP" "${INSTALL_DIR}/${BINARY_NAME}"
87
+ INSTALLED_PATH="${INSTALL_DIR}/${BINARY_NAME}"
84
88
  else
85
89
  mkdir -p "${HOME}/.local/bin"
86
90
  install -m 755 "$TMP" "${HOME}/.local/bin/${BINARY_NAME}"
91
+ INSTALLED_PATH="${HOME}/.local/bin/${BINARY_NAME}"
87
92
  echo "Installed to ${HOME}/.local/bin/${BINARY_NAME} — ensure it is on your PATH"
88
93
  fi
89
94
  fi
@@ -91,9 +96,82 @@ download_binary() {
91
96
  rm -f "$TMP"
92
97
  }
93
98
 
99
+ # Compare PATH-resolved `deployhub` to the binary we just installed.
100
+ warn_path_collision() {
101
+ EXPECTED_VERSION="${VERSION#v}"
102
+ if [ -z "$INSTALLED_PATH" ] || [ ! -x "$INSTALLED_PATH" ]; then
103
+ return 0
104
+ fi
105
+
106
+ INSTALL_BIN_DIR="$(dirname "$INSTALLED_PATH")"
107
+ # Put install dir on PATH only if missing, and APPEND (do not prepend).
108
+ # Prepending would hide an older npm-global install that sits earlier on PATH —
109
+ # the same failure mode the Windows installer hit.
110
+ case ":${PATH}:" in
111
+ *":${INSTALL_BIN_DIR}:"*) ;;
112
+ *) PATH="${PATH}:${INSTALL_BIN_DIR}"; export PATH ;;
113
+ esac
114
+
115
+ DIRECT_OUT="$("$INSTALLED_PATH" --version 2>/dev/null || true)"
116
+ DIRECT_VER="$(printf '%s\n' "$DIRECT_OUT" | head -n 1 | tr -d '\r' | sed -n 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*[-0-9A-Za-z.]*\).*/\1/p')"
117
+
118
+ echo ""
119
+ echo "Installed binary reports: ${DIRECT_VER:-unknown} ($INSTALLED_PATH)"
120
+
121
+ if ! command -v deployhub >/dev/null 2>&1; then
122
+ echo "Note: 'deployhub' is not yet visible on PATH in this shell."
123
+ echo "Open a NEW terminal, then run: deployhub --version"
124
+ return 0
125
+ fi
126
+
127
+ RESOLVED_PATH="$(command -v deployhub)"
128
+ PATH_OUT="$(deployhub --version 2>/dev/null || true)"
129
+ PATH_VER="$(printf '%s\n' "$PATH_OUT" | head -n 1 | tr -d '\r' | sed -n 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*[-0-9A-Za-z.]*\).*/\1/p')"
130
+
131
+ # Resolve symlinks where possible for a fair path comparison.
132
+ # Prefer `realpath` (GNU coreutils; also present on recent macOS).
133
+ # Do NOT use `readlink -f` — that flag is GNU-only; BSD readlink on macOS
134
+ # rejects `-f` (the `|| echo` fallback usually masks it, but it is not portable).
135
+ INST_REAL="$INSTALLED_PATH"
136
+ RES_REAL="$RESOLVED_PATH"
137
+ if command -v realpath >/dev/null 2>&1; then
138
+ INST_REAL="$(realpath "$INSTALLED_PATH" 2>/dev/null || echo "$INSTALLED_PATH")"
139
+ RES_REAL="$(realpath "$RESOLVED_PATH" 2>/dev/null || echo "$RESOLVED_PATH")"
140
+ fi
141
+
142
+ if [ "$INST_REAL" = "$RES_REAL" ] && [ -n "$PATH_VER" ] && [ "$PATH_VER" = "$EXPECTED_VERSION" ]; then
143
+ echo "PATH resolves to the newly installed binary ($PATH_VER). OK."
144
+ echo "Still open a NEW terminal before day-to-day use so your shell profile PATH applies cleanly."
145
+ return 0
146
+ fi
147
+
148
+ echo ""
149
+ echo "WARNING: Installed DeployHub ${EXPECTED_VERSION} to ${INSTALLED_PATH},"
150
+ echo " but running 'deployhub --version' currently resolves to a DIFFERENT"
151
+ echo " installation reporting a different version (or path)."
152
+ echo ""
153
+ echo " Expected: ${INST_REAL} (${EXPECTED_VERSION})"
154
+ echo " Resolved: ${RES_REAL} (${PATH_VER:-unknown version})"
155
+ echo ""
156
+ echo " This usually means an older install (e.g. via 'npm install -g') is earlier in your PATH."
157
+ echo ""
158
+ echo " To see every 'deployhub' on your PATH, run:"
159
+ echo " type -a deployhub"
160
+ echo " # or: which -a deployhub"
161
+ echo ""
162
+ echo " To remove a conflicting npm install:"
163
+ echo " npm uninstall -g ${NPM_PACKAGE}"
164
+ echo ""
165
+ echo " Or reorder your PATH so the directory containing the new binary comes first."
166
+ echo ""
167
+ echo " This check uses the CURRENT shell PATH (install dir appended only if it was"
168
+ echo " missing — not prepended, so earlier npm installs are not hidden). After fixing"
169
+ echo " PATH, open a NEW terminal and run: deployhub --version"
170
+ }
171
+
94
172
  detect_platform
95
173
  fetch_latest_version
96
174
  download_binary
97
175
 
98
176
  echo "DeployHub ${VERSION} installed successfully."
99
- deployhub --version 2>/dev/null || true
177
+ warn_path_collision
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akash-chowdhury-24/deployhub",
3
- "version": "2.0.20",
3
+ "version": "2.0.22",
4
4
  "description": "Zero-configuration deployment and artifact manager",
5
5
  "type": "module",
6
6
  "main": "./src/cli/index.js",
@@ -23,8 +23,13 @@ function create(config, cwd) {
23
23
  },
24
24
 
25
25
  async build() {
26
- log.info(`Running: ${config.buildCommand}`);
27
- const [cmd, ...args] = config.buildCommand.split(' ');
26
+ const buildCommand = config.buildCommand;
27
+ if (buildCommand == null || String(buildCommand).trim() === '') {
28
+ log.info('No build step required — skipping');
29
+ return;
30
+ }
31
+ log.info(`Running: ${buildCommand}`);
32
+ const [cmd, ...args] = String(buildCommand).split(' ');
28
33
  await execa(cmd, args, { cwd, stdio: 'inherit', shell: true });
29
34
  },
30
35
 
@@ -22,8 +22,13 @@ function create(config, cwd) {
22
22
  },
23
23
 
24
24
  async build() {
25
- log.info(`Running: ${config.buildCommand}`);
26
- const [cmd, ...args] = config.buildCommand.split(' ');
25
+ const buildCommand = config.buildCommand;
26
+ if (buildCommand == null || String(buildCommand).trim() === '') {
27
+ log.info('No build step required — skipping');
28
+ return;
29
+ }
30
+ log.info(`Running: ${buildCommand}`);
31
+ const [cmd, ...args] = String(buildCommand).split(' ');
27
32
  await execa(cmd, args, { cwd, stdio: 'inherit', shell: true });
28
33
  },
29
34
 
@@ -28,8 +28,13 @@ function create(config, cwd) {
28
28
  },
29
29
 
30
30
  async build() {
31
- log.info(`Running: ${config.buildCommand}`);
32
- const [cmd, ...args] = config.buildCommand.split(' ');
31
+ const buildCommand = config.buildCommand;
32
+ if (buildCommand == null || String(buildCommand).trim() === '') {
33
+ log.info('No build step required — skipping');
34
+ return;
35
+ }
36
+ log.info(`Running: ${buildCommand}`);
37
+ const [cmd, ...args] = String(buildCommand).split(' ');
33
38
  await execa(cmd, args, { cwd, stdio: 'inherit', shell: true });
34
39
  },
35
40
 
@@ -50,13 +50,13 @@ function create(config, cwd) {
50
50
  (config.projectType === 'both' ? config.frontend?.buildCommand : null) ||
51
51
  (config.projectType === 'backend' ? config.backend?.buildCommand : null);
52
52
 
53
- if (!buildCommand) {
54
- log.info('No build command configured, skipping');
53
+ if (buildCommand == null || String(buildCommand).trim() === '') {
54
+ log.info('No build step required skipping');
55
55
  return;
56
56
  }
57
57
 
58
58
  log.info(`Running build: ${buildCommand}`);
59
- const [cmd, ...args] = buildCommand.split(' ');
59
+ const [cmd, ...args] = String(buildCommand).split(' ');
60
60
  await execa(cmd, args, { cwd, stdio: 'inherit', shell: true });
61
61
  },
62
62
 
@@ -25,8 +25,13 @@ function create(config, cwd) {
25
25
  },
26
26
 
27
27
  async build() {
28
- log.info(`Running: ${config.buildCommand}`);
29
- const [cmd, ...args] = config.buildCommand.split(' ');
28
+ const buildCommand = config.buildCommand;
29
+ if (buildCommand == null || String(buildCommand).trim() === '') {
30
+ log.info('No build step required — skipping');
31
+ return;
32
+ }
33
+ log.info(`Running: ${buildCommand}`);
34
+ const [cmd, ...args] = String(buildCommand).split(' ');
30
35
  await execa(cmd, args, { cwd, stdio: 'inherit', shell: true });
31
36
  },
32
37
 
@@ -34,8 +34,13 @@ function create(config, cwd) {
34
34
  },
35
35
 
36
36
  async build() {
37
- log.info(`Running: ${config.buildCommand}`);
38
- const [cmd, ...args] = config.buildCommand.split(' ');
37
+ const buildCommand = config.buildCommand;
38
+ if (buildCommand == null || String(buildCommand).trim() === '') {
39
+ log.info('No build step required — skipping');
40
+ return;
41
+ }
42
+ log.info(`Running: ${buildCommand}`);
43
+ const [cmd, ...args] = String(buildCommand).split(' ');
39
44
  await execa(cmd, args, { cwd, stdio: 'inherit', shell: true });
40
45
  },
41
46
 
@@ -40,13 +40,20 @@ function create(config, cwd) {
40
40
  },
41
41
 
42
42
  async build() {
43
- const buildCommand = config.buildCommand || 'bundle exec rails assets:precompile';
44
- if (!buildCommand) {
45
- log.info('No build command configured, skipping');
43
+ // Explicit null/"" means skip (API-only Rails, etc.). Undefined keeps the
44
+ // conventional assets:precompile default from the Rails detector.
45
+ if (config.buildCommand === null || config.buildCommand === '') {
46
+ log.info('No build step required — skipping');
47
+ return;
48
+ }
49
+ const buildCommand =
50
+ config.buildCommand || 'bundle exec rails assets:precompile';
51
+ if (!String(buildCommand).trim()) {
52
+ log.info('No build step required — skipping');
46
53
  return;
47
54
  }
48
55
  log.info(`Running build: ${buildCommand}`);
49
- const [cmd, ...args] = buildCommand.split(' ');
56
+ const [cmd, ...args] = String(buildCommand).split(' ');
50
57
  await execa(cmd, args, { cwd, stdio: 'inherit', shell: true });
51
58
  },
52
59