# trayiconguard (npm)

Keep every **notification-area (system tray) icon** visible on Windows 10/11 — and keep it that way.

This npm package is a thin wrapper around the official
[TrayIconGuard](https://github.com/paulmann/windows-show-all-tray-icons) Windows binary:

- it **does not bundle** the executable — the package stays a few kilobytes;
- it downloads the release asset and **verifies its SHA-256 against the project's update feed**
  before the binary is ever started;
- the verified copy is cached in `%LOCALAPPDATA%\TrayIconGuard\npm` and reused.

```console
$ npx trayiconguard install        # download + verify, then start the setup wizard
$ npx trayiconguard status --json  # machine-readable tray state
$ npx trayiconguard autostart on   # start with Windows (HKCU Run entry)
$ npx trayiconguard update         # check the feed and update in place
$ npx trayiconguard uninstall
```

| Command | What it does |
|---|---|
| `install` | download + verify, then start the GUI wizard (*Only for me* needs no admin; *For all users* asks for one UAC prompt) |
| `install --machine <dir>` | machine-wide install body — must run in an **elevated** shell |
| `download` | download + verify into the cache only |
| `run [--minimized]` | run the cached binary |
| `status [--json]` | print tray state (`--json` for automation) |
| `promote-all` | promote every hidden icon right now, then exit |
| `autostart on\|off` | add/remove the `HKCU\…\Run` autostart entry |
| `update` | check the git feed and apply a newer version non-interactively |
| `uninstall` | remove shortcuts, autostart and the installed copy |
| `exe` | print the path of the cached executable |
| `version` | wrapper version + the latest published binary version |

Options: `--version <v>`, `--url <direct-exe-url>`, `--feed <url>`, `--force`, `--no-verify`,
`--minimized`, `--machine <dir>`, `--json`, `-h`.

> **Redirecting the wrapper works:** the 8.6.0 binary used to discard CLI output when `stdout` was
> a pipe or a file; that is fixed in 8.6.2, so
> `trayiconguard status --json > state.json` and `| ConvertFrom-Json` behave as expected.

## Requirements

- **Windows 10 1703+ or Windows 11, x64** (the binary is a native Win32 exe; the package declares
  `os: win32`, `cpu: x64`, so npm refuses to install it elsewhere).
- Node.js **18+** only to run this wrapper — TrayIconGuard itself has **zero runtime dependencies**
  (no .NET, no Visual C++ redistributable).

## What the binary does

It writes the same `HKCU\Control Panel\NotifyIconSettings\{id}\IsPromoted` values the Windows
Settings toggle uses (per user, no admin), and keeps a `RegNotifyChangeKeyValue` watcher on that
store so icons Explorer hides again are re-promoted within a fraction of a second. Extras: a
Fluent GUI with Light/Dark/System themes, 30 locales, JSON snapshots, an activity log, a headless
`--watch` mode, a full CLI with stable exit codes, and SHA-256-pinned self-updates. No telemetry.

## Security notes

- Every download is verified against the `sha256` field of
  [`update/stable.json`](https://raw.githubusercontent.com/paulmann/windows-show-all-tray-icons/main/update/stable.json);
  the daily feed is generated by the project's CI **from the bytes the GitHub release actually serves**.
- On a mismatch the file is deleted and the command aborts.
- Only the feed and the release asset are ever fetched — both over HTTPS.
- `--no-verify` exists for local debugging and is deliberately discouraged.

## Uninstall

```console
$ npx trayiconguard uninstall
$ npm uninstall -g trayiconguard     # if installed globally
$ rmdir /s "%LOCALAPPDATA%\TrayIconGuard\npm"
```

## Publication status — 2026-10-16

The package is finished and packed; the npm registry name `trayiconguard` is still free.
The wrapper always downloads the asset the live feed points at (currently **8.6.3**).

| Check | Result |
|---|---|
| `pnpm pack` | valid tarball (`trayiconguard-8.6.3.tgz`, ~7.8 kB) with `bin/trayiconguard.js`, `LICENSE`, `package.json`, `README.md` ✅ |
| `trayiconguard download` | downloads the feed's asset and its SHA-256 matches `update/stable.json` ✅ |
| `trayiconguard status --json` | forwards to the real binary, exit code 0 ✅ |
| negative test (`--url` pointing at the zip while the feed pins the exe) | `SHA-256 mismatch`, exit 1, corrupted file deleted ✅ |

**Publishing to npmjs.com is blocked by credentials.** `pnpm whoami` and `pnpm publish` fail with
`401 Unauthorized` / `404 Not Found`: the granular token in `%USERPROFILE%\.npmrc` is expired or
revoked. Refresh the credential and run:

```powershell
npm login                     # writes a fresh token into %USERPROFILE%\.npmrc
pnpm whoami                   # a 401 here still means the token is bad

cd packaging\npm
pnpm publish --no-git-checks --access public

npm view trayiconguard version dist.tarball dist.integrity
```

After the package is live, add a row to the READMEs:

```text
npx trayiconguard install
```

**GitHub Packages was tried as a fallback and is blocked as well:** publishing
`@paulmann/trayiconguard` to `npm.pkg.github.com` returns
`403 Permission permission_denied: The token provided does not match expected scopes` — the
GitHub token carries no `packages: write`. Either credential unblocks publication:

| Target | Credential needed | Command |
|---|---|---|
| npmjs.com (`trayiconguard`) | valid granular token with *read and write* for packages, or `npm login` | `pnpm publish --no-git-checks --access public` |
| GitHub Packages (`@paulmann/trayiconguard`) | classic PAT with `write:packages` (or fine-grained *Packages: Read and write*) | publish from a copy renamed to the scoped name with `publishConfig.registry = https://npm.pkg.github.com` |

## License

[PolyForm Noncommercial License 1.0.0](LICENSE) — free for noncommercial use; commercial
licensing: <icons@Deynekin.com>. TrayIconGuard is not affiliated with Microsoft.
