Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f573c38
feat: new CLI structure - migrate to setup subcommand
cmorten Jul 12, 2026
a3bb4a8
Apply suggestion from @cmorten
cmorten Jul 12, 2026
8acc82e
feat: initial manifest check
cmorten Jul 12, 2026
5d4af9b
ci: first draft test workflow for install
cmorten Jul 12, 2026
2341092
ci: dummy manifest
cmorten Jul 12, 2026
662ef10
temp: logs
cmorten Jul 12, 2026
54a9d8c
feat: macos
cmorten Jul 12, 2026
8401dbe
feat: manifest resolution, cache, and download
cmorten Jul 17, 2026
2c3a4d7
fix: missing return in validation
cmorten Jul 17, 2026
563e017
fix: ci manifest
cmorten Jul 17, 2026
9244036
ci: test install for windows and linux
cmorten Jul 17, 2026
8801ce6
ci: test jobs rename
cmorten Jul 17, 2026
b785826
ci: use bash
cmorten Jul 17, 2026
0753d2e
ci: fix ubuntu not linux
cmorten Jul 17, 2026
e714f59
feat: support proxy env vars
cmorten Jul 17, 2026
e98e598
feat: auto-extract nvda zip assets
cmorten Jul 17, 2026
5d8888a
ci: fix whitespace
cmorten Jul 17, 2026
73d7357
ci: temp log
cmorten Jul 17, 2026
00a805e
feat: migrate away from decompress
cmorten Jul 17, 2026
eb4b9ba
feat: register installs to cache and prune dead cache assets
cmorten Jul 17, 2026
fb925c3
feat: log error causes
cmorten Jul 17, 2026
270dad9
fix: avoid * in file paths
cmorten Jul 17, 2026
ddc0f57
docs: improve documentation
cmorten Jul 17, 2026
7250d33
docs: global install
cmorten Jul 17, 2026
ecf3933
chore: remove spec.md for agents
cmorten Jul 17, 2026
65d749a
docs: improve docs coverage
cmorten Jul 18, 2026
e803071
chore: package description
cmorten Jul 18, 2026
fed6d5b
docs: tweak quick start
cmorten Jul 18, 2026
62ae2ff
fix: more reliable unzip
cmorten Jul 18, 2026
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
96 changes: 81 additions & 15 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
branches: [main]

jobs:
test:
test-setup:
runs-on: ${{ matrix.os }}
strategy:
matrix:
Expand All @@ -23,7 +23,7 @@ jobs:
windows-11-arm,
]
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
Expand All @@ -35,13 +35,13 @@ jobs:
name: artifacts-test-${{ matrix.os }}
path: |
**/recordings/**/*
test-ignore-tcc-db:
test-setup-ignore-tcc-db:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest]
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
Expand All @@ -53,22 +53,88 @@ jobs:
name: artifacts-test-ignore-tcc-db-${{ matrix.os }}
path: |
**/recordings/**/*
test-nvda-install-dir:

test-install:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-2022, windows-2025, windows-11-arm]
os:
[
macos-14,
macos-15,
macos-15-intel,
macos-26,
macos-26-intel,
windows-2022,
windows-2025,
windows-11-arm,
ubuntu-latest,
]
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
- run: yarn install --frozen-lockfile
- run: yarn ci:nvda-install-dir
- run: Get-ChildItem $env:USERPROFILE\nvda
- uses: actions/upload-artifact@v4
if: always()
with:
name: artifacts-test-nvda-install-dir-${{ matrix.os }}
path: |
**/recordings/**/*
- run: yarn build
- shell: bash
run: |
tmpdir=$(mktemp -d)
cd "$tmpdir"
npm init -y
npm install @guidepup/guidepup
npm install -g "${GITHUB_WORKSPACE}"
export PATH="$(npm bin -g):$PATH"

