Skip to content

Commit 5825a84

Browse files
committed
fix(downloads): publish Hex 2.1.17 through a custom host and GitHub mirror
1 parent 9a11b5f commit 5825a84

22 files changed

Lines changed: 274 additions & 29 deletions

‎AGENTS.md‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,19 @@ precedence while available; override everything with `--device`. The app bundle
463463
build requires Xcode 26 for Icon Composer compilation and a Developer ID signing
464464
identity. `scripts/release-app.sh` prepares a notarized and stapled DMG plus its
465465
signed Sparkle appcast; run `scripts/release-app.sh publish` only after validating
466-
the prepared artifact. The Rust app is named `Hex`, packaged as `Hex.app`,
466+
the prepared artifact. Public app downloads and update feeds use
467+
`https://downloads.hex.kitlangton.dev`, connected directly to the `hex-releases`
468+
R2 bucket through Custom Domains. Preserve the legacy public R2 endpoint for
469+
installed clients. The publisher verifies both R2 artifacts and the identical
470+
GitHub DMG mirror before publishing the appcast. GitHub app releases use
471+
`app-v<VERSION>` tags with `--latest=false`, keeping them distinct from SDK
472+
releases. Never overwrite a published artifact with different bytes.
473+
After publishing a new macOS version, update `MAC_VERSION` in `site/src/App.tsx`,
474+
the explicit GitHub mirror/version link in `README.md`, and the Homebrew cask.
475+
Build the site with `bun run --cwd site build`, then deploy from `site` with
476+
`wrangler deploy`; its checked-in config targets `hex-voice-site` at
477+
`hex.kitlangton.dev`. Verify both download links after deployment.
478+
The Rust app is named `Hex`, packaged as `Hex.app`,
467479
with bundle identifier `com.kitlangton.hex2` and executable `hex`. Kit has approved
468480
his personal Developer ID signing team `QC99C9JE59` for this app. Signing requires
469481
an explicit `VOICE_CONTROL_TEAM_ID` and matching `HEX_NOTARY_PROFILE`; the build

‎Cargo.lock‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "voice-control"
3-
version = "2.1.16"
3+
version = "2.1.17"
44
edition = "2024"
55
default-run = "voice-control"
66
license = "MIT"

‎README.md‎

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</p>
1111

1212
<p align="center">
13-
<a href="https://pub-089d681d41754031a4aefa7017d8c2fb.r2.dev/releases/HEX-latest-arm64.dmg"><strong>Download for macOS</strong></a>
13+
<a href="https://downloads.hex.kitlangton.dev/releases/HEX-latest-arm64.dmg"><strong>Download for macOS</strong></a>
1414
· <a href="https://hex.kitlangton.dev/">Website</a>
1515
· <a href="docs/linux.md">Linux beta</a>
1616
· <a href="sdk/typescript/README.md">TypeScript SDK</a>
@@ -49,7 +49,7 @@ or forcibly replace another app already named `Hex.app`.
4949

5050
Or install manually:
5151

