Skip to content

Commit c2d3820

Browse files
Add Windows binaries, install.ps1, and INSTALL.md (v0.2.1) (#78)
Cross-platform install on a single canonical entry point. No code changes; release pipeline + install UX only. - .goreleaser.yaml: add windows to goos, format_overrides for zip on Windows. v0.2.1 will publish skern_<version>_windows_amd64.zip and skern_<version>_windows_arm64.zip alongside the existing macOS and Linux tarballs. - scripts/install.ps1: PowerShell installer mirroring scripts/install.sh. Detects amd64/arm64, downloads the matching zip, verifies SHA-256 against checksums.txt, extracts to %LOCALAPPDATA%\skern\bin, and warns if the dir is not on PATH. Honors SKERN_INSTALL_DIR and SKERN_VERSION env vars (parity with the bash script). - INSTALL.md: new top-level install guide. Three OS sections (macOS / Linux / Windows), each with one canonical command. Plus verify, version pinning, manual install (releases page + checksum pattern), build-from-source (go install) as a developer fallback, and uninstall. - README: install section now shows the three OS one-liners side-by-side, with go install marked "from source" and a link to INSTALL.md for full coverage. - CHANGELOG: v0.2.1 entry. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent c0daaa2 commit c2d3820

5 files changed

Lines changed: 290 additions & 1 deletion

File tree

.goreleaser.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ builds:
1313
goos:
1414
- darwin
1515
- linux
16+
- windows
1617
goarch:
1718
- amd64
1819
- arm64
@@ -25,6 +26,9 @@ builds:
2526
archives:
2627
- format: tar.gz
2728
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
29+
format_overrides:
30+
- goos: windows
31+
format: zip
2832

2933
checksum:
3034
name_template: "checksums.txt"

CHANGELOG.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,33 @@ All notable changes to skern are documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [v0.2.1] — 2026-05-03
9+
10+
Cross-platform install. No code changes; release pipeline + install UX only.
11+
12+
### Added
13+
14+
- **Windows binaries.** Releases now publish `skern_<version>_windows_amd64.zip`
15+
and `skern_<version>_windows_arm64.zip` alongside the existing macOS and Linux
16+
tarballs. Triggered by adding `windows` to the goreleaser build matrix and a
17+
`format_overrides` rule that ships Windows as zip per convention.
18+
- **`scripts/install.ps1`** — PowerShell installer mirroring `scripts/install.sh`.
19+
Detects amd64/arm64, downloads the matching zip, verifies SHA-256 against the
20+
release's `checksums.txt`, extracts to `%LOCALAPPDATA%\skern\bin`, and warns
21+
if the install dir is not on `PATH`. Honors `SKERN_INSTALL_DIR` and
22+
`SKERN_VERSION` environment variables, same as the Unix script.
23+
- **`INSTALL.md`** at repo root — single canonical install guide with one
24+
command per OS (macOS / Linux / Windows), plus version-pinning, manual
25+
install, source build, and uninstall sections. Designed as a clean structured
26+
doc that an LLM agent can follow end-to-end.
27+
28+
### Changed
29+
30+
- README install section now shows the three OS one-liners side-by-side and
31+
links to `INSTALL.md` for full coverage.
32+
33+
[v0.2.1]: https://github.com/devrimcavusoglu/skern/compare/v0.2.0...v0.2.1
34+
835
## [v0.2.0] — 2026-05-03
936

1037
Dynamic skill loading release. **Contains breaking changes.**

INSTALL.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Installing skern
2+
3+
Pick the section that matches your operating system. Each section contains exactly one install command. After running it, verify with `skern --version`.
4+
5+
## macOS
6+
7+
```sh
8+
curl -fsSL https://raw.githubusercontent.com/devrimcavusoglu/skern/main/scripts/install.sh | bash
9+
```
10+
11+
## Linux
12+
13+
```sh
14+
curl -fsSL https://raw.githubusercontent.com/devrimcavusoglu/skern/main/scripts/install.sh | bash
15+
```
16+
17+
## Windows
18+
19+
```powershell
20+
irm https://raw.githubusercontent.com/devrimcavusoglu/skern/main/scripts/install.ps1 | iex
21+
```
22+
23+
If your PowerShell execution policy blocks the script:
24+
25+
```powershell
26+
powershell -ExecutionPolicy Bypass -Command "irm https://raw.githubusercontent.com/devrimcavusoglu/skern/main/scripts/install.ps1 | iex"
27+
```
28+
29+
## Verify
30+
31+
```sh
32+
skern --version
33+
```
34+
35+
If the command is not found, the install directory is not yet on your `PATH`. The installer prints PATH instructions for your shell at the end of its output — follow those, then open a new shell.
36+
37+
## Default install locations
38+
39+
| OS | Path |
40+
|-----------------|---------------------------------|
41+
| macOS / Linux | `~/.local/bin/skern` |
42+
| Windows | `%LOCALAPPDATA%\skern\bin\skern.exe` |
43+
44+
Override with the `SKERN_INSTALL_DIR` environment variable.
45+
46+
## Pin a specific version
47+
48+
```sh
49+
SKERN_VERSION=v0.2.1 curl -fsSL https://raw.githubusercontent.com/devrimcavusoglu/skern/main/scripts/install.sh | bash
50+
```
51+
52+
```powershell
53+
$env:SKERN_VERSION = 'v0.2.1'; irm https://raw.githubusercontent.com/devrimcavusoglu/skern/main/scripts/install.ps1 | iex
54+
```
55+
56+
## Build from source
57+
58+
Requires Go 1.25+:
59+
60+
```sh
61+
go install github.com/devrimcavusoglu/skern/cmd/skern@latest
62+
```
63+
64+
## Manual install
65+
66+
Download the archive for your platform from the [releases page](https://github.com/devrimcavusoglu/skern/releases/latest), extract it, and place the `skern` (or `skern.exe`) binary on your `PATH`. Archive naming:
67+
68+
- `skern_<version>_darwin_<arch>.tar.gz`
69+
- `skern_<version>_linux_<arch>.tar.gz`
70+
- `skern_<version>_windows_<arch>.zip`
71+
72+
`<arch>` is `amd64` or `arm64`. Each release also publishes `checksums.txt` with SHA-256 sums.
73+
74+
## Uninstall
75+
76+
Delete the binary at the install location shown above. The installer does not modify any other files.

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,26 @@ skern skill install code-review --platform claude-code
3838

3939
## Install
4040

41+
**macOS / Linux:**
42+
4143
```sh
4244
curl -fsSL https://raw.githubusercontent.com/devrimcavusoglu/skern/main/scripts/install.sh | bash
4345
```
4446

45-
Or with Go 1.25+:
47+
**Windows (PowerShell):**
48+
49+
```powershell
50+
irm https://raw.githubusercontent.com/devrimcavusoglu/skern/main/scripts/install.ps1 | iex
51+
```
52+
53+
**From source** (Go 1.25+):
4654

4755
```sh
4856
go install github.com/devrimcavusoglu/skern/cmd/skern@latest
4957
```
5058

59+
Full installation guide — including version pinning, custom install paths, manual install, and uninstall — is in [INSTALL.md](./INSTALL.md).
60+
5161
## Documentation
5262

5363
Full documentation is available at **[skern.dev](https://skern.dev)**:

scripts/install.ps1

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# Skern installer - Windows / PowerShell counterpart to scripts/install.sh
2+
# Usage:
3+
# irm https://raw.githubusercontent.com/devrimcavusoglu/skern/main/scripts/install.ps1 | iex
4+
#
5+
# Environment variables:
6+
# SKERN_INSTALL_DIR - override install directory (default: %LOCALAPPDATA%\skern\bin)
7+
# SKERN_VERSION - install a specific version (default: latest)
8+
9+
$ErrorActionPreference = 'Stop'
10+
11+
$Repo = 'devrimcavusoglu/skern'
12+
$Binary = 'skern'
13+
$DefaultInstallDir = Join-Path $env:LOCALAPPDATA 'skern\bin'
14+
15+
# PowerShell 5.1 default protocol may be TLS 1.0/1.1; GitHub requires 1.2+.
16+
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
17+
18+
function Write-Info($msg) {
19+
Write-Host "[skern] $msg"
20+
}
21+
22+
function Stop-WithError($msg) {
23+
Write-Host "[skern] ERROR: $msg" -ForegroundColor Red
24+
exit 1
25+
}
26+
27+
function Get-Arch {
28+
$procArch = $env:PROCESSOR_ARCHITECTURE
29+
$procArchW6432 = $env:PROCESSOR_ARCHITEW6432
30+
if ($procArch -eq 'ARM64' -or $procArchW6432 -eq 'ARM64') {
31+
return 'arm64'
32+
}
33+
if ([System.Environment]::Is64BitOperatingSystem) {
34+
return 'amd64'
35+
}
36+
Stop-WithError "Unsupported architecture: $procArch. Skern supports amd64 and arm64."
37+
}
38+
39+
function Resolve-Version {
40+
if ($env:SKERN_VERSION) {
41+
Write-Info "Using specified version: $($env:SKERN_VERSION)"
42+
return $env:SKERN_VERSION
43+
}
44+
Write-Info 'Fetching latest release...'
45+
try {
46+
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/$Repo/releases/latest" -UseBasicParsing
47+
} catch {
48+
Stop-WithError "Could not fetch latest release: $_"
49+
}
50+
if (-not $release.tag_name) {
51+
Stop-WithError "Could not determine latest version. Set SKERN_VERSION manually or use 'go install'."
52+
}
53+
Write-Info "Latest version: $($release.tag_name)"
54+
return $release.tag_name
55+
}
56+
57+
function Get-AssetWithChecksum($version, $arch, $tmpDir) {
58+
$versionNoV = $version -replace '^v',''
59+
$assetName = "skern_${versionNoV}_windows_${arch}.zip"
60+
$downloadUrl = "https://github.com/$Repo/releases/download/$version/$assetName"
61+
$checksumsUrl = "https://github.com/$Repo/releases/download/$version/checksums.txt"
62+
63+
$zipPath = Join-Path $tmpDir $assetName
64+
$checksumsPath = Join-Path $tmpDir 'checksums.txt'
65+
66+
Write-Info "Downloading $downloadUrl ..."
67+
try {
68+
Invoke-WebRequest -Uri $downloadUrl -OutFile $zipPath -UseBasicParsing
69+
} catch {
70+
Stop-WithError "Download failed: $_"
71+
}
72+
73+
try {
74+
Invoke-WebRequest -Uri $checksumsUrl -OutFile $checksumsPath -UseBasicParsing
75+
} catch {
76+
Write-Info 'Warning: checksums file not available, skipping verification.'
77+
$checksumsPath = $null
78+
}
79+
80+
if ($checksumsPath -and (Test-Path $checksumsPath)) {
81+
$expectedLine = Get-Content $checksumsPath | Where-Object { $_ -match [regex]::Escape($assetName) } | Select-Object -First 1
82+
if ($expectedLine) {
83+
$expectedSum = ($expectedLine -split '\s+')[0]
84+
$actualSum = (Get-FileHash -Path $zipPath -Algorithm SHA256).Hash.ToLower()
85+
if ($expectedSum.ToLower() -ne $actualSum) {
86+
Stop-WithError "Checksum mismatch! Expected $expectedSum, got $actualSum. Aborting."
87+
}
88+
Write-Info 'Checksum verified.'
89+
} else {
90+
Write-Info "Warning: could not find checksum for $assetName, skipping verification."
91+
}
92+
}
93+
94+
return $zipPath
95+
}
96+
97+
function Install-Binary($zipPath, $tmpDir) {
98+
$installDir = if ($env:SKERN_INSTALL_DIR) { $env:SKERN_INSTALL_DIR } else { $DefaultInstallDir }
99+
if (-not (Test-Path $installDir)) {
100+
New-Item -ItemType Directory -Path $installDir -Force | Out-Null
101+
}
102+
103+
$extractDir = Join-Path $tmpDir 'extracted'
104+
Expand-Archive -Path $zipPath -DestinationPath $extractDir -Force
105+
106+
$exeName = "$Binary.exe"
107+
$sourceExe = Get-ChildItem -Path $extractDir -Filter $exeName -Recurse | Select-Object -First 1
108+
if (-not $sourceExe) {
109+
Stop-WithError "Binary $exeName not found after extraction. Archive may be corrupt."
110+
}
111+
112+
$targetPath = Join-Path $installDir $exeName
113+
Move-Item -Path $sourceExe.FullName -Destination $targetPath -Force
114+
Write-Info "Installed $exeName to $targetPath"
115+
116+
# Check if installDir is on PATH (user or system).
117+
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
118+
$machinePath = [Environment]::GetEnvironmentVariable('Path', 'Machine')
119+
$combinedPath = "$userPath;$machinePath"
120+
$onPath = $combinedPath.Split(';') | Where-Object { $_.TrimEnd('\') -ieq $installDir.TrimEnd('\') }
121+
122+
if (-not $onPath) {
123+
Write-Info ''
124+
Write-Info "WARNING: $installDir is not on your PATH."
125+
Write-Info 'Add it persistently with:'
126+
Write-Info ''
127+
Write-Info " [Environment]::SetEnvironmentVariable('Path', `"`$env:Path;$installDir`", 'User')"
128+
Write-Info ''
129+
Write-Info 'Then open a new shell. Or, for the current shell only:'
130+
Write-Info ''
131+
Write-Info " `$env:Path += ';$installDir'"
132+
Write-Info ''
133+
}
134+
135+
return $targetPath
136+
}
137+
138+
function Main {
139+
Write-Info 'Skern installer'
140+
Write-Info ''
141+
142+
$arch = Get-Arch
143+
Write-Info "Detected platform: windows_$arch"
144+
145+
$version = Resolve-Version
146+
147+
$tmpDir = Join-Path $env:TEMP "skern-install-$([System.Guid]::NewGuid().ToString('N'))"
148+
New-Item -ItemType Directory -Path $tmpDir -Force | Out-Null
149+
150+
try {
151+
$zipPath = Get-AssetWithChecksum -version $version -arch $arch -tmpDir $tmpDir
152+
$targetPath = Install-Binary -zipPath $zipPath -tmpDir $tmpDir
153+
154+
Write-Info ''
155+
try {
156+
$output = & $targetPath version 2>$null
157+
if ($LASTEXITCODE -eq 0) {
158+
Write-Info "Success! Installed $output"
159+
} else {
160+
Write-Info 'Installation complete. You may need to open a new shell to use skern.'
161+
}
162+
} catch {
163+
Write-Info 'Installation complete. You may need to open a new shell to use skern.'
164+
}
165+
} finally {
166+
if (Test-Path $tmpDir) {
167+
Remove-Item -Path $tmpDir -Recurse -Force -ErrorAction SilentlyContinue
168+
}
169+
}
170+
}
171+
172+
Main

0 commit comments

Comments
 (0)