Skip to content

Commit b3a5c10

Browse files
atompilotclaude
andcommitted
feat: add prebuilt exe download and one-line installer for Windows
install.ps1 now auto-downloads exe from GitHub Releases before falling back to source compilation, removing the .NET 8 SDK requirement for most users. Added install-remote.ps1 for one-line install (irm | iex) and a GitHub Actions workflow that builds both Windows exe and macOS zip on tag push. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
1 parent 4d3d4b7 commit b3a5c10

4 files changed

Lines changed: 332 additions & 38 deletions

File tree

.github/workflows/release.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
build:
13+
strategy:
14+
matrix:
15+
include:
16+
- os: windows-latest
17+
build_script: windows/build.ps1
18+
artifact: windows/dist/claudecode-notification.exe
19+
- os: macos-latest
20+
build_script: macos/build.sh
21+
artifact: macos/dist/ClaudeCodeNotification.zip
22+
23+
runs-on: ${{ matrix.os }}
24+
25+
steps:
26+
- name: Checkout
27+
uses: actions/checkout@v4
28+
29+
- name: Setup .NET 8 SDK
30+
if: runner.os == 'Windows'
31+
uses: actions/setup-dotnet@v4
32+
with:
33+
dotnet-version: "8.0.x"
34+
35+
- name: Build (Windows)
36+
if: runner.os == 'Windows'
37+
shell: pwsh
38+
run: .\${{ matrix.build_script }}
39+
40+
- name: Build (macOS)
41+
if: runner.os == 'macOS'
42+
run: bash ${{ matrix.build_script }}
43+
44+
- name: Upload to GitHub Release
45+
uses: softprops/action-gh-release@v2
46+
with:
47+
files: ${{ matrix.artifact }}

README.md

Lines changed: 73 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -139,36 +139,56 @@ To also remove the notification permission: **System Settings → Notifications
139139

140140
> **Requirements:** Windows 10 version 1809 (build 17763) or later, PowerShell 5.1+, Node.js (included with Claude Code)
141141
142-
### Step 1: Clone the repository
142+
### Option A: One-Line Install
143143

144144
```powershell
145-
git clone https://github.com/splazapp/claude-code-notification.git
146-
cd claude-code-notification\windows
145+
irm https://raw.githubusercontent.com/splazapp/claude-code-notification/main/windows/install-remote.ps1 | iex
147146
```
148147

149-
### Step 2: Install (build from source)
148+
No need to clone the repository. Downloads the latest release and configures everything automatically.
149+
150+
<details>
151+
<summary>Review the script before running</summary>
150152

151153
```powershell
154+
irm https://raw.githubusercontent.com/splazapp/claude-code-notification/main/windows/install-remote.ps1 | more
155+
# Then run it if you're satisfied:
156+
irm https://raw.githubusercontent.com/splazapp/claude-code-notification/main/windows/install-remote.ps1 | iex
157+
```
158+
</details>
159+
160+
To install a specific version:
161+
162+
```powershell
163+
$env:VERSION="v2.3.0"; irm https://raw.githubusercontent.com/splazapp/claude-code-notification/main/windows/install-remote.ps1 | iex
164+
```
165+
166+
### Option B: Clone + Install
167+
168+
```powershell
169+
git clone https://github.com/splazapp/claude-code-notification.git
170+
cd claude-code-notification\windows
152171
.\install.ps1
153172
```
154173

