mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-14 12:16:54 +00:00
feat(desktop): packaging, auto-update, CI/CD, and install scripts
- GitHub Actions: release-desktop.yaml builds macOS (arm64+amd64) + Windows on lite-v* tag push, creates DMG + tar.gz + zip GitHub Release assets - Install scripts: install-lite.sh (macOS curl) + install-lite.ps1 (Windows PowerShell) - Auto-update: internal/updater checks GitHub Releases, downloads + atomic app swap with path traversal guards, size limits, symlink handling - UpdateBanner: thin notification bar with download progress + restart - Wails bindings: CheckForUpdate, ApplyUpdate (server-cached, no URL from JS), RestartApp (graceful gateway shutdown before exit) - AboutTab: dynamic version from backend via GetVersion() - Windows build assets: icon.ico, info.json, wails.exe.manifest - Makefile: desktop-dev, desktop-build, desktop-dmg targets - README: Desktop Edition section with install commands + feature comparison - .gitignore: desktop packaging artifacts, SQLite DB files, update backups Security: HTTPS-only downloads, io.LimitReader on all extractions, zip/tar path traversal validation, symlink target guard, no untrusted URL from frontend (ApplyUpdate uses server-cached info).
This commit is contained in:
1 parent
30708ae79d
commit
b9c1731e31
18 files changed
+1095
-3
No files matched your search
@@ -0,0 +1,57 @@
|
||||
# GoClaw Lite (Desktop) installer for Windows
|
||||
# Usage:
|
||||
# irm https://raw.githubusercontent.com/nextlevelbuilder/goclaw/main/scripts/install-lite.ps1 | iex
|
||||
# .\install-lite.ps1 -Version lite-v0.1.0
|
||||
|
||||
param([string]$Version = "")
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$Repo = "nextlevelbuilder/goclaw"
|
||||
$InstallDir = "$env:LOCALAPPDATA\GoClaw Lite"
|
||||
|
||||
# Resolve latest version
|
||||
if (-not $Version) {
|
||||
Write-Host "-> Fetching latest desktop release..."
|
||||
$releases = Invoke-RestMethod "https://api.github.com/repos/$Repo/releases"
|
||||
$latest = $releases | Where-Object { $_.tag_name -like "lite-v*" -and -not $_.prerelease -and -not $_.draft } | Select-Object -First 1
|
||||
if (-not $latest) {
|
||||
Write-Error "No desktop release found. Check https://github.com/$Repo/releases"
|
||||
exit 1
|
||||
}
|
||||
$Version = $latest.tag_name
|
||||
}
|
||||
|
||||
$Semver = $Version -replace "^lite-v", ""
|
||||
Write-Host "-> Installing GoClaw Lite v$Semver..."
|
||||
|
||||
# Download
|
||||
$Asset = "goclaw-lite-$Semver-windows-amd64.zip"
|
||||
$Url = "https://github.com/$Repo/releases/download/$Version/$Asset"
|
||||
$TmpZip = Join-Path $env:TEMP $Asset
|
||||
|
||||
Write-Host "-> Downloading $Url..."
|
||||
Invoke-WebRequest -Uri $Url -OutFile $TmpZip -UseBasicParsing
|
||||
|
||||
# Extract
|
||||
Write-Host "-> Installing to $InstallDir..."
|
||||
New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
|
||||
Expand-Archive -Path $TmpZip -DestinationPath $InstallDir -Force
|
||||
Remove-Item $TmpZip -Force
|
||||
|
||||
# Create Start Menu shortcut
|
||||
$ExePath = Join-Path $InstallDir "goclaw-lite.exe"
|
||||
if (Test-Path $ExePath) {
|
||||
$ShortcutPath = Join-Path ([Environment]::GetFolderPath("StartMenu")) "Programs\GoClaw Lite.lnk"
|
||||
$Shell = New-Object -ComObject WScript.Shell
|
||||
$Shortcut = $Shell.CreateShortcut($ShortcutPath)
|
||||
$Shortcut.TargetPath = $ExePath
|
||||
$Shortcut.WorkingDirectory = $InstallDir
|
||||
$Shortcut.Save()
|
||||
Write-Host "-> Start Menu shortcut created"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "GoClaw Lite v$Semver installed to $InstallDir" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "To launch: Start Menu -> GoClaw Lite"
|
||||
Write-Host "Or run: & '$ExePath'"
|
||||
Executable
+105
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env bash
|
||||
# GoClaw Lite (Desktop) installer — downloads the latest .app from GitHub Releases.
|
||||
#
|
||||
# Usage:
|
||||
# curl -fsSL https://raw.githubusercontent.com/nextlevelbuilder/goclaw/main/scripts/install-lite.sh | bash
|
||||
# curl -fsSL ... | bash -s -- --version lite-v0.1.0
|
||||
#
|
||||
# macOS only. Windows users: download .zip from GitHub Releases.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REPO="nextlevelbuilder/goclaw"
|
||||
INSTALL_DIR="/Applications"
|
||||
VERSION=""
|
||||
|
||||
# ── Parse args ──
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--version) VERSION="$2"; shift 2 ;;
|
||||
--help|-h)
|
||||
echo "Usage: install-lite.sh [--version lite-v1.0.0]"
|
||||
echo " Downloads and installs GoClaw Lite desktop app to /Applications/"
|
||||
exit 0
|
||||
;;
|
||||
*) echo "Unknown option: $1"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# ── Detect OS/arch ──
|
||||
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
ARCH="$(uname -m)"
|
||||
case "$ARCH" in
|
||||
x86_64) ARCH="amd64" ;;
|
||||
aarch64|arm64) ARCH="arm64" ;;
|
||||
*) echo "❌ Unsupported architecture: $ARCH"; exit 1 ;;
|
||||
esac
|
||||
|
||||
if [[ "$OS" != "darwin" ]]; then
|
||||
echo "❌ This installer is for macOS only."
|
||||
echo ""
|
||||
echo "For Windows: download .zip from https://github.com/$REPO/releases"
|
||||
echo "For Linux: not yet supported"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ── Resolve version ──
|
||||
if [[ -z "$VERSION" ]]; then
|
||||
echo "→ Fetching latest desktop release..."
|
||||
VERSION=$(curl -fsSL "https://api.github.com/repos/$REPO/releases" \
|
||||
| grep '"tag_name": "lite-v' \
|
||||
| head -1 \
|
||||
| sed 's/.*"tag_name": "\(lite-v[^"]*\)".*/\1/')
|
||||
|
||||
if [[ -z "$VERSION" ]]; then
|
||||
echo "❌ No desktop release found. Check https://github.com/$REPO/releases"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
SEMVER="${VERSION#lite-v}"
|
||||
echo "→ Installing GoClaw Lite v${SEMVER} (${ARCH})..."
|
||||
|
||||
# ── Download ──
|
||||
ASSET="goclaw-lite-${SEMVER}-darwin-${ARCH}.tar.gz"
|
||||
URL="https://github.com/$REPO/releases/download/$VERSION/$ASSET"
|
||||
TMPDIR=$(mktemp -d)
|
||||
trap 'rm -rf "$TMPDIR"' EXIT
|
||||
|
||||
echo "→ Downloading $URL..."
|
||||
if ! curl -fSL --progress-bar "$URL" -o "$TMPDIR/$ASSET"; then
|
||||
echo "❌ Download failed. Check the version and try again."
|
||||
echo " Available releases: https://github.com/$REPO/releases"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ── Extract ──
|
||||
echo "→ Extracting..."
|
||||
tar xzf "$TMPDIR/$ASSET" -C "$TMPDIR"
|
||||
|
||||
if [[ ! -d "$TMPDIR/goclaw-lite.app" ]]; then
|
||||
echo "❌ Archive does not contain goclaw-lite.app"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ── Install ──
|
||||
TARGET="$INSTALL_DIR/goclaw-lite.app"
|
||||
if [[ -d "$TARGET" ]]; then
|
||||
echo "→ Removing existing installation..."
|
||||
rm -rf "$TARGET"
|
||||
fi
|
||||
|
||||
echo "→ Installing to $TARGET..."
|
||||
cp -R "$TMPDIR/goclaw-lite.app" "$TARGET"
|
||||
|
||||
# Remove quarantine attribute (unsigned app)
|
||||
xattr -rd com.apple.quarantine "$TARGET" 2>/dev/null || true
|
||||
|
||||
echo ""
|
||||
echo "✅ GoClaw Lite v${SEMVER} installed to $TARGET"
|
||||
echo ""
|
||||
echo "To launch:"
|
||||
echo " open /Applications/goclaw-lite.app"
|
||||
echo ""
|
||||
echo "If macOS blocks the app:"
|
||||
echo " Right-click → Open → Open (first launch only)"
|
||||
Reference in new issue
Block a user