Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,6 @@ jobs:
name: windows-${{ matrix.arch }}-msi
path: |
build/out/*.msi
build/out/Install-Prempti.ps1
build/out/Uninstall-Prempti.ps1
if-no-files-found: error

build-test-macos:
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,6 @@ jobs:
name: windows-${{ matrix.arch }}
path: |
build/out/*.msi
build/out/Install-Prempti.ps1
build/out/Uninstall-Prempti.ps1
if-no-files-found: error

publish:
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ Windows has no user-level systemd or launchd equivalent, so Prempti uses a **Pow
- **Path separators**: all runtime paths (broker socket, library_path, rules_files, http_output URL) are normalized to forward slashes at config-generation time. The plugin also canonicalizes paths to forward slashes for rule matching (stripping the Windows `\\?\` long-path prefix that `std::fs::canonicalize` sometimes adds).
- **AF_UNIX**: both `broker.sock` and `supervisor.sock` are real Unix domain sockets (Windows 10+ has kernel `AF_UNIX` support). The `uds_windows` crate provides Rust bindings.
- **Plugin library**: `coding_agent.dll` on Windows (vs `.so` on Linux and `.dylib` on macOS). The Windows packager copies the DLL into `%LOCALAPPDATA%\prempti\share\` and the post-install script renders a `library_path` in `falco.coding_agents_plugin.yaml` that points at the absolute path with forward slashes.
- **Fail-safety on MSI uninstall**: the MSI declares a deferred `REMOVE=ALL` custom action (`installers/windows/Package.wxs`) that runs `uninstall.ps1` before `RemoveFiles`, so Apps & Features, `msiexec /x` and the bundled helper all stop the service, remove the hook, drop the Run-key entry and clean `bin\` from the user `PATH`. `Return="ignore"` on the CA keeps a user-edited `settings.json` from blocking the uninstall.
- **Fail-safety on MSI uninstall**: the MSI declares a deferred `REMOVE=ALL` custom action (`installers/windows/Package.wxs`) that runs `uninstall.ps1` before `RemoveFiles`, so Apps & Features and `msiexec /x` both stop the service, remove the hook, drop the Run-key entry and clean `bin\` from the user `PATH`. `Return="ignore"` on the CA keeps a user-edited `settings.json` from blocking the uninstall.
- **`ctl start` detachment**: the launcher is a long-lived descendant (it waits on the supervisor, which waits on Falco), so a direct `CreateProcess` of the launcher is tracked by the caller's PowerShell job object and keeps a captured pipeline (`& ctl start 2>&1`) open until everything exits. To break that chain, `service_start` invokes PowerShell's `Start-Process` (ShellExecute), producing a grandchild that's fully independent of the caller. Caveat: `Start-Process -Wait ctl start` from a script still hangs because `-Wait` follows the whole process tree — the captured form `& ctl start 2>&1` is the one to use.
- **Post-install auto-start fail-safety**: `postinstall.ps1` starts the service via `Start-Process` after registering the hook, polls up to 5s for Falco, and falls through to a `Write-Warning` if it doesn't see Falco in time. Install still completes; the user recovers with `premptictl start` manually. If Falco fails to start at all (port conflict, missing DLL, etc.) the user is not silently left with a registered hook and a dead broker.

Expand Down
19 changes: 6 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,9 @@ The installer copies all components to `~/.prempti/`, starts a systemd user serv

### Windows

From the [latest release](https://github.com/falcosecurity/prempti/releases/latest), download **both** the `.msi` for your CPU architecture and the `Install-Prempti.ps1` helper, then run:
From the [latest release](https://github.com/falcosecurity/prempti/releases/latest), download the `.msi` for your CPU architecture and double-click it (or run `msiexec /i prempti-<version>-windows-<arch>.msi`).

```powershell
powershell -ExecutionPolicy Bypass -File Install-Prempti.ps1
```

The helper runs the MSI, deploys all components to `%LOCALAPPDATA%\prempti\`, adds `bin\` to your user `PATH`, registers the Claude Code hook, registers an auto-start entry for subsequent logins, and starts the service immediately so Claude Code is protected without any extra step.
The MSI deploys all components to `%LOCALAPPDATA%\prempti\`, adds `bin\` to your user `PATH`, registers the Claude Code hook, registers an auto-start entry for subsequent logins, and starts the service immediately so Claude Code is protected without any extra step.

> [!NOTE]
> Pick the MSI that matches your CPU: `prempti-<version>-windows-x64.msi` on Intel/AMD64, `prempti-<version>-windows-arm64.msi` on Windows ARM64. The x64 MSI can install under emulation on ARM64 hosts but prefer the native ARM64 MSI for best performance. See [`installers/windows/`](installers/windows/) for build prerequisites and details.
Expand Down Expand Up @@ -190,12 +186,9 @@ premptictl start

Any of these paths works — they all run the same cleanup custom action:

- ```powershell
powershell -ExecutionPolicy Bypass -File Uninstall-Prempti.ps1
```
(bundled with the release),
- Apps & Features,
- `msiexec /x <product-code>`.
- Apps & Features (recommended),
- `msiexec /x prempti-<version>-windows-<arch>.msi` (if you still have the MSI file),
- `msiexec /x <product-code>` (the GUID is in `HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\` under the Prempti entry).

The MSI removes the Claude Code hook, the auto-start entry, and the `bin\` `PATH` entry before removing files, so Claude Code is not left in a fail-closed state.

Expand Down Expand Up @@ -353,7 +346,7 @@ Requires: Rust (latest stable), Visual Studio 2022+ with C++ workload, CMake 3.2
powershell -ExecutionPolicy Bypass -File installers\windows\package.ps1
```

Output: `build/out/prempti-<version>-windows-<arch>.msi` (plus `Install-Prempti.ps1` and `Uninstall-Prempti.ps1` helpers).
Output: `build/out/prempti-<version>-windows-<arch>.msi`.

> Falco is built from source on the first run (~10 min). Subsequent builds use the cached binary.

Expand Down
28 changes: 12 additions & 16 deletions installers/windows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,18 +168,10 @@ powershell -ExecutionPolicy Bypass -File installers\windows\package.ps1 -SkipRus

> **Migrating from `coding-agents-kit`?** Prempti does not migrate or remove existing `coding-agents-kit` installations. Uninstall `coding-agents-kit` first to avoid duplicate services or stale Claude Code hooks.

### Recommended: `Install-Prempti.ps1`

The `Install-Prempti.ps1` helper (emitted next to the MSI in `build\out\`) is the recommended path. It runs the MSI silently and, if the product is already installed, opens the MSI maintenance UI instead of forcing a silent reinstall:
Double-click the MSI, or run from PowerShell:

```powershell
powershell -ExecutionPolicy Bypass -File build\out\Install-Prempti.ps1
```

### Manual `msiexec`

```powershell
msiexec /i build\out\prempti-<version>-windows-arm64.msi
msiexec /i build\out\prempti-<version>-windows-<arch>.msi
```

The MSI runs `postinstall.ps1` automatically via a deferred custom action. No manual follow-up script is required. The post-install step:
Expand Down Expand Up @@ -217,15 +209,19 @@ premptictl start

### Uninstalling

Any of the three paths works — the MSI runs `uninstall.ps1` as a deferred custom action whenever `REMOVE=ALL`, so Apps & Features, `msiexec /x`, and the bundled helper all stop the service, remove the Claude Code hook, remove the auto-start Run-key entry, and clean `bin\` from the user `PATH` before removing files.
Any of these paths works — the MSI runs `uninstall.ps1` as a deferred custom action whenever `REMOVE=ALL`, so each one stops the service, removes the Claude Code hook, removes the auto-start Run-key entry, and cleans `bin\` from the user `PATH` before removing files.

The bundled helper is still the most convenient:
- **Apps & Features** → Prempti → Uninstall (recommended).
- **By MSI path** (if you still have the file):

```powershell
powershell -ExecutionPolicy Bypass -File Uninstall-Prempti.ps1
```
```powershell
msiexec /x prempti-<version>-windows-<arch>.msi
```
- **By product code** (the GUID is in `HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\` under the Prempti entry):

> **Older 0.1.x builds**: MSI packages from before the uninstall custom action was added required the helper script — without it, Apps & Features would leave the Claude Code hook registered and brick Claude Code until `premptictl hook remove` was run manually.
```powershell
msiexec /x <product-code>
```

## Running Tests

Expand Down
48 changes: 0 additions & 48 deletions installers/windows/package.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -246,53 +246,5 @@ if (-not $wix) { throw 'WiX Toolset not found. Install via: dotnet tool install

if ($LASTEXITCODE -ne 0) { throw 'WiX build failed.' }

# ---------------------------------------------------------------------------
# Emit companion uninstall script
# ---------------------------------------------------------------------------

$uninstallScript = Join-Path $OutputDir 'Uninstall-Prempti.ps1'
@"
# Uninstall Prempti $Version
# Run cleanup first: remove hook and auto-start registration
`$prefix = Join-Path `$env:LOCALAPPDATA 'prempti'
`$cleanup = Join-Path `$prefix 'scripts\uninstall.ps1'
if (Test-Path `$cleanup) {
& powershell -NoProfile -ExecutionPolicy Bypass -File `$cleanup -Prefix `$prefix
}
# Remove files via MSI
`$p = Start-Process msiexec -ArgumentList '/x', '$ProductCode', '/quiet' -Wait -PassThru
if (`$p.ExitCode -ne 0 -and `$p.ExitCode -ne 1605) { Write-Error "Uninstall failed (exit `$(`$p.ExitCode))" }
Write-Host "Uninstall complete"
"@ | Set-Content $uninstallScript -Encoding UTF8

# ---------------------------------------------------------------------------
# Emit install helper script (runs MSI + postinstall)
# ---------------------------------------------------------------------------

$installScript = Join-Path $OutputDir 'Install-Prempti.ps1'
@"
# Install Prempti $Version
`$msi = Join-Path `$PSScriptRoot '$MsiName'
`$productCode = '$ProductCode'

# If already installed, open normal MSI maintenance UI (Repair/Uninstall)
# instead of forcing a silent reinstall.
`$installer = New-Object -ComObject WindowsInstaller.Installer
`$state = `$installer.ProductState(`$productCode)
if (`$state -eq 5) {
Start-Process msiexec -ArgumentList '/i', `$msi -Wait | Out-Null
exit 0
}

`$p = Start-Process msiexec -ArgumentList '/i', `$msi, '/quiet' -Wait -PassThru
if (`$p.ExitCode -ne 0) { Write-Error "MSI install failed (exit `$(`$p.ExitCode))"; exit 1 }
# postinstall.ps1 runs automatically via the MSI deferred custom action
# (see installers\windows\Package.wxs). No manual follow-up is required.
Write-Host "Prempti installation complete"
"@ | Set-Content $installScript -Encoding UTF8

Write-Host ""
Write-Host "MSI created: $(Join-Path $OutputDir $MsiName)"
Write-Host ""
Write-Host "Install: powershell -ExecutionPolicy Bypass -File Install-Prempti.ps1"
Write-Host "Uninstall: powershell -ExecutionPolicy Bypass -File Uninstall-Prempti.ps1"
Loading