diff --git a/README.md b/README.md index c8ca301..6bd9197 100644 --- a/README.md +++ b/README.md @@ -1,55 +1,69 @@ -# CodexBar +
+ Your Codex usage limits, in the macOS menu bar, in your timezone. +
-CodexBar puts your Codex plan limits in the macOS menu bar. It shows the current five-hour and weekly usage, reset times in your timezone, and whether you're ahead of a steady pace through each window. + -It deliberately stops there: no cost tracking, charts, token copying, account switching, or provider abstraction. +--- -Settings cover the parts that affect the small menu-bar experience: +CodexBar shows your Codex plan limits in the menu bar—the same session and weekly percentages reported by Codex, nothing more. The menu-bar item shows the highest usage percentage; the dropdown lists each limit with a progress bar, its reset time in your local timezone, and whether you're ahead of a steady pace through the window. -- Default or custom warning and critical colours -- A pace flame beside the menu-bar percentage -- Full-screen reactions for session resets, weekly resets, and crossing weekly pace -- Launch at login +That's the whole app. No cost tracking, charts, token copying, account switching, or provider abstraction. -## Requirements +## Install -- macOS 15 or later on Apple Silicon -- Codex CLI installed and signed in with ChatGPT +```sh +brew install --cask gordonbeeming/tap/codex-bar +open -a CodexBar +``` -CodexBar starts `codex app-server` locally and reads its documented `account/read` and `account/rateLimits/read` responses. Codex owns authentication and token refresh; CodexBar never reads `~/.codex/auth.json`. +CodexBar needs macOS 15 or later on Apple Silicon, plus the [Codex CLI](https://developers.openai.com/codex/cli) installed and signed in with ChatGPT. -If Codex isn't on the app's inherited `PATH`, CodexBar also checks common Homebrew, fnm, Volta, nvm, and `~/.local/bin` locations. Set `CODEX_PATH` to an explicit executable path when needed. +The app launches at login by default. You can turn that off in Settings. -## Build and install +### From source ```sh -make test make install open ~/Applications/CodexBar.app ``` -The installed app launches at login by default. You can turn that off in Settings. +`make install` builds a release binary and signs it with an available Apple Development identity, falling back to ad-hoc signing. + +## Settings + +Open **Settings…** from the dropdown: + +- **Usage colours** — use the default 75% warning and 90% critical levels, or drag the two splitters to choose your own. +- **Pace flame** — show a flame beside the menu-bar percentage when usage is ahead of a steady pace through a window. +- **Celebrations** — choose full-screen reactions for session resets, weekly resets, and crossing the weekly pace line, or turn them off individually. +- **Launch at login** — on by default for an installed app. -## Development +## How it works + +CodexBar starts `codex app-server` locally and reads its `account/read` and `account/rateLimits/read` responses once a minute, plus when the menu opens with stale data. Codex remains responsible for authentication and token refresh; CodexBar never reads `~/.codex/auth.json`. + +The app guards against temporary usage regressions before updating the display or firing a reset celebration. A suspicious drop must persist across three readings, while a real window reset or a Codex plan change is accepted immediately. Plan changes also reseed the celebration baseline, so upgrading doesn't create a fake reset signal. + +If Codex isn't on the app's inherited `PATH`, CodexBar checks common Homebrew, fnm, Volta, nvm, and `~/.local/bin` locations. Set `CODEX_PATH` to an explicit executable path if your installation lives somewhere else. + +## Dev loop ```sh -make run +make run # Run directly from source +make test # Build and run the unit tests ``` -`swift run` doesn't produce an app bundle, so launch-at-login controls only appear in the installed app. +The testable usage mapping, formatting, thresholds, celebration detection, and snapshot stabilization live in `CodexBarCore`. The app target is a small SwiftUI `MenuBarExtra` on top. ## Releasing -Publish a GitHub release tagged `vX.Y`. The release workflow builds and tests the app, signs it with the Developer ID certificate, notarizes and staples the bundle, uploads `CodexBar-X.Y.dmg`, then updates `gordonbeeming/homebrew-tap`. - -The release job uses the `prod` environment with these secrets: +Publish a GitHub release tagged `vX.Y` and CI handles the rest: tests, Developer ID signing, notarization, stapling, DMG upload, and the signed Homebrew cask update. -- `DEVELOPER_ID_CERTIFICATE` -- `DEVELOPER_ID_PASSWORD` -- `APPLE_ID` -- `APPLE_TEAM_ID` -- `APPLE_APP_PASSWORD` -- `HOMEBREW_TAP_DEPLOY_KEY` -- `COMMIT_SIGNING_KEY` +For local setup, packaging details, CI secrets, and the full release process, see the [development and release guide](docs/development.md). diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000..ed77eef --- /dev/null +++ b/docs/development.md @@ -0,0 +1,88 @@ +# Development and release guide + +This document covers the contributor and maintainer details that don't need to sit in the consumer-focused README. + +## Requirements + +- macOS 15 or later on Apple Silicon +- Xcode with Swift 6.1 or later +- Codex CLI installed and signed in with ChatGPT for live usage data + +## Build and test + +Run the normal development checks with: + +```sh +swift build --build-tests +swift test --parallel +``` + +The Makefile also provides a release build target and a standard test target: + +```sh +make build # swift build -c release +make test # swift test +``` + +## Run and install + +Run the executable directly from source with: + +```sh +make run +``` + +`swift run` doesn't create an app bundle, so launch-at-login controls are only available in an installed build. + +After any code change that affects the app, install and relaunch it: + +```sh +make install +open ~/Applications/CodexBar.app +``` + +`make install` builds the release executable, creates `dist/CodexBar.app`, signs it with an available Apple Development identity or ad-hoc identity, stops the running installed copy, and copies the new bundle to `~/Applications`. + +To create the signed bundle without installing it: + +```sh +make bundle +``` + +You can override the bundle metadata and signing options when packaging: + +```sh +make bundle VERSION=0.3 BUILD=42 CODESIGN_IDENTITY="Developer ID Application: YOUR_NAME (TEAM_ID)" CODESIGN_OPTS="--options runtime --timestamp" +``` + +## Project structure + +- `Sources/CodexBarCore` contains the testable protocol models, usage mapping, formatting, severity thresholds, celebration detection, and snapshot stabilization. +- `Sources/CodexBar` contains the app-server client, settings, menu-bar UI, reactions, launch-at-login support, and icon rendering. +- `Tests/CodexBarCoreTests` covers the core behavior. +- `Packaging/Info.plist` and `Makefile` build the distributable app bundle. +- `.github/workflows/build.yml` runs CI and publishes releases. + +## Release process + +Releases use `vX.Y` tags. Publishing a GitHub release triggers the release job, which: + +1. Builds and tests all targets. +2. Imports the Developer ID certificate into a temporary keychain. +3. Builds and signs `CodexBar.app` with the hardened runtime and timestamping. +4. Verifies the signature, submits the app for notarization, and staples the ticket. +5. Creates and uploads `CodexBar-X.Y.dmg`. +6. Updates `gordonbeeming/homebrew-tap` with the matching version and SHA-256 checksum. +7. Signs the Homebrew cask commit before pushing it through the repository-specific deploy key. + +The `prod` GitHub environment provides these secrets: + +- `DEVELOPER_ID_CERTIFICATE` +- `DEVELOPER_ID_PASSWORD` +- `APPLE_ID` +- `APPLE_TEAM_ID` +- `APPLE_APP_PASSWORD` +- `HOMEBREW_TAP_DEPLOY_KEY` +- `COMMIT_SIGNING_KEY` + +The certificate secret contains the base64-encoded `.p12`. `COMMIT_SIGNING_KEY` must contain an OpenSSH-formatted private key because Git's SSH signing helper doesn't accept the PKCS#8 export produced by some password managers.