155-
The installer will:
156-
- Build `claudecode-notification.exe` from C# source (requires [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0))
157-
- Copy files to `%APPDATA%\claudecode-notification\`
158-
- Register the Toast AUMID in the registry
159-
- Configure hooks in `%USERPROFILE%\.claude\settings.json`
174+
The installer will automatically download the prebuilt exe from GitHub Releases. If the download fails, it falls back to building from source (requires [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0)).
160175

161-
### Step 2 (alternative): Build separately, then install
176+
To install a specific version:
162177

163178
```powershell
164-
# Build first (requires .NET 8 SDK)
165-
.\build.ps1
179+
$env:VERSION="v2.3.0"; .\install.ps1
180+
```
181+
182+
### Option C: Build from Source
166183

167-
# Then install (no SDK required at install time)
184+
```powershell
185+
git clone https://github.com/splazapp/claude-code-notification.git
186+
cd claude-code-notification\windows
187+
.\build.ps1 # requires .NET 8 SDK
168188
.\install.ps1
169189
```
170190

171-
### Step 3: Enable notifications
191+
### Enable notifications
172192

173193
On first notification, Windows may prompt to allow notifications. If none appear:
174194

@@ -228,6 +248,8 @@ Other apps are supported if they set the `__CFBundleIdentifier` environment vari
228248

229249
```
230250
claude-code-notification/
251+
├── .github/workflows/
252+
│ └── release.yml # CI: build + upload exe/zip on tag push
231253
├── macos/
232254
│ ├── claudecode-notification.sh # Bash hook handler — routes events, tracks state
233255
│ ├── notifier.swift # Swift notification sender with click callback
@@ -244,7 +266,8 @@ claude-code-notification/
244266
├── Notifier.cs # C# Toast notification sender with HWND focus
245267
├── Notifier.csproj # .NET 8 project file
246268
├── build.ps1 # Build script (dotnet publish → single exe)
247-
├── install.ps1 # Install script
269+
├── install.ps1 # Install script (auto-downloads exe from Releases)
270+
├── install-remote.ps1 # Remote one-line installer — irm | iex
248271
├── uninstall.ps1 # Uninstall script
249272
└── dist/ # Build output (gitignored)
250273
└── claudecode-notification.exe
@@ -261,7 +284,7 @@ claude-code-notification/
261284
- Windows 10 version 1809 (build 17763) or later
262285
- PowerShell 5.1+ (pre-installed on Windows 10)
263286
- Node.js (included with Claude Code)
264-
- [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0) (only needed to build from source)
287+
- [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0) (only needed to build from source; prebuilt exe is downloaded automatically)
265288

266289
## License
267290

@@ -383,36 +406,56 @@ bash uninstall.sh
383406

384407
> **系统要求:** Windows 10 1809(build 17763)及以上,PowerShell 5.1+,Node.js(Claude Code 已包含)
385408
386-
### 第一步:Clone 仓库
409+
### 方式 A:一键安装
387410

388411
```powershell
389-
git clone https://github.com/splazapp/claude-code-notification.git
390-
cd claude-code-notification\windows
412+
irm https://raw.githubusercontent.com/splazapp/claude-code-notification/main/windows/install-remote.ps1 | iex
391413
```
392414

393-
### 第二步:安装
415+
无需 clone 仓库。自动下载最新版本并完成全部配置。
416+
417+
<details>
418+
<summary>运行前先审查脚本</summary>
394419

395420
```powershell
421+
irm https://raw.githubusercontent.com/splazapp/claude-code-notification/main/windows/install-remote.ps1 | more
422+
# 确认没问题后再执行:
423+
irm https://raw.githubusercontent.com/splazapp/claude-code-notification/main/windows/install-remote.ps1 | iex
424+
```
425+
</details>
426+
427+
指定版本安装:
428+
429+
```powershell
430+
$env:VERSION="v2.3.0"; irm https://raw.githubusercontent.com/splazapp/claude-code-notification/main/windows/install-remote.ps1 | iex
431+
```
432+
433+
### 方式 B:Clone + 安装
434+
435+
```powershell
436+
git clone https://github.com/splazapp/claude-code-notification.git
437+
cd claude-code-notification\windows
396438
.\install.ps1
397439
```
398440

