futrou 2.0.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.
- package/LICENSE +21 -0
- package/README.md +27 -0
- package/bin/futrou-darwin-amd64 +0 -0
- package/bin/futrou-darwin-arm64 +0 -0
- package/bin/futrou-linux-amd64 +0 -0
- package/bin/futrou-linux-arm64 +0 -0
- package/bin/futrou-windows-amd64.exe +0 -0
- package/bin/futrou-windows-arm64.exe +0 -0
- package/index.cjs +46 -0
- package/index.d.ts +1 -0
- package/install.ps1 +186 -0
- package/install.sh +246 -0
- package/package.json +34 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 futrou.com
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Futrou CLI
|
|
2
|
+
|
|
3
|
+
The **Futrou CLI** allows you to manage your Futrou projects and infrastructure from your terminal.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
To install the CLI globally, run:
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install -g futrou
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Or use any other favorite package manager:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
yarn global add futrou
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
Once installed, you can access the CLI using the `npx futrou` command.
|
|
21
|
+
|
|
22
|
+
## Documentation
|
|
23
|
+
|
|
24
|
+
For more detailed guides on how to use the CLI, please visit [docs.futrou.com](https://docs.futrou.com).
|
|
25
|
+
|
|
26
|
+
## License
|
|
27
|
+
[MIT License](LICENSE)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/index.cjs
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { execFileSync } = require('child_process');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
|
|
8
|
+
const pkg = require('./package.json');
|
|
9
|
+
const DIST_NAME = pkg.name;
|
|
10
|
+
const NAME = pkg.productName || pkg.name;
|
|
11
|
+
|
|
12
|
+
const PLATFORMS = [
|
|
13
|
+
{ platform: 'linux', arch: 'x64', goos: 'linux', goarch: 'amd64' },
|
|
14
|
+
{ platform: 'linux', arch: 'arm64', goos: 'linux', goarch: 'arm64' },
|
|
15
|
+
{ platform: 'darwin', arch: 'x64', goos: 'darwin', goarch: 'amd64' },
|
|
16
|
+
{ platform: 'darwin', arch: 'arm64', goos: 'darwin', goarch: 'arm64' },
|
|
17
|
+
{ platform: 'win32', arch: 'x64', goos: 'windows', goarch: 'amd64' },
|
|
18
|
+
{ platform: 'win32', arch: 'arm64', goos: 'windows', goarch: 'arm64' },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
function getBinaryName() {
|
|
22
|
+
const platform = os.platform();
|
|
23
|
+
const arch = os.arch();
|
|
24
|
+
|
|
25
|
+
const entry = PLATFORMS.find(e => e.platform === platform && e.arch === arch);
|
|
26
|
+
|
|
27
|
+
if (!entry) {
|
|
28
|
+
const list = PLATFORMS.map(e => ` ${e.platform}/${e.arch}`).join('\n');
|
|
29
|
+
process.stderr.write(
|
|
30
|
+
`Unsupported platform: ${platform}/${arch}\n` +
|
|
31
|
+
`${NAME} supports:\n${list}\n`
|
|
32
|
+
);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const ext = platform === 'win32' ? '.exe' : '';
|
|
37
|
+
return `${DIST_NAME}-${entry.goos}-${entry.goarch}${ext}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const bin = path.join(__dirname, 'bin', getBinaryName());
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
execFileSync(bin, process.argv.slice(2), { stdio: 'inherit' });
|
|
44
|
+
} catch (err) {
|
|
45
|
+
process.exit(err.status ?? 1);
|
|
46
|
+
}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/install.ps1
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env pwsh
|
|
2
|
+
param(
|
|
3
|
+
[String]$Version = "latest",
|
|
4
|
+
[Switch]$NoPathUpdate = $false,
|
|
5
|
+
[Switch]$DownloadWithoutCurl = $false
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
$ErrorActionPreference = "Stop"
|
|
9
|
+
|
|
10
|
+
# ---------------------------------------------------------------------------
|
|
11
|
+
# Colors
|
|
12
|
+
# ---------------------------------------------------------------------------
|
|
13
|
+
$C_RESET = [char]27 + "[0m"
|
|
14
|
+
$C_GREEN = [char]27 + "[1;32m"
|
|
15
|
+
$C_YELLOW = [char]27 + "[0;33m"
|
|
16
|
+
$C_DIM = [char]27 + "[2m"
|
|
17
|
+
$C_RED = [char]27 + "[0;31m"
|
|
18
|
+
|
|
19
|
+
function Write-Info { param($msg) Write-Output "${C_DIM}${msg}${C_RESET}" }
|
|
20
|
+
function Write-Success{ param($msg) Write-Output "${C_GREEN}${msg}${C_RESET}" }
|
|
21
|
+
function Write-Warn { param($msg) Write-Output "${C_YELLOW}${msg}${C_RESET}" }
|
|
22
|
+
function Write-Fail { param($msg) Write-Output "${C_RED}error: ${msg}${C_RESET}"; exit 1 }
|
|
23
|
+
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
# Detect architecture from registry (reliable under ARM64 emulation)
|
|
26
|
+
# ---------------------------------------------------------------------------
|
|
27
|
+
$Arch = (Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment').PROCESSOR_ARCHITECTURE
|
|
28
|
+
|
|
29
|
+
if (-not ($Arch -eq "AMD64" -or $Arch -eq "ARM64")) {
|
|
30
|
+
Write-Fail "Futrou CLI only supports x86_64 and ARM64 Windows."
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
$GoArch = if ($Arch -eq "ARM64") { "arm64" } else { "amd64" }
|
|
34
|
+
$Target = "windows-$GoArch"
|
|
35
|
+
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
# Resolve version
|
|
38
|
+
# ---------------------------------------------------------------------------
|
|
39
|
+
if ($Version -match "^\d+\.\d+\.\d+$") { $Version = "v$Version" }
|
|
40
|
+
|
|
41
|
+
$BaseURL = "https://github.com/futrou/futrou-cli/releases"
|
|
42
|
+
$FileName = "futrou-$Target.exe"
|
|
43
|
+
$URL = if ($Version -eq "latest") {
|
|
44
|
+
"$BaseURL/latest/download/$FileName"
|
|
45
|
+
} else {
|
|
46
|
+
"$BaseURL/download/$Version/$FileName"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# ---------------------------------------------------------------------------
|
|
50
|
+
# Install location (%USERPROFILE%\.futrou\bin\futrou.exe)
|
|
51
|
+
# ---------------------------------------------------------------------------
|
|
52
|
+
$InstallRoot = if ($env:FUTROU_INSTALL) { $env:FUTROU_INSTALL } else { "$HOME\.futrou" }
|
|
53
|
+
$BinDir = "$InstallRoot\bin"
|
|
54
|
+
$Exe = "$BinDir\futrou.exe"
|
|
55
|
+
|
|
56
|
+
$null = New-Item -ItemType Directory -Force -Path $BinDir
|
|
57
|
+
|
|
58
|
+
# ---------------------------------------------------------------------------
|
|
59
|
+
# Detect existing installation and decide action label
|
|
60
|
+
# ---------------------------------------------------------------------------
|
|
61
|
+
$Action = "Installing"
|
|
62
|
+
$CurrentVersion = $null
|
|
63
|
+
|
|
64
|
+
if (Test-Path $Exe) {
|
|
65
|
+
try {
|
|
66
|
+
$raw = & $Exe --version 2>$null
|
|
67
|
+
if ($raw -match '(\d+\.\d+\.\d+)') { $CurrentVersion = $Matches[1] }
|
|
68
|
+
} catch { }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if ($CurrentVersion -and $Version -ne "latest") {
|
|
72
|
+
$TargetVersion = $Version.TrimStart('v')
|
|
73
|
+
if ($CurrentVersion -eq $TargetVersion) {
|
|
74
|
+
Write-Info "Futrou CLI v$CurrentVersion is already installed at $Exe"
|
|
75
|
+
exit 0
|
|
76
|
+
}
|
|
77
|
+
$cur = [Version]$CurrentVersion
|
|
78
|
+
$tgt = [Version]$TargetVersion
|
|
79
|
+
$Action = if ($tgt -gt $cur) { "Upgrading" } elseif ($tgt -lt $cur) { "Downgrading" } else { "Reinstalling" }
|
|
80
|
+
} elseif ($CurrentVersion) {
|
|
81
|
+
$Action = "Upgrading"
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
$DisplayVersion = if ($Version -eq "latest") { "latest" } else { $Version.TrimStart('v') }
|
|
85
|
+
|
|
86
|
+
if ($CurrentVersion) {
|
|
87
|
+
Write-Info "$Action Futrou CLI v$CurrentVersion → v$DisplayVersion"
|
|
88
|
+
} else {
|
|
89
|
+
Write-Info "Installing Futrou CLI v$DisplayVersion"
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
# ---------------------------------------------------------------------------
|
|
93
|
+
# Download
|
|
94
|
+
# ---------------------------------------------------------------------------
|
|
95
|
+
$TmpExe = "$BinDir\futrou-tmp.exe"
|
|
96
|
+
Remove-Item -Force $TmpExe -ErrorAction SilentlyContinue
|
|
97
|
+
|
|
98
|
+
$downloaded = $false
|
|
99
|
+
|
|
100
|
+
if (-not $DownloadWithoutCurl) {
|
|
101
|
+
try {
|
|
102
|
+
curl.exe "-#SfLo" $TmpExe $URL
|
|
103
|
+
if ($LASTEXITCODE -eq 0) { $downloaded = $true }
|
|
104
|
+
} catch { }
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (-not $downloaded) {
|
|
108
|
+
try {
|
|
109
|
+
Invoke-RestMethod -Uri $URL -OutFile $TmpExe
|
|
110
|
+
$downloaded = $true
|
|
111
|
+
} catch {
|
|
112
|
+
Write-Fail "Could not download $URL`n$_"
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (-not (Test-Path $TmpExe)) {
|
|
117
|
+
Write-Fail "Download produced no file. Did antivirus delete it?"
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
try { Remove-Item -Force $Exe -ErrorAction SilentlyContinue } catch { }
|
|
121
|
+
Move-Item -Force $TmpExe $Exe
|
|
122
|
+
|
|
123
|
+
# ---------------------------------------------------------------------------
|
|
124
|
+
# Verify
|
|
125
|
+
# ---------------------------------------------------------------------------
|
|
126
|
+
$InstalledVersion = $null
|
|
127
|
+
try {
|
|
128
|
+
$raw = & $Exe --version 2>$null
|
|
129
|
+
if ($raw -match '(\d+\.\d+\.\d+)') { $InstalledVersion = $Matches[1] }
|
|
130
|
+
} catch { }
|
|
131
|
+
|
|
132
|
+
if (-not $InstalledVersion) {
|
|
133
|
+
Write-Fail "Installed binary did not run correctly."
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
$ActionPast = switch ($Action) {
|
|
137
|
+
"Installing" { "installed" }
|
|
138
|
+
"Upgrading" { "upgraded" }
|
|
139
|
+
"Downgrading" { "downgraded" }
|
|
140
|
+
default { "installed" }
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
Write-Success "Futrou CLI v$InstalledVersion was $ActionPast to $Exe"
|
|
144
|
+
|
|
145
|
+
# ---------------------------------------------------------------------------
|
|
146
|
+
# PATH update
|
|
147
|
+
# ---------------------------------------------------------------------------
|
|
148
|
+
function Get-UserPath {
|
|
149
|
+
$key = (Get-Item 'HKCU:').OpenSubKey('Environment')
|
|
150
|
+
$key.GetValue('Path', $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function Set-UserPath([String]$Value) {
|
|
154
|
+
$key = (Get-Item 'HKCU:').OpenSubKey('Environment', $true)
|
|
155
|
+
$kind = if ($Value.Contains('%')) {
|
|
156
|
+
[Microsoft.Win32.RegistryValueKind]::ExpandString
|
|
157
|
+
} else {
|
|
158
|
+
[Microsoft.Win32.RegistryValueKind]::String
|
|
159
|
+
}
|
|
160
|
+
$key.SetValue('Path', $Value, $kind)
|
|
161
|
+
|
|
162
|
+
if (-not ("Win32.NativeMethods" -as [Type])) {
|
|
163
|
+
Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @"
|
|
164
|
+
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
|
|
165
|
+
public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, UIntPtr wParam,
|
|
166
|
+
string lParam, uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);
|
|
167
|
+
"@
|
|
168
|
+
}
|
|
169
|
+
$result = [UIntPtr]::Zero
|
|
170
|
+
[Win32.NativeMethods]::SendMessageTimeout(
|
|
171
|
+
[IntPtr]0xffff, 0x1a, [UIntPtr]::Zero, "Environment", 2, 5000, [ref]$result
|
|
172
|
+
) | Out-Null
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (-not $NoPathUpdate) {
|
|
176
|
+
$CurrentPath = (Get-UserPath) -split ';' | Where-Object { $_ -ne '' }
|
|
177
|
+
if ($CurrentPath -notcontains $BinDir) {
|
|
178
|
+
$NewPath = ($CurrentPath + $BinDir) -join ';'
|
|
179
|
+
Set-UserPath $NewPath
|
|
180
|
+
$env:PATH = $env:PATH + ";$BinDir"
|
|
181
|
+
Write-Info "Added $BinDir to your PATH"
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
Write-Output ""
|
|
186
|
+
Write-Output "To get started, restart your terminal, then run: futrou --help"
|
package/install.sh
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# On Windows under Git Bash / MINGW, delegate to PowerShell
|
|
5
|
+
if [[ ${OS:-} = Windows_NT ]]; then
|
|
6
|
+
if [[ ${MSYSTEM:-} != MINGW64* ]]; then
|
|
7
|
+
powershell -c "irm https://raw.githubusercontent.com/futrou/futrou-cli/main/install.ps1 | iex"
|
|
8
|
+
exit $?
|
|
9
|
+
fi
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
# ---------------------------------------------------------------------------
|
|
13
|
+
# Colors (only when stdout is a terminal)
|
|
14
|
+
# ---------------------------------------------------------------------------
|
|
15
|
+
Color_Off=''
|
|
16
|
+
Red=''
|
|
17
|
+
Green=''
|
|
18
|
+
Yellow=''
|
|
19
|
+
Dim=''
|
|
20
|
+
Bold_White=''
|
|
21
|
+
Bold_Green=''
|
|
22
|
+
|
|
23
|
+
if [[ -t 1 ]]; then
|
|
24
|
+
Color_Off='\033[0m'
|
|
25
|
+
Red='\033[0;31m'
|
|
26
|
+
Green='\033[0;32m'
|
|
27
|
+
Yellow='\033[0;33m'
|
|
28
|
+
Dim='\033[0;2m'
|
|
29
|
+
Bold_Green='\033[1;32m'
|
|
30
|
+
Bold_White='\033[1m'
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
error() { echo -e "${Red}error${Color_Off}:" "$@" >&2; exit 1; }
|
|
34
|
+
info() { echo -e "${Dim}$@${Color_Off}"; }
|
|
35
|
+
info_bold() { echo -e "${Bold_White}$@${Color_Off}"; }
|
|
36
|
+
success() { echo -e "${Bold_Green}$@${Color_Off}"; }
|
|
37
|
+
warn() { echo -e "${Yellow}$@${Color_Off}"; }
|
|
38
|
+
|
|
39
|
+
# ---------------------------------------------------------------------------
|
|
40
|
+
# Detect platform
|
|
41
|
+
# ---------------------------------------------------------------------------
|
|
42
|
+
platform=$(uname -ms)
|
|
43
|
+
|
|
44
|
+
case $platform in
|
|
45
|
+
'Darwin x86_64') target=darwin-amd64 ;;
|
|
46
|
+
'Darwin arm64') target=darwin-arm64 ;;
|
|
47
|
+
'Linux x86_64') target=linux-amd64 ;;
|
|
48
|
+
'Linux aarch64' | 'Linux arm64') target=linux-arm64 ;;
|
|
49
|
+
'MINGW64'*'ARM64'* | 'MINGW64'*'aarch64'*) target=windows-arm64 ;;
|
|
50
|
+
'MINGW64'*) target=windows-amd64 ;;
|
|
51
|
+
*)
|
|
52
|
+
error "Unsupported platform: $platform
|
|
53
|
+
Futrou CLI supports: linux/x86_64, linux/aarch64, darwin/x86_64, darwin/arm64, windows/x86_64, windows/arm64"
|
|
54
|
+
;;
|
|
55
|
+
esac
|
|
56
|
+
|
|
57
|
+
# Rosetta 2 detection on macOS
|
|
58
|
+
if [[ $target == darwin-amd64 ]]; then
|
|
59
|
+
if [[ $(sysctl -n sysctl.proc_translated 2>/dev/null) == 1 ]]; then
|
|
60
|
+
target=darwin-arm64
|
|
61
|
+
info "Rosetta 2 detected — downloading futrou for $target instead"
|
|
62
|
+
fi
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
exe_ext=''
|
|
66
|
+
[[ $target == windows-* ]] && exe_ext='.exe'
|
|
67
|
+
|
|
68
|
+
# ---------------------------------------------------------------------------
|
|
69
|
+
# Resolve version
|
|
70
|
+
# ---------------------------------------------------------------------------
|
|
71
|
+
GITHUB=${GITHUB:-"https://github.com"}
|
|
72
|
+
REPO="$GITHUB/futrou/futrou-cli"
|
|
73
|
+
|
|
74
|
+
if [[ $# -eq 0 ]]; then
|
|
75
|
+
version="latest"
|
|
76
|
+
else
|
|
77
|
+
version="$1"
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
# Normalise: accept "1.2.3" or "v1.2.3" → "v1.2.3"
|
|
81
|
+
if [[ $version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
82
|
+
version="v$version"
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
if [[ $version == "latest" ]]; then
|
|
86
|
+
download_url="$REPO/releases/latest/download/futrou-$target$exe_ext"
|
|
87
|
+
else
|
|
88
|
+
download_url="$REPO/releases/download/$version/futrou-$target$exe_ext"
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# ---------------------------------------------------------------------------
|
|
92
|
+
# Install location (~/.futrou/bin/futrou)
|
|
93
|
+
# ---------------------------------------------------------------------------
|
|
94
|
+
install_env=FUTROU_INSTALL
|
|
95
|
+
install_dir=${FUTROU_INSTALL:-$HOME/.futrou}
|
|
96
|
+
bin_dir="$install_dir/bin"
|
|
97
|
+
exe="$bin_dir/futrou$exe_ext"
|
|
98
|
+
|
|
99
|
+
mkdir -p "$bin_dir" || error "Failed to create install directory \"$bin_dir\""
|
|
100
|
+
|
|
101
|
+
# ---------------------------------------------------------------------------
|
|
102
|
+
# Detect existing installation and decide action label
|
|
103
|
+
# ---------------------------------------------------------------------------
|
|
104
|
+
action="Installing"
|
|
105
|
+
current_version=""
|
|
106
|
+
|
|
107
|
+
if [[ -x "$exe" ]]; then
|
|
108
|
+
current_version=$("$exe" --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
if [[ -n "$current_version" && "$version" != "latest" ]]; then
|
|
112
|
+
target_version="${version#v}"
|
|
113
|
+
if [[ "$current_version" == "$target_version" ]]; then
|
|
114
|
+
info "Futrou CLI v$current_version is already installed at $exe"
|
|
115
|
+
exit 0
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
# Compare semver: split into parts and compare numerically
|
|
119
|
+
IFS='.' read -r cur_maj cur_min cur_pat <<< "$current_version"
|
|
120
|
+
IFS='.' read -r tgt_maj tgt_min tgt_pat <<< "$target_version"
|
|
121
|
+
|
|
122
|
+
if (( tgt_maj > cur_maj )) || \
|
|
123
|
+
(( tgt_maj == cur_maj && tgt_min > cur_min )) || \
|
|
124
|
+
(( tgt_maj == cur_maj && tgt_min == cur_min && tgt_pat > cur_pat )); then
|
|
125
|
+
action="Upgrading"
|
|
126
|
+
else
|
|
127
|
+
action="Downgrading"
|
|
128
|
+
fi
|
|
129
|
+
elif [[ -n "$current_version" ]]; then
|
|
130
|
+
action="Upgrading"
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
display_version="${version#v}"
|
|
134
|
+
[[ $version == "latest" ]] && display_version="latest"
|
|
135
|
+
|
|
136
|
+
if [[ -n "$current_version" ]]; then
|
|
137
|
+
info "$action Futrou CLI v$current_version → v$display_version"
|
|
138
|
+
else
|
|
139
|
+
info "Installing Futrou CLI v$display_version"
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
# ---------------------------------------------------------------------------
|
|
143
|
+
# Download
|
|
144
|
+
# ---------------------------------------------------------------------------
|
|
145
|
+
if command -v curl >/dev/null 2>&1; then
|
|
146
|
+
curl --fail --location --progress-bar --output "$exe" "$download_url" ||
|
|
147
|
+
error "Failed to download from \"$download_url\""
|
|
148
|
+
elif command -v wget >/dev/null 2>&1; then
|
|
149
|
+
wget -q --show-progress -O "$exe" "$download_url" ||
|
|
150
|
+
error "Failed to download from \"$download_url\""
|
|
151
|
+
else
|
|
152
|
+
error "curl or wget is required to install Futrou CLI"
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
chmod +x "$exe"
|
|
156
|
+
|
|
157
|
+
# ---------------------------------------------------------------------------
|
|
158
|
+
# Verify
|
|
159
|
+
# ---------------------------------------------------------------------------
|
|
160
|
+
installed_version=$("$exe" --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)
|
|
161
|
+
[[ -z $installed_version ]] && error "Downloaded binary failed to run"
|
|
162
|
+
|
|
163
|
+
success "Futrou CLI v$installed_version was ${action,,} to $exe"
|
|
164
|
+
|
|
165
|
+
# ---------------------------------------------------------------------------
|
|
166
|
+
# PATH setup (skip if already in PATH)
|
|
167
|
+
# ---------------------------------------------------------------------------
|
|
168
|
+
if command -v futrou >/dev/null 2>&1; then
|
|
169
|
+
echo
|
|
170
|
+
info "Run 'futrou --help' to get started"
|
|
171
|
+
exit 0
|
|
172
|
+
fi
|
|
173
|
+
|
|
174
|
+
tildify() {
|
|
175
|
+
[[ $1 == $HOME/* ]] && echo "~/${1#$HOME/}" || echo "$1"
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
tilde_bin_dir=$(tildify "$bin_dir")
|
|
179
|
+
quoted_install_dir="\"${install_dir//\"/\\\"}\""
|
|
180
|
+
[[ $quoted_install_dir == \"$HOME/* ]] && quoted_install_dir="${quoted_install_dir/$HOME\//\$HOME/}"
|
|
181
|
+
|
|
182
|
+
echo
|
|
183
|
+
|
|
184
|
+
case $(basename "${SHELL:-bash}") in
|
|
185
|
+
fish)
|
|
186
|
+
fish_config=$HOME/.config/fish/config.fish
|
|
187
|
+
tilde_fish_config=$(tildify "$fish_config")
|
|
188
|
+
commands=(
|
|
189
|
+
"set --export $install_env $quoted_install_dir"
|
|
190
|
+
"set --export PATH \$$install_env/bin \$PATH"
|
|
191
|
+
)
|
|
192
|
+
if [[ -w $fish_config ]]; then
|
|
193
|
+
{ echo; echo '# futrou'; for cmd in "${commands[@]}"; do echo "$cmd"; done; } >> "$fish_config"
|
|
194
|
+
info "Added \"$tilde_bin_dir\" to \$PATH in \"$tilde_fish_config\""
|
|
195
|
+
info_bold " source $tilde_fish_config"
|
|
196
|
+
else
|
|
197
|
+
info "Manually add to $tilde_fish_config:"
|
|
198
|
+
for cmd in "${commands[@]}"; do info_bold " $cmd"; done
|
|
199
|
+
fi
|
|
200
|
+
;;
|
|
201
|
+
zsh)
|
|
202
|
+
zsh_config=$HOME/.zshrc
|
|
203
|
+
tilde_zsh_config=$(tildify "$zsh_config")
|
|
204
|
+
commands=(
|
|
205
|
+
"export $install_env=$quoted_install_dir"
|
|
206
|
+
"export PATH=\"\$$install_env/bin:\$PATH\""
|
|
207
|
+
)
|
|
208
|
+
if [[ -w $zsh_config ]]; then
|
|
209
|
+
{ echo; echo '# futrou'; for cmd in "${commands[@]}"; do echo "$cmd"; done; } >> "$zsh_config"
|
|
210
|
+
info "Added \"$tilde_bin_dir\" to \$PATH in \"$tilde_zsh_config\""
|
|
211
|
+
info_bold " exec \$SHELL"
|
|
212
|
+
else
|
|
213
|
+
info "Manually add to $tilde_zsh_config:"
|
|
214
|
+
for cmd in "${commands[@]}"; do info_bold " $cmd"; done
|
|
215
|
+
fi
|
|
216
|
+
;;
|
|
217
|
+
bash)
|
|
218
|
+
commands=(
|
|
219
|
+
"export $install_env=$quoted_install_dir"
|
|
220
|
+
"export PATH=\"\$$install_env/bin:\$PATH\""
|
|
221
|
+
)
|
|
222
|
+
set_manually=true
|
|
223
|
+
for bash_config in "$HOME/.bash_profile" "$HOME/.bashrc"; do
|
|
224
|
+
if [[ -w $bash_config ]]; then
|
|
225
|
+
{ echo; echo '# futrou'; for cmd in "${commands[@]}"; do echo "$cmd"; done; } >> "$bash_config"
|
|
226
|
+
info "Added \"$tilde_bin_dir\" to \$PATH in \"$(tildify "$bash_config")\""
|
|
227
|
+
info_bold " source $(tildify "$bash_config")"
|
|
228
|
+
set_manually=false
|
|
229
|
+
break
|
|
230
|
+
fi
|
|
231
|
+
done
|
|
232
|
+
if [[ $set_manually == true ]]; then
|
|
233
|
+
info "Manually add to ~/.bashrc:"
|
|
234
|
+
for cmd in "${commands[@]}"; do info_bold " $cmd"; done
|
|
235
|
+
fi
|
|
236
|
+
;;
|
|
237
|
+
*)
|
|
238
|
+
info "Manually add \"$tilde_bin_dir\" to your \$PATH:"
|
|
239
|
+
info_bold " export $install_env=$quoted_install_dir"
|
|
240
|
+
info_bold " export PATH=\"\$$install_env/bin:\$PATH\""
|
|
241
|
+
;;
|
|
242
|
+
esac
|
|
243
|
+
|
|
244
|
+
echo
|
|
245
|
+
info "To get started, run:"
|
|
246
|
+
info_bold " futrou --help"
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "futrou",
|
|
3
|
+
"productName": "Futrou CLI",
|
|
4
|
+
"version": "2.0.0",
|
|
5
|
+
"description": "Futrou CLI - Deploy and manage Futrou Cloud from your terminal.",
|
|
6
|
+
"bin": {
|
|
7
|
+
"futrou": "./index.cjs",
|
|
8
|
+
"futrou-cli": "./index.cjs"
|
|
9
|
+
},
|
|
10
|
+
"types": "./index.d.ts",
|
|
11
|
+
"os": [
|
|
12
|
+
"linux",
|
|
13
|
+
"darwin",
|
|
14
|
+
"win32"
|
|
15
|
+
],
|
|
16
|
+
"cpu": [
|
|
17
|
+
"x64",
|
|
18
|
+
"arm64"
|
|
19
|
+
],
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=16"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"futrou",
|
|
25
|
+
"cloud",
|
|
26
|
+
"deploy",
|
|
27
|
+
"cli"
|
|
28
|
+
],
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/futrou/futrou-cli.git"
|
|
33
|
+
}
|
|
34
|
+
}
|