Skip to content

Commit 1f2640d

Browse files
committed
feat: add windows install support
1 parent 0165f3a commit 1f2640d

9 files changed

Lines changed: 660 additions & 136 deletions

File tree

.github/workflows/release.yml

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ jobs:
4242
runner: macos-15
4343
target: aarch64-apple-darwin
4444
experimental: false
45+
- label: windows-x86_64
46+
runner: windows-latest
47+
target: x86_64-pc-windows-msvc
48+
experimental: false
49+
- label: windows-aarch64
50+
runner: windows-latest
51+
target: aarch64-pc-windows-msvc
52+
experimental: true
4553

4654
steps:
4755
- name: Checkout repository
@@ -95,7 +103,8 @@ jobs:
95103
if: startsWith(matrix.runner, 'macos')
96104
run: brew install librsvg
97105

98-
- name: Package release artifacts
106+
- name: Package release artifacts (Unix)
107+
if: ${{ !startsWith(matrix.runner, 'windows') }}
99108
shell: bash
100109
env:
101110
TAG: ${{ github.ref_name }}
@@ -143,12 +152,43 @@ jobs:
143152
fi
144153
)
145154
155+
- name: Package release artifacts (Windows)
156+
if: startsWith(matrix.runner, 'windows')
157+
shell: pwsh
158+
env:
159+
TAG: ${{ github.ref_name }}
160+
TARGET_TRIPLE: ${{ matrix.target }}
161+
run: |
162+
$ErrorActionPreference = 'Stop'
163+
$assetDir = "aura-$env:TAG-$env:TARGET_TRIPLE"
164+
$stageRoot = "dist/$assetDir"
165+
New-Item -ItemType Directory -Force -Path $stageRoot | Out-Null
166+
167+
Copy-Item "target/$env:TARGET_TRIPLE/release/aura.exe" "$stageRoot/aura.exe"
168+
Copy-Item "target/$env:TARGET_TRIPLE/release/aura-plugin-rtk.exe" "$stageRoot/aura-plugin-rtk.exe"
169+
170+
if (Test-Path "scripts/install.ps1") {
171+
Copy-Item "scripts/install.ps1" "$stageRoot/install.ps1"
172+
}
173+
174+
foreach ($f in @('README.md', 'LICENSE')) {
175+
if (Test-Path $f) { Copy-Item $f "$stageRoot/$f" }
176+
}
177+
178+
$zip = "dist/$assetDir.zip"
179+
if (Test-Path $zip) { Remove-Item $zip }
180+
Compress-Archive -Path "$stageRoot/*" -DestinationPath $zip
181+
182+
$hash = (Get-FileHash -Algorithm SHA256 $zip).Hash.ToLower()
183+
"$hash $assetDir.zip" | Out-File -Encoding ascii "dist/$assetDir.sha256"
184+
146185
- name: Upload packaged artifacts
147186
uses: actions/upload-artifact@v7
148187
with:
149188
name: release-${{ matrix.target }}
150189
path: |
151190
dist/*.tar.gz
191+
dist/*.zip
152192
dist/*.sha256
153193
if-no-files-found: error
154194

@@ -170,4 +210,5 @@ jobs:
170210
generate_release_notes: true
171211
files: |
172212
dist/*.tar.gz
213+
dist/*.zip
173214
dist/*.sha256

PLAN.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,19 @@
153153

154154
---
155155

156+
## Phase 11 — Windows support ✓
157+
158+
- [x] Cargo gating: `tray-icon` falls through to its Win32 backend on Windows (no `gtk` feature needed); the existing "not Linux/BSD" target table covers this
159+
- [x] Windows Credential Manager read/write for Claude Code OAuth (`Claude Code-credentials`, user = `%USERNAME%`) via `keyring` crate (`windows-native` backend); falls back to `.credentials.json` for legacy installs
160+
- [x] `scripts/install.ps1` — copies binaries to `%LOCALAPPDATA%\Programs\Aura` and drops a Startup-folder `Aura.lnk` for autostart
161+
- [x] `install.sh` detects MSYS/MinGW/Cygwin and points users at `install.ps1`
162+
- [x] `justfile` adds `install-windows`, `uninstall-windows`, `start-windows`, `stop-windows`, `status-windows`
163+
- [x] Release CI matrix builds `x86_64-pc-windows-msvc` (stable) and `aarch64-pc-windows-msvc` (experimental); Windows artifacts are zipped (not tarballed)
164+
- [x] README documents Windows config path (`%APPDATA%\aura\config.toml`), install flow, and Credential Manager caveat
165+
- [ ] **Manual test required** — first-launch verification on x86_64 + aarch64 Windows hosts; code-signing setup once a Windows Authenticode cert is available
166+
167+
---
168+
156169
## Phase 10 — macOS support ✓
157170

158171
- [x] Cross-platform Cargo gating for `tray-icon` (`gtk` feature only on Linux/BSD)

README.md

Lines changed: 77 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ Aura is configured via a single TOML file at the OS-standard config location:
6262
|---|---|
6363
| Linux | `~/.config/aura/config.toml` |
6464
| macOS | `~/Library/Application Support/aura/config.toml` |
65+
| Windows | `%APPDATA%\aura\config.toml` |
6566

6667
Define as many profiles as you need:
6768

@@ -89,13 +90,15 @@ kind = "codex"
8990
- [ ] Custom command agents (BYOA — Bring Your Own Agent)
9091
- [ ] Plugin authoring guide + example plugin
9192
- [x] macOS support (Apple Silicon + Intel; menu-bar app + launchd autostart)
93+
- [x] Windows support (x86_64 + aarch64; tray app + Startup-folder autostart)
9294
- [ ] Plugin registry
9395

9496
## Installation
9597

96-
Aura runs as a systemd user service on Linux and as a menu-bar app (launchd
97-
LaunchAgent + `Aura.app`) on macOS. You can either grab a prebuilt release
98-
archive or build from source with Cargo (Rust 1.80+).
98+
Aura runs as a systemd user service on Linux, as a menu-bar app (launchd
99+
LaunchAgent + `Aura.app`) on macOS, and as a tray app with a Startup-folder
100+
shortcut on Windows. You can either grab a prebuilt release archive or build
101+
from source with Cargo (Rust 1.80+).
99102

100103
### System dependencies (Linux)
101104

@@ -129,84 +132,57 @@ Claude Code OAuth tokens are stored in the macOS Keychain on Darwin (service
129132
get a "Keychain read failed" warning, run Claude Code at least once to
130133
populate the entry, then restart Aura.
131134

135+
### System dependencies (Windows)
136+
137+
No system packages required — the MSVC C runtime ships with Windows. To
138+
build from source you'll need:
139+
140+
```powershell
141+
# Install Rust (https://rustup.rs) and the MSVC build tools
142+
# (Visual Studio "Desktop development with C++" workload or VS Build Tools).
143+
rustup target add x86_64-pc-windows-msvc # default on Windows hosts
144+
```
145+
146+
On Windows Claude Code stores OAuth tokens in **Credential Manager** (target
147+
`Claude Code-credentials`); Aura reads them from there automatically, falling
148+
back to `%USERPROFILE%\.claude\.credentials.json` for legacy installs. If you
149+
get a "Credential Manager read failed" warning, run Claude Code at least once
150+
to populate the entry, then restart Aura.
151+
132152
### Install from GitHub Releases
133153

134-
Published releases include tarballs containing the `aura` and `aura-plugin-rtk`
135-
binaries plus the systemd unit (Linux archives only):
154+
Published releases include tarballs (Linux/macOS) and a zip (Windows)
155+
containing the `aura` and `aura-plugin-rtk` binaries plus the platform
156+
autostart artifact:
136157

137158
- Linux x86_64 (gnu) — `x86_64-unknown-linux-gnu`
138159
- Linux x86_64 (musl) — `x86_64-unknown-linux-musl`
139160
- Linux aarch64 (gnu) — `aarch64-unknown-linux-gnu`
140161
- macOS Intel — `x86_64-apple-darwin` (ships `Aura.app` + `com.aura.agent-usage.plist`)
141162
- macOS Apple Silicon — `aarch64-apple-darwin`
163+
- Windows x86_64 — `x86_64-pc-windows-msvc` (ships `aura.exe` + `install.ps1`)
164+
- Windows aarch64 — `aarch64-pc-windows-msvc` (experimental)
142165

143-
> Note: the musl Linux artifact is still experimental. macOS archives are
144-
> built and signed best-effort — unsigned bundles will be quarantined by
145-
> Gatekeeper; see the macOS deps section above.
166+
> Note: the musl Linux artifact and the aarch64 Windows artifact are still
167+
> experimental. macOS archives are built and signed best-effort — unsigned
168+
> bundles will be quarantined by Gatekeeper; see the macOS deps section above.
169+
> Windows binaries are unsigned: SmartScreen may prompt on first run.
146170
147-
Pick the archive that matches your host:
171+
Run the installer — it auto-detects your host, downloads the matching archive,
172+
verifies its checksum, and wires up autostart:
148173

149174
```bash
150-
VERSION="$(curl -fsSLI -o /dev/null -w '%{url_effective}' \
151-
https://github.com/Rfluid/aura/releases/latest \
152-
| sed 's:.*/::')"
153-
154-
if [ -z "${VERSION}" ]; then
155-
echo "Failed to determine the latest GitHub release version" >&2
156-
exit 1
157-
fi
158-
159-
case "$(uname -s)-$(uname -m)" in
160-
Linux-x86_64) ASSET="aura-${VERSION}-x86_64-unknown-linux-gnu" ;;
161-
Linux-aarch64) ASSET="aura-${VERSION}-aarch64-unknown-linux-gnu" ;;
162-
Darwin-x86_64) ASSET="aura-${VERSION}-x86_64-apple-darwin" ;;
163-
Darwin-arm64) ASSET="aura-${VERSION}-aarch64-apple-darwin" ;;
164-
*)
165-
echo "No published release artifact for $(uname -s)-$(uname -m)" >&2
166-
exit 1
167-
;;
168-
esac
169-
170-
curl -LO "https://github.com/Rfluid/aura/releases/download/${VERSION}/${ASSET}.tar.gz"
171-
curl -LO "https://github.com/Rfluid/aura/releases/download/${VERSION}/${ASSET}.sha256"
172-
173-
if command -v sha256sum >/dev/null 2>&1; then
174-
sha256sum -c "${ASSET}.sha256"
175-
else
176-
shasum -a 256 -c "${ASSET}.sha256"
177-
fi
178-
179-
tar -xzf "${ASSET}.tar.gz"
180-
181-
install -Dm755 "${ASSET}/aura" "${HOME}/.local/bin/aura"
182-
install -Dm755 "${ASSET}/aura-plugin-rtk" "${HOME}/.local/bin/aura-plugin-rtk"
183-
184-
case "$(uname -s)" in
185-
Linux)
186-
if [ -f "${ASSET}/aura.service" ]; then
187-
install -Dm644 "${ASSET}/aura.service" "${HOME}/.config/systemd/user/aura.service"
188-
systemctl --user daemon-reload
189-
systemctl --user enable --now aura
190-
fi
191-
;;
192-
Darwin)
193-
if [ -d "${ASSET}/Aura.app" ]; then
194-
rm -rf "/Applications/Aura.app"
195-
cp -R "${ASSET}/Aura.app" "/Applications/Aura.app"
196-
xattr -dr com.apple.quarantine "/Applications/Aura.app" 2>/dev/null || true
197-
fi
198-
if [ -f "${ASSET}/com.aura.agent-usage.plist" ]; then
199-
install -m 644 "${ASSET}/com.aura.agent-usage.plist" \
200-
"${HOME}/Library/LaunchAgents/com.aura.agent-usage.plist"
201-
launchctl bootout "gui/$(id -u)/com.aura.agent-usage" 2>/dev/null || true
202-
launchctl bootstrap "gui/$(id -u)" \
203-
"${HOME}/Library/LaunchAgents/com.aura.agent-usage.plist"
204-
fi
205-
;;
206-
esac
175+
# Linux / macOS
176+
curl -fsSL https://raw.githubusercontent.com/Rfluid/aura/main/install.sh | bash
177+
```
178+
179+
```powershell
180+
# Windows (PowerShell)
181+
iex (irm https://raw.githubusercontent.com/Rfluid/aura/main/scripts/install.ps1)
207182
```
208183

209-
Make sure `~/.local/bin` is on `PATH`.
184+
Make sure `~/.local/bin` (Linux/macOS) or `%LOCALAPPDATA%\Programs\Aura`
185+
(Windows) is on `PATH`.
210186

211187
### Build from source
212188

@@ -216,6 +192,11 @@ Make sure `~/.local/bin` is on `PATH`.
216192
./install.sh # auto-detects Linux/macOS and wires up autostart
217193
```
218194

195+
```powershell
196+
# Windows
197+
powershell -ExecutionPolicy Bypass -File .\scripts\install.ps1
198+
```
199+
219200
Or, with [`just`](https://github.com/casey/just):
220201

221202
```bash
@@ -224,6 +205,10 @@ just install # build + install (Linux: systemd, macOS: launchd +
224205
systemctl --user enable --now aura
225206
```
226207

208+
```powershell
209+
just install-windows # build + install + Startup-folder shortcut
210+
```
211+
227212
#### Manual (Linux)
228213

229214
```bash
@@ -251,13 +236,33 @@ launchctl bootstrap "gui/$(id -u)" \
251236
~/Library/LaunchAgents/com.aura.agent-usage.plist
252237
```
253238

239+
#### Manual (Windows)
240+
241+
```powershell
242+
cargo build --release --workspace
243+
244+
$dst = Join-Path $env:LOCALAPPDATA 'Programs\Aura'
245+
New-Item -ItemType Directory -Force -Path $dst | Out-Null
246+
Copy-Item -Force target\release\aura.exe "$dst\aura.exe"
247+
Copy-Item -Force target\release\aura-plugin-rtk.exe "$dst\aura-plugin-rtk.exe"
248+
249+
# Autostart at sign-in via Startup-folder shortcut.
250+
$wsh = New-Object -ComObject WScript.Shell
251+
$lnk = $wsh.CreateShortcut((Join-Path ([Environment]::GetFolderPath('Startup')) 'Aura.lnk'))
252+
$lnk.TargetPath = "$dst\aura.exe"
253+
$lnk.WorkingDirectory = $dst
254+
$lnk.WindowStyle = 7
255+
$lnk.Save()
256+
```
257+
254258
### Common commands
255259

256-
| Command | What it does |
257-
| --------------------------- | ----------------------------------------------------------------- |
258-
| `just run` | Launch Aura (debug build) without installing |
259-
| `just status` / `just logs` | Service status / tail logs (systemd on Linux, launchd on macOS) |
260-
| `just uninstall` | Remove binaries + unit / LaunchAgent (keeps config & state) |
260+
| Command | What it does |
261+
| ------------------------------------------------- | ---------------------------------------------------------------------------------- |
262+
| `just run` | Launch Aura (debug build) without installing |
263+
| `just status` / `just logs` | Service status / tail logs (systemd on Linux, launchd on macOS) |
264+
| `just status-windows` / `just stop-windows` | Show / stop the running `aura.exe` on Windows |
265+
| `just uninstall` / `just uninstall-windows` | Remove binaries + unit / LaunchAgent / Startup shortcut (keeps config & state) |
261266

262267
## Sponsor
263268

crates/aura-core/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,12 @@ ureq.workspace = true
2020
[target.'cfg(target_os = "macos")'.dependencies]
2121
security-framework = "2"
2222

23+
# On Windows Claude Code stores the same credential blob in the Windows
24+
# Credential Manager (service `Claude Code-credentials`) and likewise
25+
# removes the on-disk file. Use the `windows-native` keyring backend so
26+
# we don't pull dbus/secret-service deps on other platforms.
27+
[target.'cfg(target_os = "windows")'.dependencies]
28+
keyring = { version = "3", default-features = false, features = ["windows-native"] }
29+
2330
[dev-dependencies]
2431
tempfile = "3"

0 commit comments

Comments
 (0)