@anvil-works/anvil-cli 0.5.0 → 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/README.md CHANGED
@@ -11,11 +11,31 @@ A CLI tool for syncing Anvil apps between your local filesystem and the Anvil ID
11
11
  - **Form Support**: Syncs forms with templates and code
12
12
  - **Theme Assets**: Syncs theme assets and configuration
13
13
 
14
- ## Installation
15
-
16
- ```bash
17
- npm install -g @anvil-works/anvil-cli
18
- ```
14
+ ## Installation
15
+
16
+ ### macOS/Linux
17
+
18
+ ```bash
19
+ curl -fsSL https://anvil.works/install/anvil-cli/install.sh | sh
20
+ ```
21
+
22
+ ### Windows PowerShell
23
+
24
+ ```powershell
25
+ irm https://anvil.works/install/anvil-cli/install.ps1 | iex
26
+ ```
27
+
28
+ ### Windows CMD
29
+
30
+ ```cmd
31
+ curl -fsSL https://anvil.works/install/anvil-cli/install.cmd -o install.cmd && install.cmd && del install.cmd
32
+ ```
33
+
34
+ ### Manual Fallback
35
+
36
+ ```bash
37
+ npm install -g @anvil-works/anvil-cli
38
+ ```
19
39
 
20
40
  ## Quick Start
21
41
 
package/dist/cli.js CHANGED
@@ -52287,9 +52287,12 @@ var __webpack_exports__ = {};
52287
52287
  console.log();
52288
52288
  console.log(chalk_source.cyan("To update, run one of the following commands:"));
52289
52289
  console.log();
52290
- console.log(chalk_source.gray(" npm: ") + chalk_source.white("npm update -g @anvil-works/anvil-cli"));
52291
- console.log(chalk_source.gray(" pnpm: ") + chalk_source.white("pnpm update -g @anvil-works/anvil-cli"));
52292
- console.log(chalk_source.gray(" yarn: ") + chalk_source.white("yarn global upgrade @anvil-works/anvil-cli"));
52290
+ if ("win32" === process.platform) {
52291
+ console.log(chalk_source.gray(" PowerShell: ") + chalk_source.white("irm https://anvil.works/install/anvil-cli/install.ps1 | iex"));
52292
+ console.log(chalk_source.gray(" CMD: ") + chalk_source.white("curl -fsSL https://anvil.works/install/anvil-cli/install.cmd -o install.cmd && install.cmd && del install.cmd"));
52293
+ } else console.log(chalk_source.gray(" macOS/Linux: ") + chalk_source.white("curl -fsSL https://anvil.works/install/anvil-cli/install.sh | sh"));
52294
+ console.log(chalk_source.gray(" npm: ") + chalk_source.white("npm update -g @anvil-works/anvil-cli"));
52295
+ console.log(chalk_source.gray(" pnpm: ") + chalk_source.white("pnpm update -g @anvil-works/anvil-cli"));
52293
52296
  console.log();
52294
52297
  } catch (e) {
52295
52298
  logger_logger.error("Error: " + e.message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anvil-works/anvil-cli",
3
- "version": "0.5.0",
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 "$@"