# PackPilot 2.0.2

**Released 2026-08-16.** A Ninite-style bulk software installer, now for **both Windows and
macOS**, driven by one shared catalogue of 124 free applications.

## 2.0.2 — standalone repository publication

The authoritative source was published in its own repository on 2026-08-16. The Windows archive
was rebuilt under a new patch version so the documentation packaged beside the executable names
the current Windows and macOS releases. Application behavior is unchanged.

The macOS artifact remains version 1.0.1 and is byte-identical to the Developer ID signed,
notarised and stapled build already published by InstaHost.

## What's new

### One catalogue, two editions

PackPilot is now cross-platform. The Windows edition and the new macOS edition read the **same
`catalog/catalog.json`**, embedded into each build from the single copy in the repository. Each
build compares the embedded digest against the shared file and fails if they differ, so the two
editions cannot drift apart without the build saying so.

- **124 applications** across 13 categories: 110 installable on Windows, 90 on macOS, 76 on both.
- Windows installs are performed by the **Windows Package Manager (winget)**, falling back to
  **Chocolatey** and then to a direct download.
- macOS installs are performed by **Homebrew**, using `brew install --cask` for applications and
  `brew install` for command-line packages.

Nothing is bundled and nothing is repackaged. PackPilot only ever asks an official package
manager for a package by its official identifier.

### Every identifier is verified against its official source

The catalogue is the one part of this project that can be wrong without the compiler noticing: a
package identifier that does not exist looks perfectly valid in JSON and only fails on the
technician's machine, halfway through a deployment.

`tools/verify-catalog.py` therefore checks every identifier against the vendor's own index
before each build:

- **Windows** — the Windows Package Manager community source index that `winget` itself
  downloads, `https://cdn.winget.microsoft.com/cache/source.msix` (14,323 package identifiers).
- **macOS** — the official Homebrew cask and formula API at `https://formulae.brew.sh`
  (7,687 casks and 8,535 formulae).

All 109 winget identifiers and 90 Homebrew tokens resolve. The check runs as the first step of
`build.sh` and blocks the build on any failure.

### Licence badges

The catalogue deliberately mixes open-source software with freeware and the free editions of
commercial products. A technician ticking boxes on a client's machine has to be able to tell them
apart, so every application now carries an explicit licence and a badge beside its name:

| Badge | Meaning |
| --- | --- |
| open source | Released under an open-source licence. |
| freeware | Free of charge, closed source. |
| free personal | Free for personal or non-commercial use; a licence is required at work. |
| free tier | Free account or free edition of a commercial product. |

The badge never relies on colour alone — the text says which it is — and the full licence
sentence is on the tooltip. Search matches the licence too, so `open source` filters the list.

### The insta.host look, on both platforms

Both editions now use the shared InstaHost desktop design: the `#04060F` window ground, the
cyan-to-violet brand gradient, cards with the 2px brand rule, flat controls, and the display /
body / mono font stacks that degrade to whatever is actually installed.

- **Windows** — the theme, controls, About window and provenance code are ported from the User
  Profile Migrator rather than reimplemented, including the shell dark-mode hooks
  (`SetPreferredAppMode`, the immersive dark title bar, `DarkMode_Explorer` / `DarkMode_CFD` /
  `DarkMode_ItemsView`) that the chrome Windows draws itself will otherwise ignore.
- **macOS** — the design tokens are byte-identical to the Simple Scanner implementation, and the
  dark appearance is forced so the product looks the same regardless of the machine.

### An About window that proves what it is

Both editions report, without a network: product and three-part version, build date, publisher
and author, the freeware statement, the **SHA-256 of the running executable**, and the signature
state — Authenticode on Windows, the live code-signature check and team identifier on macOS.
The macOS build is signed with **Developer ID Application: Patrick Hamid (E4DUZ8FY37)**,
notarised by Apple and stapled, so About reports that authority rather than "unknown authority".
The four canonical links (author, more free tools, privacy, buy me a coffee) appear in About and
in a permanent footer in the main window.

### Store packages can be added by identifier