cat > node_modules/@guidepup/guidepup/manifest.json <<'EOF'
{
"version": 1,
"screenReaders": [
{
"id": "nvda",
"name": "NVDA",
"platforms": ["win32"],
"defaultDownload": true,
"assets": [
{
"version": "0.2.1-2026.1.1",
"repository": "guidepup/nvda",
"asset": "guidepup-nvda-0.2.1-2026.1.1.zip",
"sha256": "b6fdfde86190c7c14132d459f2f88995da6251ded431e23947d676ffb152f963"
}
]
},
{
"id": "voiceover",
"name": "VoiceOver",
"platforms": ["darwin"],
"defaultDownload": true,
"assets": [
{
"version": "0.0.1",
"platformVersion": "23",
"repository": "guidepup/voiceover",
"asset": "guidepup-voiceover-preferences-macos-14.dmg",
"sha256": "c6595f5ca50440e8553cde278936a46eff58d4c904e19c87e7d0e25950617ee1"
},
{
"version": "0.0.1",
"platformVersion": "24",
"repository": "guidepup/voiceover",
"asset": "guidepup-voiceover-preferences-macos-15.dmg",
"sha256": "8bdc3a11c45a19cc876a859bfbd64529469a8b7d4ad41fd7e00a0729ebdbcb25"
},
{
"version": "0.0.1",
"platformVersion": "25",
"repository": "guidepup/voiceover",
"asset": "guidepup-voiceover-preferences-macos-26.dmg",
"sha256": "9af2a3af7c9bffae1b2af26f1970548ecd62f33965fd30f4e43f21b9f57ce5ca"
}
]
}
]
}
EOF

guidepup install
143 changes: 91 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,108 +1,147 @@
# Guidepup Setup
# `@guidepup/setup`

<a href="https://www.npmjs.com/package/@guidepup/setup"><img alt="Guidepup Setup available on NPM" src="https://img.shields.io/npm/v/@guidepup/setup" /></a>
<a href="https://github.com/guidepup/setup/actions/workflows/test.yml"><img alt="Guidepup Setup test workflows" src="https://github.com/guidepup/setup/workflows/Test/badge.svg" /></a>
<a href="https://github.com/guidepup/setup/blob/main/LICENSE"><img alt="Guidepup Setup uses the MIT license" src="https://img.shields.io/github/license/guidepup/setup" /></a>

## [Documentation](https://www.guidepup.dev/docs/guides/automated-environment-setup)

