Skip to content

Latest commit

 

History

History
214 lines (156 loc) · 6.41 KB

File metadata and controls

214 lines (156 loc) · 6.41 KB

Distribution

How to cut a release of ModelsUsage and make brew install work. No Apple Developer account involved — the build is ad-hoc signed and recipients do a one-time Gatekeeper allow on first launch.

Everything goes through tools/build-app.sh.

TL;DR

# Personal use — runs on YOUR Mac after one right-click → Open.
./tools/build-app.sh                  # default: ad-hoc signed

# Share with someone — hand them the zip; they do the same dance once.
./tools/build-app.sh
ls build/ModelsUsage-*.zip

build/ is gitignored; rebuilds are clean each time.

Sign modes

Ad-hoc signed (default)

./tools/build-app.sh

Self-signature via codesign --sign -. Hardened runtime stays on and the bundle is tamper-evident, but it identifies no developer, so recipients see "app from an unidentified developer" the first time and need the First launch allow.

Unsigned

./tools/build-app.sh --skip-sign

No signature at all — only useful as a build sanity check.

Configure

Version and bundle ID come from env vars or tools/.env (gitignored):

# tools/.env (optional)
BUNDLE_ID="dev.cato.ModelsUsage"

Defaults if unset:

  • BUNDLE_ID = dev.local.ModelsUsage
  • VERSION = latest v* git tag with the v stripped, falling back to 0.1.0 if there's no tag
  • BUILD = git rev-list --count HEAD

Override on the command line for a one-off:

VERSION=0.3.0-rc1 ./tools/build-app.sh

Cut a release

# 1. Pick a version (semver, no leading "v").
VERSION=0.1.0

# 2. Tag and push. build-app.sh reads `git describe --tags`, so tagging
#    BEFORE building makes the bundle's CFBundleShortVersionString match
#    the release name.
git tag v$VERSION
git push origin v$VERSION

# 3. Build the ad-hoc-signed bundle + companion zip. Produces:
#      build/ModelsUsage.app
#      build/ModelsUsage-$VERSION.zip
./tools/build-app.sh

# 4. Grab the checksum — Homebrew needs it.
shasum -a 256 build/ModelsUsage-$VERSION.zip

# 5. Publish the GitHub release and attach the zip.
gh release create v$VERSION \
  build/ModelsUsage-$VERSION.zip \
  --title "v$VERSION" \
  --notes "ModelsUsage v$VERSION. Ad-hoc signed — first launch needs a Gatekeeper allow (see README)."

Add --draft to review before going live, or --prerelease for -rc/-beta builds (those bypass the git tag — pass VERSION on the command line and skip step 2).

Homebrew support

brew install --cask catokolas/tap/modelsusage works once a release is on GitHub and a cask file exists in the tap. No submission to homebrew-core is needed (and it would reject an ad-hoc signed, un-notarized app anyway).

What's required

  1. A GitHub release with the ModelsUsage-<version>.zip asset (the "Cut a release" recipe above).
  2. A public tap repo named homebrew-<name>. This already exists at catokolas/homebrew-tap (reachable as catokolas/tap — Homebrew strips the homebrew- prefix). It already hosts the macspoonstweaks cask; ModelsUsage just adds a second cask file alongside it.
  3. A cask file Casks/modelsusage.rb in that tap (below).

The cask

Create Casks/modelsusage.rb in catokolas/homebrew-tap:

cask "modelsusage" do
  version "0.1.0"
  sha256 "<paste shasum -a 256 of the release zip here>"

  url "https://github.com/catokolas/ModelsUsage/releases/download/v#{version}/ModelsUsage-#{version}.zip"
  name "Models Usage"
  desc "Native macOS dashboard for AI coding-tool token usage (KIX, Claude Code, Codex)"
  homepage "https://github.com/catokolas/ModelsUsage"

  depends_on macos: :sonoma

  app "ModelsUsage.app"

  zap trash: [
    "~/Library/Application Support/ModelsUsage",
    "~/Library/Caches/ModelsUsage",
  ]
end

Notes on the stanzas:

  • No depends_on cask: "hammerspoon" — unlike MacSpoonsTweaks, ModelsUsage reads the log files / KIX API directly and needs no external runtime. The KIX token lives in the Keychain (item dev.local.ModelsUsage); zap can't remove Keychain items, so users delete that manually if desired: security delete-generic-password -s dev.local.ModelsUsage -a kix-token.
  • depends_on macos: :sonoma — mirrors the macOS 14 floor in Package.swift.
  • zap trash: […] — what brew uninstall --zap removes alongside the app (the settings JSON and the per-source aggregate caches).
  • No auto_updates true — no Sparkle; Homebrew is the update channel (brew upgrade --cask modelsusage).
  • Lowercase token + filename (cask "modelsusage" / Casks/modelsusage.rb); the display name can stay CamelCase.

Bump per release

Each new release only needs version + sha256 updated:

# In the ModelsUsage repo, right after `gh release create …`:
NEW_SHA=$(shasum -a 256 build/ModelsUsage-$VERSION.zip | cut -d' ' -f1)
echo "version: $VERSION  sha256: $NEW_SHA"

# Then in catokolas/homebrew-tap, edit Casks/modelsusage.rb:
#   - set `version "$VERSION"`
#   - set `sha256 "$NEW_SHA"`
# commit + push.

Verify the cask

# Pre-flight audit. DON'T pass `--new` or `--strict` — those enforce
# homebrew-cask SUBMISSION rules (75+ GitHub stars, Apple notarization)
# that a personal tap with an ad-hoc signed app can't meet, and which
# don't block install.
brew audit --cask catokolas/tap/modelsusage

# Real install:
brew install --cask catokolas/tap/modelsusage

# Cleanup test:
brew uninstall --cask --zap modelsusage

Troubleshooting

"App is damaged and can't be opened" (in red)

Stuck quarantine flag (common with zips from email/browsers). Clear it:

xattr -dr com.apple.quarantine /Applications/ModelsUsage.app

Then open as usual. brew install --cask normally strips this for you.

Repeated Keychain prompts after a rebuild

Ad-hoc signatures change on every build, so the Keychain stops trusting the new binary and re-prompts for the stored KIX token. Click Always Allow; it stays quiet until the next rebuild. The app only touches the Keychain when KIX is an active source.

Codesign fails with AMFIUnserializeXML: syntax error

Keep tools/Entitlements.plist minimal (<dict/> only) — Apple's strict plist parser rejects some XML in the entitlements dict.

Build script can't find the executable

It looks under .build/apple/Products/Release/ (universal build) then .build/release/. If both miss, the swift build -c release step failed — run it manually and inspect.