399-
安装脚本会自动:
400-
- 从 C# 源码编译 `claudecode-notification.exe`(需要 [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0)
401-
- 复制文件到 `%APPDATA%\claudecode-notification\`
402-
- 注册 Toast AUMID 到注册表
403-
- 配置 `%USERPROFILE%\.claude\settings.json` 中的 hooks
441+
安装脚本会自动从 GitHub Releases 下载预编译 exe。下载失败时回退到源码编译(需要 [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0))。
404442

405-
### 第二步(进阶):先构建再安装
443+
指定版本安装:
406444

407445
```powershell
408-
# 先构建(需要 .NET 8 SDK)
409-
.\build.ps1
446+
$env:VERSION="v2.3.0"; .\install.ps1
447+
```
448+
449+
### 方式 C:从源码编译
410450

411-
# 再安装(安装时不需要 SDK)
451+
```powershell
452+
git clone https://github.com/splazapp/claude-code-notification.git
453+
cd claude-code-notification\windows
454+
.\build.ps1 # 需要 .NET 8 SDK
412455
.\install.ps1
413456
```
414457

415-
### 第三步:允许通知
458+
### 允许通知
416459

417460
首次收到通知时 Windows 可能弹出权限请求。若通知未出现:
418461

windows/install-remote.ps1

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# ClaudeCodeNotification — Windows Remote Installer
2+
# One-line install: irm https://raw.githubusercontent.com/splazapp/claude-code-notification/main/windows/install-remote.ps1 | iex
3+
#
4+
# Environment variables:
5+
# $env:VERSION = "v2.3.0" — pin to a specific release (default: latest)
6+
7+
Set-StrictMode -Version Latest
8+
$ErrorActionPreference = "Stop"
9+
10+
$Repo = "splazapp/claude-code-notification"
11+
$ExeName = "claudecode-notification.exe"
12+
$ScriptName = "claudecode-notification.ps1"
13+
$InstallDir = "$env:APPDATA\claudecode-notification"
14+
$SettingsFile = "$HOME\.claude\settings.json"
15+
$AppId = "ClaudeCodeNotification"
16+
17+
Write-Host ""
18+
Write-Host "=== ClaudeCodeNotification Windows Remote Installer ===" -ForegroundColor Cyan
19+
Write-Host ""
20+
21+
# ─── Pre-flight checks ───
22+
23+
# Windows 10 1809+ (build 17763)
24+
$build = [System.Environment]::OSVersion.Version.Build
25+
if ($build -lt 17763) {
26+
Write-Host "Error: Windows 10 1809 (build 17763) or later required. Your build: $build" -ForegroundColor Red
27+
exit 1
28+
}
29+
30+
# PowerShell 5.1+
31+
if ($PSVersionTable.PSVersion.Major -lt 5 -or
32+
($PSVersionTable.PSVersion.Major -eq 5 -and $PSVersionTable.PSVersion.Minor -lt 1)) {
33+
Write-Host "Error: PowerShell 5.1+ required." -ForegroundColor Red
34+
exit 1
35+
}
36+
37+
# Claude Code installed
38+
if (-not (Test-Path "$HOME\.claude")) {
39+
Write-Host "Error: ~/.claude/ not found. Please install Claude Code first." -ForegroundColor Red
40+
exit 1
41+
}
42+
43+
# Node.js (needed for hooks setup)
44+
if (-not (Get-Command node -ErrorAction SilentlyContinue)) {
45+
Write-Host "Error: Node.js is required (included with Claude Code)." -ForegroundColor Red
46+
exit 1
47+
}
48+
49+
# ─── Determine version ───
50+
51+
$ReleaseTag = if ($env:VERSION) { $env:VERSION } else { "latest" }
52+
53+
if ($ReleaseTag -ne "latest") {
54+
Write-Host "==> Using specified version: $ReleaseTag"
55+
} else {
56+
Write-Host "==> Downloading latest release ..."
57+
}
58+
59+
# ─── Temporary directory with cleanup ───
60+
61+
$TmpDir = Join-Path $env:TEMP "claudecode-notification-install-$(Get-Random)"
62+
New-Item -ItemType Directory -Force -Path $TmpDir | Out-Null
63+
64+
try {
65+
# ─── Download exe from GitHub Releases ───
66+
67+
if ($ReleaseTag -eq "latest") {
68+
$ExeUrl = "https://github.com/$Repo/releases/latest/download/$ExeName"
69+
} else {
70+
$ExeUrl = "https://github.com/$Repo/releases/download/$ReleaseTag/$ExeName"
71+
}
72+
73+
Write-Host " Fetching $ExeName ..."
74+
try {
75+
Invoke-WebRequest -Uri $ExeUrl -OutFile (Join-Path $TmpDir $ExeName) -UseBasicParsing
76+
} catch {
77+
Write-Host "Error: Failed to download $ExeName from $ExeUrl" -ForegroundColor Red
78+
Write-Host " $_" -ForegroundColor Red
79+
exit 1
80+
}
81+
82+
# ─── Download hook script from raw.githubusercontent.com ───
83+
84+
if ($ReleaseTag -eq "latest") {
85+
$ScriptUrl = "https://raw.githubusercontent.com/$Repo/main/windows/$ScriptName"
86+
} else {
87+
$ScriptUrl = "https://raw.githubusercontent.com/$Repo/$ReleaseTag/windows/$ScriptName"
88+
}
89+
90+
Write-Host " Fetching $ScriptName ..."
91+
try {
92+
Invoke-WebRequest -Uri $ScriptUrl -OutFile (Join-Path $TmpDir $ScriptName) -UseBasicParsing
93+
} catch {
94+
Write-Host "Error: Failed to download $ScriptName from $ScriptUrl" -ForegroundColor Red
95+
Write-Host " $_" -ForegroundColor Red
96+
exit 1
97+
}
98+
99+
# ─── Install files ───
100+
101+
Write-Host "==> Installing to $InstallDir ..."
102+
if (Test-Path $InstallDir) { Remove-Item $InstallDir -Recurse -Force }
103+
New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
104+
105+
Copy-Item (Join-Path $TmpDir $ScriptName) (Join-Path $InstallDir $ScriptName)
106+
Copy-Item (Join-Path $TmpDir $ExeName) (Join-Path $InstallDir $ExeName)
107+
108+
Write-Host " Copied $ScriptName"
109+
Write-Host " Copied $ExeName"
110+
111+
# ─── Register Toast AUMID ───
112+
113+
Write-Host "==> Registering Toast AppUserModelId ..."
114+
$RegPath = "HKCU:\SOFTWARE\Classes\AppUserModelId\$AppId"
115+
if (-not (Test-Path $RegPath)) { New-Item -Path $RegPath -Force | Out-Null }
116+
Set-ItemProperty -Path $RegPath -Name "DisplayName" -Value $AppId
117+
Write-Host " Registered: $AppId"
118+
119+
# ─── Configure Claude Code hooks ───
120+
121+
Write-Host "==> Configuring Claude Code hooks ..."
122+
123+
$SettingsDir = Split-Path $SettingsFile
124+
if (-not (Test-Path $SettingsDir)) { New-Item -ItemType Directory -Force -Path $SettingsDir | Out-Null }
125+
if (-not (Test-Path $SettingsFile)) { '{}' | Set-Content $SettingsFile -Encoding UTF8 }
126+
127+
$HookScript = Join-Path $InstallDir $ScriptName
128+
129+
$TmpJs = Join-Path $env:TEMP "claudecode-notification-setup.js"
130+
@'
131+
const fs = require('fs');
132+
const settingsPath = process.argv[2];
133+
const hookScript = process.argv[3];
134+
const psPrefix = 'powershell.exe -ExecutionPolicy Bypass -NonInteractive -File';
135+
136+
let settings = {};
137+
try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch {}
138+
settings.hooks = settings.hooks || {};
139+
140+
for (const event of ['UserPromptSubmit', 'Stop', 'Notification']) {
141+
const fullCmd = psPrefix + ' "' + hookScript + '" ' + event;
142+
const hookEntry = { hooks: [{ type: 'command', command: fullCmd }] };
143+
const existing = settings.hooks[event] || [];
144+
const already = existing.some(e =>
145+
e.hooks && e.hooks.some(h => h.command && h.command.includes('claudecode-notification.ps1'))
146+
);
147+
if (!already) existing.push(hookEntry);
148+
settings.hooks[event] = existing;
149+
}
150+
151+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
152+
console.log(' settings.json updated.');
153+
'@ | Set-Content $TmpJs -Encoding UTF8
154+
155+
node $TmpJs $SettingsFile $HookScript
156+
Remove-Item $TmpJs -Force -ErrorAction SilentlyContinue
157+
158+
# ─── Done ───
159+
160+
Write-Host ""
161+
Write-Host "==> Installation complete!" -ForegroundColor Green
162+
Write-Host ""
163+
Write-Host "Hooks registered for: UserPromptSubmit, Stop, Notification"
164+
Write-Host "Install dir: $InstallDir"
165+
Write-Host ""
166+
Write-Host "On first notification, Windows may ask for notification permission." -ForegroundColor Yellow
167+
Write-Host "If notifications don't appear: Settings -> System -> Notifications -> ClaudeCodeNotification -> On"
168+
169+
} finally {
170+
# ─── Cleanup temp directory ───
171+
Remove-Item $TmpDir -Recurse -Force -ErrorAction SilentlyContinue
172+
}

0 commit comments

Comments
 (0)