52-
1. [Download the latest signed DMG](https://pub-089d681d41754031a4aefa7017d8c2fb.r2.dev/releases/HEX-latest-arm64.dmg) and open it.
52+
1. [Download the latest signed DMG](https://downloads.hex.kitlangton.dev/releases/HEX-latest-arm64.dmg) and open it.
5353
2. Drag `Hex.app` into Applications, then launch it.
5454
3. Complete the permission and model steps in setup.
5555

@@ -61,9 +61,17 @@ Or install manually:
6161
HEX checks for signed updates automatically. Use **HEX > Check for Updates...**
6262
to check immediately.
6363

64-
**Looking for the Mac app in GitHub Releases?** Those releases currently contain
65-
the TypeScript SDK. Use the DMG link above for the app and its built-in updater
66-
for subsequent releases.
64+
**Download blocked?** [Alternative download: GitHub — Hex 2.1.16](https://github.com/anomalyco/hex/releases/download/app-v2.1.16/HEX-2.1.16-arm64.dmg)
65+
contains the identical signed DMG for Apple silicon and macOS 15+. App releases
66+
use `app-v…` tags; the repository also publishes separate TypeScript SDK releases.
67+
If an older installation cannot check for updates on your network, install the
68+
DMG manually over the existing Rust app.
69+
70+
On managed networks, ask IT to allow `downloads.hex.kitlangton.dev` for the app
71+
and updates. Local model setup separately needs `huggingface.co` and its model
72+
download CDN; optional Voice Commands needs `download.moonshine.ai`. A successful
73+
app download does not establish that those model hosts are reachable. After
74+
restoring access, retry model preparation in Settings (or Retry for Commands).
6775

6876
Coming from the original Swift app? Install the new app manually and complete
6977
setup. Settings and history are not transferred. Quit the old app before

‎app/Info.plist‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
<key>SUAllowsAutomaticUpdates</key>
4242
<false/>
4343
<key>SUFeedURL</key>
44-
<string>https://pub-089d681d41754031a4aefa7017d8c2fb.r2.dev/appcast.xml</string>
44+
<string>https://downloads.hex.kitlangton.dev/appcast.xml</string>
4545
<key>SUPublicEDKey</key>
4646
<string>mIek27lttJe8cIBqVZFhh6reRKjpTx1h9ZY9OKWPtuM=</string>
4747
<key>SUVerifyUpdateBeforeExtraction</key>

‎app/appcast.xml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
33
<channel>
44
<title>HEX Updates</title>
5-
<link>https://pub-089d681d41754031a4aefa7017d8c2fb.r2.dev/</link>
5+
<link>https://downloads.hex.kitlangton.dev/</link>
66
<description>Signed automatic updates for HEX.</description>
77
<language>en</language>
88
</channel>

‎docs/downloads.md‎

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Download Hosting
2+
3+
## Public Paths
4+
5+
```ts
6+
hex.kitlangton.dev // versioned links and platform requirements
7+
├── downloads.hex.kitlangton.dev // direct R2 Custom Domain; no redirect
8+
│ ├── releases/HEX-<version>-arm64.dmg
9+
│ ├── releases/HEX-<version>-arm64.zip // signed Sparkle artifact
10+
│ ├── releases/HEX-latest-arm64.dmg // mutable pointer; no-cache
11+
│ └── appcast.xml // mutable pointer; published last
12+
└── github.com/anomalyco/hex
13+
└── releases/download/app-v<version>/HEX-<version>-arm64.dmg
14+
```
15+
16+
The `hex-releases` bucket retains its existing `r2.dev` public endpoint so older
17+
Rust installations can still fetch the feed. The current appcast's enclosure
18+
URLs use the custom hostname. No legacy Swift feed is involved.
19+
20+
The download hostname has active TLS with minimum TLS 1.2. A Cloudflare
21+
Configuration Rule disables **Browser Integrity Check** only for
22+
`http.host eq "downloads.hex.kitlangton.dev"`. This is public file hosting for
23+
browser and non-browser clients: the inherited zone check returned HTTP 403,
24+
error 1010, for Python's default user agent. The host-specific rule restored
25+
HTTP 200 without changing the zone-wide setting. Keep future browser challenges
26+
off download and updater routes.
27+
28+
`scripts/release-app.sh publish` uploads and reads back the R2 DMG and ZIP, then
29+
calls `scripts/publish-app-mirror.sh`. The mirror starts as a draft, verifies
30+
the uploaded DMG, publishes with `--latest=false`, and verifies an unauthenticated
31+
download. Existing assets must match byte-for-byte; they are never clobbered.
32+
Only then does the publisher move the latest DMG and publish the appcast.
33+
App tags remain separate from TypeScript SDK tags; do not use GitHub's generic
34+
`releases/latest` redirect for an app download.
35+
36+
After each macOS publication, update the site's `MAC_VERSION`, the README's
37+
explicit app mirror link, and `anomalyco/homebrew-tap/Casks/hex.rb`. Deploy the
38+
site using its checked-in Wrangler config and verify both rendered links.
39+
40+
## Network Recovery
41+
42+
App and model downloads have different hosts. Managed networks may need to allow:
43+
44+
- `downloads.hex.kitlangton.dev` for app artifacts and feeds.
45+
- GitHub release downloads and their asset delivery host for the alternative DMG.
46+
- `huggingface.co` and its model download CDN for dictation-model setup.
47+
- `download.moonshine.ai` for optional Voice Commands.
48+
49+
If the old update endpoint is blocked, install the new signed DMG manually.
50+
After restoring model-host access, retry preparation in Settings or choose
51+
Retry for Commands. Transfer failures preserve partial downloads. App download
52+
success does not establish model-host reachability, and our external checks do
53+
not establish access from a particular enterprise network.
54+
55+
## Observed Migration Checks — September 11, 2026
56+
57+
- The initial 2.1.16 mirror and custom-domain DMG matched the published Homebrew
58+
SHA-256: `102dc1a8d80dc359ee15a30141957b6a311e581214b44a3c615026fa91288b8a`.
59+
Its notarization staple validated.
60+
- All five retained Sparkle ZIPs (2.1.12–2.1.16) were fetched directly through
61+
the custom domain, compared to the prepared artifacts, checked against the
62+
feed's lengths, and verified with the app's Ed25519 public key.
63+
- The migration changed only feed hostnames and terminal whitespace; versions,
64+
signatures, lengths, and release notes were preserved. The published feed was
65+
read back identically from both the custom host and old R2 endpoint.
66+
- The live website was rendered and inspected at 1280×900 and 390×844. Both
67+
showed the version, requirements, and alternate link.
68+
- Homebrew's cask and livecheck use the custom hostname; the 2.1.16 checksum
69+
stayed unchanged during the host migration.
70+
- `cargo test --locked`: 455 passed, 10 opt-in tests ignored, and all 12 keyboard
71+
layout child processes passed. A stale Homebrew `libgit2` build-cache path was
72+
cleared before the successful run. Strict all-target/all-feature Clippy and
73+
the site's TypeScript/production build passed.
74+
- No signed Linux feed has been published yet. Linux installer/updater source
75+
defaults were migrated; no Linux native install or enterprise-network test
76+
was performed as part of these hosting checks.

‎docs/features/README.md‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,38 @@ not require Bun or OpenCode, launch the app automatically, migrate the legacy
3737
Swift app, or forcibly replace an existing app destination. Homebrew uninstall
3838
leaves runtime settings, models, and retained data intact.
3939

40+
```ts
41+
Download Hex // setup.download-recovery
42+
├── Website / README / Homebrew -> downloads.hex.kitlangton.dev -> R2 bytes
43+
├── Alternative download: GitHub -> app-v<version> -> identical signed DMG
44+
└── Older app cannot reach its update feed -> manually install the DMG
45+
46+
Prepare local models // separate network dependency
47+
├── Dictation -> huggingface.co and its download CDN
48+
└── Commands -> download.moonshine.ai
49+
└── Transfer fails -> host-specific guidance -> restore access -> Retry
50+
```
51+
52+
The website shows the pinned macOS version and platform requirements beside its
53+
download links. App mirrors use explicit `app-v…` release tags rather than GitHub's
54+
repository-wide latest release, which may refer to the SDK. The legacy `r2.dev`
55+
endpoint remains available for installed clients. New builds use the custom host
56+
for Sparkle and Linux updates; the signed Linux payload and verification key are
57+
unchanged. Hosting does not guarantee access through every corporate policy.
58+
59+
Sources: [website](../../site/src/App.tsx), [mirror publisher](../../scripts/publish-app-mirror.sh),
60+
[macOS release publisher](../../scripts/release-app.sh),
61+
[Linux installer](../../scripts/install-linux-release.sh), and
62+
[Linux updater](../../src/linux_updater.rs). The macOS publisher verifies the
63+
downloaded R2 artifacts and GitHub mirror before publishing the appcast.
64+
Model transfer failures in [transcription_models.rs](../../src/transcription_models.rs)
65+
and [moonshine.rs](../../src/moonshine.rs) explain the source host, retry, and
66+
separate prerequisites. These messages do not diagnose a particular firewall
67+
or establish a successful subsequent model download.
68+
Executed hosting checks and deployment details are recorded in
69+
[Download Hosting](../downloads.md). In-app feed defaults and recovery copy ship
70+
with 2.1.17; the initial 2.1.16 mirror preserves that release's original bytes.
71+
4072
```ts
4173
Launch Hex // setup
4274
-> Grant Microphone / Input Monitoring / Accessibility

‎docs/features/commands.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ Sources: `load_command_recognizer` and live policy handling in
5151
These cover a controlled loader, notice copy, and settings transitions, not
5252
download-to-speech recognition or physical microphone readiness.
5353

54+
Transfer failures identify `download.moonshine.ai`, suggest restoring connectivity
55+
or asking IT to allow that host, and direct the user to Retry. The error also
56+
explains that hotkey dictation does not need the Commands model. Existing partial
57+
downloads are retained for retry; this is distinct from the app download host.
58+
See [download recovery](README.md#get-ready).
59+
5460
### Awake And Asleep
5561

5662
```ts

‎docs/linux.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ sudo pacman -S --needed alsa-lib curl gtk3 gtk-layer-shell jq libappindicator-gt
7171
libxkbcommon libxkbcommon-x11 libx11 libxcb openblas openssl util-linux \
7272
vulkan-icd-loader wl-clipboard wtype xxd
7373
curl --proto '=https' --tlsv1.2 -fsSLO \
74-
https://pub-089d681d41754031a4aefa7017d8c2fb.r2.dev/install-linux.sh
74+
https://downloads.hex.kitlangton.dev/install-linux.sh
7575
less install-linux.sh
7676
sh install-linux.sh
7777
~/.local/bin/hex model install

0 commit comments

Comments
 (0)