@anvil-works/anvil-cli 0.4.3 → 0.5.1

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/dist/index.js CHANGED
@@ -20042,7 +20042,8 @@ var __webpack_exports__ = {};
20042
20042
  }
20043
20043
  const configDefaults = {
20044
20044
  devMode: false,
20045
- verbose: false
20045
+ verbose: false,
20046
+ preferredEditor: ""
20046
20047
  };
20047
20048
  function isTestMode() {
20048
20049
  return "test" === process.env.NODE_ENV || !!process.env.RSTEST;
@@ -22721,6 +22722,7 @@ var __webpack_exports__ = {};
22721
22722
  });
22722
22723
  this.ws.on("error", (error)=>{
22723
22724
  logger_logger.debug(`[WebSocket ${this.sessionId}]`, `Error: ${error.message}`);
22725
+ if (this.isClosing) return;
22724
22726
  if (error.message.includes("502")) logger_logger.error(chalk_source.red("WebSocket connection failed (502 Bad Gateway) - likely a temporary server issue"));
22725
22727
  else logger_logger.error(chalk_source.red(`WebSocket error: ${error.message}`));
22726
22728
  this.emit("error", {
@@ -22821,15 +22823,20 @@ var __webpack_exports__ = {};
22821
22823
  }
22822
22824
  teardownSocket() {
22823
22825
  this.stopHeartbeat();
22824
- if (!this.ws) return;
22826
+ const socket = this.ws;
22827
+ this.ws = null;
22828
+ if (!socket) return;
22825
22829
  try {
22826
22830
  logger_logger.debug(`[WebSocket ${this.sessionId}]`, "Closing WebSocket");
22827
- this.ws.removeAllListeners();
22828
- if (this.ws.readyState === ws_wrapper.OPEN || this.ws.readyState === ws_wrapper.CONNECTING) this.ws.terminate();
22831
+ if (socket.readyState === ws_wrapper.CONNECTING) {
22832
+ socket.once("error", ()=>{});
22833
+ socket.terminate();
22834
+ return;
22835
+ }
22836
+ if (socket.readyState === ws_wrapper.OPEN) return void socket.close();
22829
22837
  } catch (e) {
22830
22838
  logger_logger.debug(`[WebSocket ${this.sessionId}]`, "Error closing WebSocket (ignoring):", e);
22831
22839
  }
22832
- this.ws = null;
22833
22840
  }
22834
22841
  }
22835
22842
  async function detectRemoteChanges(gitService, oldCommitId, newCommitId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anvil-works/anvil-cli",
3
- "version": "0.4.3",
3
+ "version": "0.5.1",
4
4
  "description": "CLI tool for developing Anvil apps locally",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -8,7 +8,8 @@
8
8
  "anvil": "./dist/cli.js"
9
9
  },
10
10
  "files": [
11
- "dist"
11
+ "dist",
12
+ "scripts/install"
12
13
  ],
13
14
  "publishConfig": {
14
15
  "access": "public"
@@ -0,0 +1,26 @@
1
+ @echo off
2
+ REM Source of truth: @anvil-works/anvil-cli (scripts/install/install.cmd).
3
+ REM This script is synced into anvil website static install endpoints; do not edit the synced copy directly.
4
+ setlocal
5
+
6
+ set "SCRIPT_URL=%ANVIL_INSTALL_URL%"
7
+ if not defined SCRIPT_URL set "SCRIPT_URL=https://anvil.works/install/anvil-cli/install.ps1"
8
+ set "SCRIPT_PATH=%TEMP%\anvil-install-%RANDOM%%RANDOM%.ps1"
9
+
10
+ where curl >nul 2>&1
11
+ if errorlevel 1 (
12
+ echo Error: curl is required but was not found.
13
+ exit /b 1
14
+ )
15
+
16
+ curl -fsSL "%SCRIPT_URL%" -o "%SCRIPT_PATH%"
17
+ if errorlevel 1 (
18
+ echo Error: failed to download installer from %SCRIPT_URL%
19
+ exit /b 1
20
+ )
21
+
22
+ powershell -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT_PATH%"
23
+ set "EXIT_CODE=%ERRORLEVEL%"
24
+
25
+ del /q "%SCRIPT_PATH%" >nul 2>&1
26
+ exit /b %EXIT_CODE%
@@ -0,0 +1,180 @@
1
+ # Source of truth: @anvil-works/anvil-cli (scripts/install/install.ps1).
2
+ # This script is synced into anvil website static install endpoints; do not edit the synced copy directly.
3
+ $ErrorActionPreference = 'Stop'
4
+ Set-StrictMode -Version Latest
5
+
6
+ $AnvilHome = if ($env:ANVIL_HOME) { $env:ANVIL_HOME } else { Join-Path $env:USERPROFILE '.anvil-cli' }
7
+ $NodeDir = Join-Path $AnvilHome 'node-v20'
8
+ $NpmPrefix = Join-Path $AnvilHome 'npm-global'
9
+ $MinTargetMajor = 20
10
+
11
+ function Write-Info([string] $Message) {
12
+ Write-Host $Message
13
+ }
14
+
15
+ function Fail([string] $Message) {
16
+ throw $Message
17
+ }
18
+
19
+ function Ensure-Directory([string] $Path) {
20
+ if (-not (Test-Path -LiteralPath $Path)) {
21
+ New-Item -ItemType Directory -Path $Path | Out-Null
22
+ }
23
+ }
24
+
25
+ function Get-PlatformArch {
26
+ if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64' -or $env:PROCESSOR_ARCHITEW6432 -eq 'ARM64') {
27
+ return 'arm64'
28
+ }
29
+ return 'x64'
30
+ }
31
+
32
+ function Get-NodeMajorFromPath {
33
+ if (-not (Get-Command node -ErrorAction SilentlyContinue)) {
34
+ return $null
35
+ }
36
+
37
+ $version = (& node -v).Trim()
38
+ if ($version -match '^v(\d+)') {
39
+ return [int]$Matches[1]
40
+ }
41
+
42
+ return $null
43
+ }
44
+
45
+ function Update-CurrentPath {
46
+ $env:Path = "$NpmPrefix;$NodeDir;$env:Path"
47
+ }
48
+
49
+ function Add-UserPathSegment([string] $Segment) {
50
+ $currentUserPath = [Environment]::GetEnvironmentVariable('Path', 'User')
51
+ if (-not $currentUserPath) {
52
+ [Environment]::SetEnvironmentVariable('Path', $Segment, 'User')
53
+ return
54
+ }
55
+
56
+ $parts = $currentUserPath -split ';' | Where-Object { $_ -ne '' }
57
+ if ($parts -contains $Segment) {
58
+ return
59
+ }
60
+
61
+ [Environment]::SetEnvironmentVariable('Path', "$Segment;$currentUserPath", 'User')
62
+ }
63
+
64
+ function Install-NodeV20 {
65
+ $arch = Get-PlatformArch
66
+ $baseUrl = 'https://nodejs.org/dist/latest-v20.x'
67
+ $sumsUrl = "$baseUrl/SHASUMS256.txt"
68
+
69
+ $tmpRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("anvil-install-" + [System.Guid]::NewGuid().ToString('N'))
70
+ Ensure-Directory -Path $tmpRoot
71
+
72
+ try {
73
+ $sumsPath = Join-Path $tmpRoot 'SHASUMS256.txt'
74
+ Invoke-WebRequest -UseBasicParsing -Uri $sumsUrl -OutFile $sumsPath
75
+
76
+ $pattern = "node-v20\.[0-9]+\.[0-9]+-win-$arch\.zip$"
77
+ $archiveLine = Get-Content -LiteralPath $sumsPath | Where-Object { $_ -match $pattern } | Select-Object -First 1
78
+ if (-not $archiveLine) {
79
+ Fail "Could not resolve Node.js archive for win-$arch"
80
+ }
81
+
82
+ $tokens = $archiveLine -split '\s+'
83
+ $archiveName = $tokens[-1]
84
+ $archivePath = Join-Path $tmpRoot $archiveName
85
+ $archiveUrl = "$baseUrl/$archiveName"
86
+
87
+ Write-Info "Installing Node.js v20 for win-$arch..."
88
+ Invoke-WebRequest -UseBasicParsing -Uri $archiveUrl -OutFile $archivePath
89
+
90
+ $expectedHash = ($tokens | Where-Object { $_ -match '^[A-Fa-f0-9]{64}$' } | Select-Object -First 1)
91
+ if ($expectedHash) {
92
+ $actualHash = (Get-FileHash -Algorithm SHA256 -LiteralPath $archivePath).Hash.ToLowerInvariant()
93
+ if ($actualHash -ne $expectedHash.ToLowerInvariant()) {
94
+ Fail 'Checksum verification failed for Node.js archive'
95
+ }
96
+ }
97
+
98
+ if (Test-Path -LiteralPath $NodeDir) {
99
+ Remove-Item -LiteralPath $NodeDir -Recurse -Force
100
+ }
101
+
102
+ Expand-Archive -LiteralPath $archivePath -DestinationPath $tmpRoot -Force
103
+ $expandedRoot = Get-ChildItem -LiteralPath $tmpRoot -Directory | Where-Object { $_.Name -like 'node-v20.*-win-*' } | Select-Object -First 1
104
+ if (-not $expandedRoot) {
105
+ Fail 'Failed to locate extracted Node.js directory'
106
+ }
107
+
108
+ Move-Item -LiteralPath $expandedRoot.FullName -Destination $NodeDir
109
+ }
110
+ finally {
111
+ if (Test-Path -LiteralPath $tmpRoot) {
112
+ Remove-Item -LiteralPath $tmpRoot -Recurse -Force
113
+ }
114
+ }
115
+ }
116
+
117
+ function Ensure-Node {
118
+ $major = Get-NodeMajorFromPath
119
+ if ($major -and $major -ge $MinTargetMajor) {
120
+ $version = (& node -v).Trim()
121
+ Write-Info "Using existing Node.js $version"
122
+ return
123
+ }
124
+
125
+ if ($major) {
126
+ Write-Info "Existing Node.js major v$major is too old; installing Node.js v20 user-local"
127
+ }
128
+
129
+ Ensure-Directory -Path $AnvilHome
130
+ Install-NodeV20
131
+ }
132
+
133
+ function Ensure-Npm {
134
+ $npmCmd = Join-Path $NodeDir 'npm.cmd'
135
+ if (Test-Path -LiteralPath $npmCmd) {
136
+ return $npmCmd
137
+ }
138
+
139
+ if (Get-Command npm -ErrorAction SilentlyContinue) {
140
+ return 'npm'
141
+ }
142
+
143
+ Fail 'npm is unavailable after Node.js setup'
144
+ }
145
+
146
+ function Main {
147
+ Ensure-Directory -Path $AnvilHome
148
+ Ensure-Directory -Path $NpmPrefix
149
+
150
+ Ensure-Node
151
+
152
+ Update-CurrentPath
153
+ Add-UserPathSegment -Segment $NodeDir
154
+ Add-UserPathSegment -Segment $NpmPrefix
155
+
156
+ $npm = Ensure-Npm
157
+
158
+ Write-Info 'Installing anvil-cli...'
159
+ & $npm config set prefix "$NpmPrefix"
160
+ & $npm install -g @anvil-works/anvil-cli@latest
161
+
162
+ $anvilCmd = Join-Path $NpmPrefix 'anvil.cmd'
163
+ if (-not (Test-Path -LiteralPath $anvilCmd)) {
164
+ $anvilCmd = 'anvil'
165
+ }
166
+
167
+ try {
168
+ $version = (& $anvilCmd --version).Trim()
169
+ }
170
+ catch {
171
+ Fail "anvil installed but command verification failed: $($_.Exception.Message)"
172
+ }
173
+
174
+ Write-Info ''
175
+ Write-Info "anvil-cli installed successfully (v$version)"
176
+ Write-Info "Next step: run 'anvil onboard'"
177
+ Write-Info "If your current terminal cannot find 'anvil', start a new terminal session."
178
+ }
179
+
180
+ Main
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env sh
2
+ # Source of truth: @anvil-works/anvil-cli (scripts/install/install.sh).
3
+ # This script is synced into anvil website static install endpoints; do not edit the synced copy directly.
4
+ set -eu
5
+
6
+ ANVIL_HOME="${ANVIL_HOME:-$HOME/.anvil-cli}"
7
+ NODE_DIR="$ANVIL_HOME/node-v20"
8
+ NPM_PREFIX="$ANVIL_HOME/npm-global"
9
+ MIN_NODE_MAJOR=20
10
+
11
+ log() {
12
+ printf '%s\n' "$*"
13
+ }
14
+
15
+ fail() {
16
+ printf 'Error: %s\n' "$*" >&2
17
+ exit 1
18
+ }
19
+
20
+ need_cmd() {
21
+ command -v "$1" >/dev/null 2>&1 || fail "Required command not found: $1"
22
+ }
23
+
24
+ append_path_export() {
25
+ profile_file="$1"
26
+ line='export PATH="$HOME/.anvil-cli/npm-global/bin:$HOME/.anvil-cli/node-v20/bin:$PATH"'
27
+
28
+ [ -f "$profile_file" ] || touch "$profile_file"
29
+ grep -F "$line" "$profile_file" >/dev/null 2>&1 || {
30
+ printf '\n%s\n' "$line" >> "$profile_file"
31
+ }
32
+ }
33
+
34
+ persist_path_hint() {
35
+ append_path_export "$HOME/.profile"
36
+
37
+ if [ -n "${ZSH_VERSION:-}" ] || [ "${SHELL:-}" = "$(command -v zsh 2>/dev/null || true)" ]; then
38
+ append_path_export "$HOME/.zshrc"
39
+ fi
40
+
41
+ if [ -n "${BASH_VERSION:-}" ] || [ "${SHELL:-}" = "$(command -v bash 2>/dev/null || true)" ]; then
42
+ append_path_export "$HOME/.bashrc"
43
+ fi
44
+ }
45
+
46
+ detect_platform() {
47
+ os_name="$(uname -s)"
48
+ arch_name="$(uname -m)"
49
+
50
+ case "$os_name" in
51
+ Darwin) platform_os="darwin" ;;
52
+ Linux) platform_os="linux" ;;
53
+ *) fail "Unsupported OS: $os_name (only macOS and Linux are supported)" ;;
54
+ esac
55
+
56
+ case "$arch_name" in
57
+ x86_64|amd64) platform_arch="x64" ;;
58
+ arm64|aarch64) platform_arch="arm64" ;;
59
+ *) fail "Unsupported architecture: $arch_name" ;;
60
+ esac
61
+ }
62
+
63
+ node_version_major() {
64
+ node -v 2>/dev/null | sed -E 's/^v([0-9]+).*/\1/'
65
+ }
66
+
67
+ install_node_v20() {
68
+ detect_platform
69
+ need_cmd curl
70
+ need_cmd tar
71
+
72
+ base_url="https://nodejs.org/dist/latest-v20.x"
73
+ sums_url="$base_url/SHASUMS256.txt"
74
+ tmp_dir="$(mktemp -d)"
75
+ trap 'rm -rf "$tmp_dir"' EXIT INT TERM
76
+
77
+ log "Installing Node.js v20 for $platform_os-$platform_arch..."
78
+ curl -fsSL "$sums_url" -o "$tmp_dir/SHASUMS256.txt"
79
+
80
+ archive_name="$(grep -E "node-v20\\.[0-9]+\\.[0-9]+-$platform_os-$platform_arch\\.tar\\.xz$" "$tmp_dir/SHASUMS256.txt" | awk '{print $2}' | head -n1)"
81
+ [ -n "$archive_name" ] || fail "Could not resolve Node.js archive for $platform_os-$platform_arch"
82
+
83
+ archive_url="$base_url/$archive_name"
84
+ archive_path="$tmp_dir/$archive_name"
85
+
86
+ curl -fsSL "$archive_url" -o "$archive_path"
87
+
88
+ if command -v shasum >/dev/null 2>&1; then
89
+ expected_sum="$(grep " $archive_name$" "$tmp_dir/SHASUMS256.txt" | awk '{print $1}' | head -n1)"
90
+ actual_sum="$(shasum -a 256 "$archive_path" | awk '{print $1}')"
91
+ [ "$expected_sum" = "$actual_sum" ] || fail "Checksum verification failed for Node.js archive"
92
+ elif command -v sha256sum >/dev/null 2>&1; then
93
+ expected_sum="$(grep " $archive_name$" "$tmp_dir/SHASUMS256.txt" | awk '{print $1}' | head -n1)"
94
+ actual_sum="$(sha256sum "$archive_path" | awk '{print $1}')"
95
+ [ "$expected_sum" = "$actual_sum" ] || fail "Checksum verification failed for Node.js archive"
96
+ else
97
+ log "Warning: no sha256 tool found; skipping checksum verification"
98
+ fi
99
+
100
+ rm -rf "$NODE_DIR"
101
+ mkdir -p "$NODE_DIR"
102
+ tar -xJf "$archive_path" -C "$NODE_DIR" --strip-components=1
103
+ }
104
+
105
+ ensure_node() {
106
+ if command -v node >/dev/null 2>&1; then
107
+ major="$(node_version_major || true)"
108
+ if [ -n "$major" ] && [ "$major" -ge "$MIN_NODE_MAJOR" ]; then
109
+ log "Using existing Node.js $(node -v)"
110
+ return
111
+ fi
112
+ log "Existing Node.js $(node -v) is too old; installing Node.js v20 user-local"
113
+ install_node_v20
114
+ return
115
+ fi
116
+
117
+ install_node_v20
118
+ }
119
+
120
+ main() {
121
+ need_cmd curl
122
+ need_cmd tar
123
+
124
+ mkdir -p "$ANVIL_HOME" "$NPM_PREFIX"
125
+
126
+ ensure_node
127
+
128
+ export PATH="$NPM_PREFIX/bin:$NODE_DIR/bin:$PATH"
129
+ persist_path_hint
130
+
131
+ need_cmd npm
132
+
133
+ log "Installing anvil-cli..."
134
+ npm config set prefix "$NPM_PREFIX" >/dev/null
135
+ NPM_CONFIG_PREFIX="$NPM_PREFIX" npm install -g @anvil-works/anvil-cli@latest
136
+
137
+ if command -v anvil >/dev/null 2>&1; then
138
+ version="$(anvil --version 2>/dev/null || true)"
139
+ elif [ -x "$NPM_PREFIX/bin/anvil" ]; then
140
+ version="$($NPM_PREFIX/bin/anvil --version 2>/dev/null || true)"
141
+ else
142
+ fail "anvil installed but command not found on PATH"
143
+ fi
144
+
145
+ log ""
146
+ log "anvil-cli installed successfully${version:+ (v$version)}"
147
+ log "Next step: run 'anvil onboard'"
148
+ log "If your current shell cannot find 'anvil', open a new terminal session."
149
+ }
150
+
151
+ main "$@"