[![MacOS Sonoma Support](https://img.shields.io/badge/macos-Somona-blue.svg?logo=apple)](https://apps.apple.com/us/app/macos-sonoma/id6450717509)
[![MacOS Sequoia Support](https://img.shields.io/badge/macos-Sequoia-blue.svg?logo=apple)](https://apps.apple.com/us/app/macos-sequoia/id6596773750)
[![MacOS Tahoe Support](https://img.shields.io/badge/macos-Tahoe-blue.svg?logo=apple)](https://www.apple.com/uk/os/macos/)
[![macOS Sonoma Support](https://img.shields.io/badge/macos-Somona-blue.svg?logo=apple)](https://apps.apple.com/us/app/macos-sonoma/id6450717509)
[![macOS Sequoia Support](https://img.shields.io/badge/macos-Sequoia-blue.svg?logo=apple)](https://apps.apple.com/us/app/macos-sequoia/id6596773750)
[![macOS Tahoe Support](https://img.shields.io/badge/macos-Tahoe-blue.svg?logo=apple)](https://www.apple.com/uk/os/macos/)
[![Windows Server 2022 Support](https://img.shields.io/badge/windows_server-2022-blue.svg?logo=windows)](https://www.microsoft.com/en-us/evalcenter/evaluate-windows-server-2022)
[![Windows Server 2025 Support](https://img.shields.io/badge/windows_server-2025-blue.svg?logo=windows)](https://www.microsoft.com/en-us/evalcenter/evaluate-windows-server-2025)

This package sets up your environment for screen reader automation.
The `@guidepup/setup` CLI enables automation for <a href="https://www.guidepup.dev/docs/api/class-voiceover"><b>VoiceOver on macOS</b></a> and <a href="https://www.guidepup.dev/docs/api/class-nvda"><b>NVDA on Windows</b></a>.

It enables automation for <a href="https://www.guidepup.dev/docs/api/class-voiceover"><b>VoiceOver on MacOS</b></a> and <a href="https://www.guidepup.dev/docs/api/class-nvda"><b>NVDA on Windows</b></a>.
## Quick start

## Getting Started
```sh
# Setup machine once for screen reader automation
npx @guidepup/setup setup

Run this command:
# In project directory install Guidepup
npm install @guidepup/guidepup

```console
npx @guidepup/setup
# In project directory install required screen reader assets
npx @guidepup/setup install
```

And get cracking with your screen reader automation code!
## Environment setup

## Usage
The `setup` CLI command configures your operating system for screen reader automation and only needs to be run once per machine:

### GitHub Actions
```sh
npx @guidepup/setup setup
```

### CI

If you are using GitHub Actions, check out the dedicated [`guidepup/setup-action`](https://github.com/marketplace/actions/guidepup-setup):
If you are running the `setup` CLI command in CI/CD, it is recommended to add the `--ci` flag to prevent prompts for manual interaction:

```yaml
- name: Setup Environment
uses: guidepup/setup-action
```sh
npx @guidepup/setup setup --ci
```

### MacOS
### macOS

If you are running this command locally you may need to take some manual steps to complete setup by following the [manual VoiceOver setup documentation](https://www.guidepup.dev/docs/guides/manual-voiceover-setup).

#### CI
#### Ignoring TCC database updates

If you are running this command in CI/CD, it is recommended to add the `--ci` flag to prevent interactive prompts:
If updating the `TCC.db` is not possible (due to enabled System Integrity Protection) or not required for your macOS setup, you can skip database updates by using the `--macos-ignore-tcc-db` flag:

```console
npx @guidepup/setup --ci
```sh
npx @guidepup/setup setup --macos-ignore-tcc-db
```

#### Ignore TCC.db Updates
> [!NOTE]
> If the necessary permissions have not been granted by other means, using this flag may result in your environment not being set up for reliable screen reader automation.

> [!WARNING]
> For system TCC.db updates you must first disable [System Integrity Protection (SIP)](https://support.apple.com/en-gb/102149). This comes with **serious security implications**, so please first refer to the [Apple documentation](https://developer.apple.com/documentation/security/disabling-and-enabling-system-integrity-protection) for more details before taking any action. Consider whether you are able to use alternative manual setup steps for configuration before exploring this option further.
>
> SIP only needs to be disabled while the required changes are being made. Re-enable SIP once the `setup` CLI command has completed.

If updating the TCC.db is not possible (due to SIP) or required you can skip the database update step by using the `--ignore-tcc-db` flag:
#### Recording

```console
npx @guidepup/setup --ignore-tcc-db
If you are encountering errors in CI for macOS you can pass a `--macos-record` flag to the command which will output a screen-recording of the setup to a `./recordings/` directory:

```sh
npx @guidepup/setup setup --ci --macos-record
```

> [!NOTE]
> If the necessary permissions have not been granted by other means, using this flag may result in your environment not being set up for reliable screen reader automation.
## Installing screen reader assets

#### Recording
Each version of Guidepup requires specific screen reader assets to execute correctly.

Install the default supported screen reader assets with one command from your project directory:

If you are encountering errors in CI for MacOS you can pass a `--record` flag to the command which will output a screen-recording of the setup to a `./recordings/` directory:
```sh
npx @guidepup/setup install
```

The `install` CLI command uses your project's installed `@guidepup/guidepup` version to determine which screen reader assets to install.

New Guidepup releases may update the required screen reader assets. If you update Guidepup, rerun the `install` CLI command to install the latest supported screen reader assets.

```console
npx @guidepup/setup --ci --record
You can install a specific screen reader by providing additional arguments to the `install` CLI command:

```sh
# Install VoiceOver
npx @guidepup/setup install voiceover

# Install NVDA
npx @guidepup/setup install nvda
```

### Windows
Screen reader options include:

- `voiceover` on macOS (default)
- `nvda` on Windows (default)

#### NVDA Installation
### Managing screen reader assets

When running on windows a portable NVDA instance compatible with Guidepup will be installed to a temporary directory by default. The location of this installation directory is stored in the Windows registry under the key `HKCU\Software\Guidepup\Nvda`.
By default Guidepup downloads screen reader assets into the operating system's standard cache directory:

If you want to specify the directory that NVDA is installed to you can pass a `--nvda-install-dir` flag to the command:
- `~/.cache/guidepup/` on Linux
- `~/Library/Caches/guidepup/` on macOS
- `%USERPROFILE%\AppData\Local\guidepup\` on Windows

```console
npx @guidepup/setup --nvda-install-dir <NVDA_INSTALLATION_DIRECTORY>
You can override the default cache directory using an environment variable:

```sh
GUIDEPUP_SCREEN_READERS_PATH=$HOME/guidepup npx @guidepup/setup install
```

##### Using HTTP / HTTPS Proxy for Installation
### Unused screen reader cleanup

If you are using a proxy connection, you must define the proxy URL in an env variable. You can use any of the following variables:
Guidepup tracks which projects use each installed screen reader asset. When an asset is no longer referenced by any project, it is automatically removed the next time the `install` CLI command runs.

- `HTTPS_PROXY`
- `https_proxy`
- `HTTP_PROXY`
- `http_proxy`
### Installing behind a proxy

#### Foreground Timeout Lock
Guidepup screen readers are installed directly from GitHub release URLs. If you are using a proxy you can use an environment variable to define the proxy URL:

Modern versions of Windows have a setting which prevents new application instances launching in front of other applications in quick succession, requiring over 3 minutes between activations before it will actually show the window - in the interim it launches the window minimized.
```sh
HTTPS_PROXY=https://192.0.2.1 npx @guidepup/setup install
```

Many test automation frameworks will completely close down a browser after a test has finished and then launch a new instance for the next test - on Windows this suffers from the timeout lock on foreground windows. This impacts on screen reader automation which need the window to activate and focus to be able to drive the screen reader on the application.
## Global install

To mitigate this the setup script updates two keys in the Windows registry under `HKCU\Control Panel\Desktop`:
You can install the CLI globally:

- `ForegroundLockTimeout` - Specifies the time in milliseconds, following user input, during which the system will not allow applications to force themselves into the foreground. Defaults to `200000`.
- `ForegroundFlashCount` - Determines the number of times the taskbar button will flash to notify the user that a background window has been activated by the system. If the time elapsed since the last user input exceeds the value of ForegroundLockTimeout, the window will automatically be brought to the foreground. Defaults to `3`.
```sh
npm install -g @guidepup/setup
```

Both of these are set to `0` by the setup script.
After which you can access the CLI directly through the `guidepup` command:

```sh
guidepup setup
guidepup install
```

## Powerful Tooling
## Powerful tooling

Check out some of the other Guidepup modules:

Expand Down
File renamed without changes.
24 changes: 11 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"name": "@guidepup/setup",
"version": "0.23.0",
"description": "Setup your environment for screen-reader automation.",
"version": "0.24.0",
"description": "CLI for configuring environments and install screen reader assets for Guidepup.",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
"bin": {
"setup": "bin/setup"
"guidepup": "bin/guidepup"
},
"author": "Craig Morten <craig.morten@hotmail.co.uk>",
"license": "MIT",
Expand All @@ -26,16 +26,15 @@
],
"scripts": {
"build": "yarn clean && yarn compile",
"ci": "yarn clean && yarn lint && yarn build && yarn resolutionFix && yarn start --ci --record",
"ci:nvda-install-dir": "yarn clean && yarn lint && yarn build && yarn resolutionFix && yarn start --ci --record --nvda-install-dir %userprofile%\\nvda",
"ci:ignore-tcc-db": "yarn clean && yarn lint && yarn build && yarn resolutionFix && yarn start --ci --record --ignore-tcc-db",
"ci": "yarn clean && yarn lint && yarn build && yarn resolutionFix && yarn start:setup --ci --macos-record",
"ci:ignore-tcc-db": "yarn clean && yarn lint && yarn build && yarn resolutionFix && yarn start:setup --ci --macos-record --macos-ignore-tcc-db",
"clean": "rimraf lib",
"compile": "tsc",
"dev": "ts-node ./src/index.ts",
"resolutionFix": "ts-node ./.github/workflows/resolutionFix.ts",
"lint": "eslint . --ext .ts",
"lint:fix": "yarn lint --fix",
"start": "node ./bin/setup",
"start:setup": "node ./bin/guidepup setup",
"prepublish": "yarn build"
},
"devDependencies": {
Expand All @@ -53,10 +52,9 @@
},
"dependencies": {
"chalk": "^4.0.0",
"decompress": "^4.2.1",
"https-proxy-agent": "^7.0.5",
"regedit": "5.0.1",
"semver": "^7.5.4"
},
"guidepupNvdaVersion": "0.2.0-2026.1.1"
"commander": "^15.0.0",
"semver": "^7.5.4",
"undici": "^8.7.0",
"unzipper": "^0.12.5"
}
}
13 changes: 13 additions & 0 deletions src/commands/install/delete-asset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { rm } from "node:fs/promises";
import { handleInfoWithPath } from "../../logging";

export async function deleteAsset(assetPath: string): Promise<void> {
handleInfoWithPath("Removing", assetPath);

try {
await rm(assetPath, { force: true, recursive: true });
} catch {
// Ignore cleanup failures, preferring to expose the error that triggered
// cleanup.
}
}
Loading
Loading