Custom package identifiers now accept an explicit source: `msstore:9NBLGGH4NNS1` or
`winget:Mozilla.Firefox`. A bare twelve-character upper-case identifier is recognised as a
Microsoft Store product ID on its own. Asking the community source for a Store package is the
usual reason winget reports that it "cannot be found".

## Bugs fixed

- **Eight catalogue entries named packages that do not exist.** `VivaldiTechnologies.Vivaldi`,
  `Cisco.WebexTeams`, `dotPDNLLC.paintdotnet`, `AnyDeskSoftwareGmbH.AnyDesk`,
  `TimKosse.FileZilla.Client`, `RustDesk.RustDesk`, `Microsoft.Sysinternals` and the WhatsApp
  Store identifier were all rejected by the winget source. Six are corrected to their real
  identifiers; the rest are served another way or dropped. *Symptom:* the package silently
  failed partway through a deployment. *Root cause:* identifiers were written by hand and never
  checked against the index.
- **Status colours were unreadable on the dark theme.** The deployment list used `Firebrick`,
  a dark green and `Gray`, all chosen for a white background. They now route through named
  theme constants.
- **The category filter hid the tick box but not its row.** Filtering left summary text and
  licence badges behind for hidden applications, and "select all visible" could tick something
  the user could not see. Visibility is now a property of the row.
- **The sample profiles referenced five renamed applications** and silently installed nothing
  for them.

## Behaviour and UX changes

- The recommended set is read from the catalogue's `recommended` flag instead of a hard-coded
  list in the user interface, so it can be curated without a rebuild.
- Applications the running platform cannot install are filtered out entirely rather than offered
  and then failing.
- The Windows About entry opens the provenance window instead of a message box.

## Breaking changes

- **Catalogue schema 1 → 2.** `winget` and `choco` have moved into a `windows` block, a `macos`
  block has been added, and `licence`, `summary` and `recommended` are now expected. A
  hand-written schema-1 `catalog.json` override placed next to the executable will no longer
  populate the picker and must be migrated.
- Five catalogue ids were renamed for consistency across platforms: `azcli` → `azurecli`,
  `githubcli` → `gh`, `nodelts` → `node`, `pwsh` → `powershell`, `wt` → `windowsterminal`.
  Existing `*.ppprofile` files that name them will skip those entries; re-save the profile.

## Known issues and residual risks

- The Windows artifact is **unsigned**, as with the other tools in this family. SmartScreen will
  warn on first run. Verify the published SHA-256 before running it.
- A compile is not a rendering check. Nothing on the build host can render a Windows Forms
  window, so the Windows interface was verified by compilation plus a reading of the diff
  against the design reference; the visual result is confirmed on the next run on Windows.
- Real `winget install` and `brew install` runs were not exercised by the test suite, which would
  mean installing software on the build host. Argument construction, script generation, timeout
  and cancellation are covered by tests.

## 2.0.1 / 1.0.1 — signing correction

The first published build of the macOS edition was ad-hoc signed, so **About**
reported "unknown authority". It is now signed with **Developer ID Application:
Patrick Hamid (E4DUZ8FY37)**, notarised by Apple and stapled, and opens without
a Gatekeeper warning.

The filenames carry new patch versions because the previous ones had already
been published and cached at the edge for 24 hours. Replacing the bytes behind
a filename that is already public does not reach anyone holding a cached copy,
so the corrected build is published under a name that has never been served.
Nothing else changed in either edition.

## Installing

**Windows 10/11 (x64).** Download `PackPilot-2.0.2-win-x64.zip`, extract, run `PackPilot.exe`.
No installer and no .NET runtime are required. It asks for administrator rights so it can install
for all users; decline and it installs for the current user instead.

**macOS 13 or newer (Apple silicon and Intel).** Download `PackPilot-1.0.1-macos-universal.zip`,
extract, drag `PackPilot.app` to Applications. The build is Developer ID signed and notarised,
so it opens without a Gatekeeper warning and needs no `xattr` step.

Homebrew is required; PackPilot offers to install it from the official script if it is missing.
