From 4c169ef3d71df28ecccec6536fdef4364dbf9233 Mon Sep 17 00:00:00 2001 From: James Maes Date: Mon, 15 Jun 2026 11:57:32 -0500 Subject: [PATCH] docs: record v100.0.1 release, brew tap, Sparkle key wiring + build gotcha --- docs/EXECUTION-STATUS.md | 9 ++++--- docs/SESSION-STATE.md | 51 +++++++++++++++++----------------------- 2 files changed, 27 insertions(+), 33 deletions(-) diff --git a/docs/EXECUTION-STATUS.md b/docs/EXECUTION-STATUS.md index 28cddeb6..79fa4650 100644 --- a/docs/EXECUTION-STATUS.md +++ b/docs/EXECUTION-STATUS.md @@ -228,9 +228,12 @@ per-component owner actions gathered from the scaffolding agents merged in. notarization/Gatekeeper. Also re-sign the vendored Sparkle helpers under the SAME Developer ID (PLAN §3.3 / §4.6) or notarization rejects. (This is also what makes the default `ai/build.sh` stop failing on the missing `Local Self-Signed` cert.) -- [ ] **Generate a FRESH Sparkle EdDSA keypair:** paste the PUBLIC key into `Info.plist:66` - (replace `REPLACE_WITH_FORK_SUPUBLIC_EDKEY`); store the PRIVATE key as the CI secret - `SPARKLE_ED_PRIVATE_KEY`. The placeholder is NOT lwouis's key and will verify nothing. +- [x] **Sparkle EdDSA keypair generated (2026-06-15).** PUBLIC key wired into `Info.plist` + (`SUPublicEDKey`); PRIVATE key stored in 1Password "CommandTabFree-Sparkle-EdDSA" + GitHub + Actions secret `SPARKLE_ED_PRIVATE_KEY` (env `production`); keychain account `commandtabfree`. + `SUEnableAutomaticChecks` set false until DOMAIN serves a real appcast. + **TODO at CI-wiring time:** `update_appcast.sh` still calls the deprecated `sign_update -s` — + switch it to `--ed-key-file` (or `--account commandtabfree`); the `-s` path rejects this key format. ### 3.4 GitHub Actions secrets + Environment (BLOCKING for release) diff --git a/docs/SESSION-STATE.md b/docs/SESSION-STATE.md index d0659445..7daae772 100644 --- a/docs/SESSION-STATE.md +++ b/docs/SESSION-STATE.md @@ -1,39 +1,30 @@ # SESSION-STATE — CommandTabFree (de-paywalled AltTab fork) -_Handoff written 2026-06-15. Branch: `depaywall-free` (NOT merged to master)._ +_Updated 2026-06-15. `master` now carries the fork (merged + pushed). Public pre-release **v100.0.1** live; Homebrew tap live._ ## What this is -`KofTwentyTwo/alt-tab-free` is a fork of **AltTab** (`lwouis/alt-tab-macos`, GPL-3.0). Upstream author lwouis added a Pro paywall in v11.0.0 (commit `9147a4a8`); this fork **neutralizes the paywall so all features are free** and is rebranded **CommandTabFree**. Goal: ship free + keep merging upstream forever (thin, merge-stable patch — see `docs/PLAN-maintained-fork.md`). +`KofTwentyTwo/alt-tab-free` is a fork of **AltTab** (`lwouis/alt-tab-macos`, GPL-3.0) that neutralizes the v11 Pro paywall so all features are free, rebranded **CommandTabFree**. Strategy: thin, merge-stable patch tracking upstream forever (`docs/PLAN-maintained-fork.md`). -## ✅ DONE (all on branch `depaywall-free`, HEAD `98a023aa`) -- **De-paywall** (commit `f3d76859`): 3 inert edits — `LicenseManager.computeState()` → `guard false else { return .pro }` (single state producer opens every gate); `LicenseCookie.syncLicenseCookie` + `AppCenterCrash.init` wrapped `if false`; `App.handleCustomUrl` early-returns (kills activate-fingerprint POST). `src/pro/` left physically present but inert. -- **Anti-relock tests** (`4506c539`, `1a914c88`): `testDepaywall*` guards in `LicenseManagerTests.swift`; 16 legacy paywall tests `XCTSkip`-marked. **Test scheme GREEN.** -- **Identity** (`4d82a684`): `PRODUCT_NAME=CommandTabFree`, `PRODUCT_BUNDLE_IDENTIFIER=com.koftwentytwo.commandtabfree` (FROZEN) in `config/local.xcconfig`. -- **Local-build version fix** (`e2429096`): `CURRENT_PROJECT_VERSION=0.0.0` in `local.xcconfig` (else `App.version` (App.swift:14) nil-crashes on local builds). -- **Brand sweep + About** (`f5f9034d`): 11 user-facing "AltTab"→"CommandTabFree"; About box credits upstream — _"A free fork of AltTab by Louis Pontoise — GPL-3.0"_ (`AboutTab.swift:18`), Source-code link → fork repo (`App.repository`, App.swift:16). PRESERVED: migration key `PreferencesMigrations.swift:363` "Screen showing AltTab", LICENCE/NOTICE/contributors, src/pro strings. -- **Placeholder icon** (`98a023aa`): `resources/icons/app/app.icns` = dark slate + ⌘⇥ glyph (generated; **real artwork still TODO**). Xcode scheme product name fixed → `CommandTabFree.app`. -- **Local build runs**: ad-hoc-signed `CommandTabFree.app`, de-paywalled, launches. CI/identity scaffolding (`upstream_sync.yml`, `guard.yml`, adapted `ci_cd.yml`, `update_appcast.sh`) committed earlier (`3dde8a91`). +## ✅ DONE +- De-paywall + anti-relock tests + frozen identity (`com.koftwentytwo.commandtabfree`) + brand sweep + placeholder icon — all on **`master`** (was `depaywall-free`, fast-forward merged, HEAD `c7d2d968`, pushed to origin; source is public for GPL §6). +- **Sparkle EdDSA keypair generated.** Public key in `Info.plist` (`SUPublicEDKey`); private key in 1Password item **"CommandTabFree-Sparkle-EdDSA"** + GitHub Actions secret `SPARKLE_ED_PRIVATE_KEY` (env `production`); keychain account `commandtabfree`. `SUEnableAutomaticChecks=false` until a real appcast host exists. This fixed the launch-time "updater failed to start" alert. +- **Public release v100.0.1** (pre-release, **unsigned / not notarized**, universal x86_64+arm64). v100.0.0 deleted (had the Sparkle bug). +- **Homebrew tap live:** `brew install --cask koftwentytwo/tap/commandtabfree` (`KofTwentyTwo/homebrew-tap` → `Casks/commandtabfree.rb`). Cask strips the quarantine (postflight `xattr`) for the unsigned app. +- **Local daily driver installed:** `/Applications/CommandTabFree.app` = **Release** build (no QA menu) signed with the `Local Self-Signed` cert (stable signature → no TCC re-grant loop). Remaining: user grants Accessibility + Screen Recording on first launch. -### Build / run locally -- Ad-hoc (no cert): `xcodebuild -project alt-tab-macos.xcodeproj -scheme Debug -configuration Debug -derivedDataPath DerivedData CODE_SIGN_IDENTITY="-"` → `DerivedData/Build/Products/Debug/CommandTabFree.app` -- Stable signature (recommended, fixes the TCC loop): `scripts/codesign/setup_local.sh` (needs keychain/admin approval — user runs it), then `ai/build.sh`; afterwards `rm -f codesign.{conf,key,crt,p12}`. -- **TCC permission loop** (ad-hoc rebuilds leave stale grants): `tccutil reset ScreenCapture com.koftwentytwo.commandtabfree && tccutil reset Accessibility com.koftwentytwo.commandtabfree`. The durable fix is the stable cert above. +### Build recipes (verified this session) +- **Local (stable, no QA menu):** `xcodebuild -project alt-tab-macos.xcodeproj -scheme Release -derivedDataPath DerivedData CURRENT_PROJECT_VERSION= CODE_SIGN_IDENTITY="Local Self-Signed" CODE_SIGN_STYLE=Manual DEVELOPMENT_TEAM="" OTHER_CODE_SIGN_FLAGS="--timestamp=none" CODE_SIGNING_ALLOWED=YES` (needs `scripts/codesign/setup_local.sh` cert first; user runs it — keychain/admin prompt). +- **Public artifact (ad-hoc):** same recipe but `CODE_SIGN_IDENTITY="-" CODE_SIGNING_REQUIRED=NO`. Zip with `ditto -c -k --sequesterRsrc --keepParent`. +- **GOTCHA — do NOT pass `-configuration Release`.** With `-scheme Release` it splits SPM package outputs and breaks clean-build module-map generation (`build/GeneratedModuleMaps/*.modulemap not found`, then "unable to resolve module Cocoa/Sparkle/..."). Use the scheme only (matches `scripts/build_app.sh`). A failed build can corrupt `build/`; recover with `rm -rf build DerivedData` then rebuild. -## ⏳ NEXT (publish checklist — see `docs/EXECUTION-STATUS.md` §3) -Owner-gated, **Apple Developer ID is the long pole** (user struggling): KofTwentyTwo must enroll as an **Organization** under a *separate* Apple ID (their primary is MMLT's Account Holder; account `744245396565` = `kingsrook_root_admin` profile) + D-U-N-S + $99. Then: -- Sparkle EdDSA keypair (I generate, owner stores private key as CI secret) -- GitHub secrets in a `production` environment; `gh label create sync conflict chokepoint-refresh`; external cron for `upstream_sync.yml` -- `DOMAIN`/appcast host → **kof22.com is ready** (see DNS below); replace `fork.invalid` in `local.xcconfig` -- **Real icon artwork** (replace placeholder) -- Push `depaywall-free` + open PR (runs `guard.yml`, no secrets) → merge → signed/notarized release - -## DNS/mail (DONE this session — infra, not the fork repo) -Plan at `/Users/james.maes/Git.Local/kof22/DNS-MAIL-PLAN.md` (outside repo). Both `kof22.com` and `koftwentytwo.com` migrated to benchfinity-style vanity NS (`ns1/ns2.` glued to `.146`) on the **Synology DNS Server**; `realm.direct` retired for these two. `koftwentytwo.com`: web→`50.122.5.146` (=kof22), MX→`mail.kof22.com` (per-domain mail; each IP runs Postfix/Dovecot), added as MailPlus additional domain on `.146`. Outbound relays via **SocketLabs** (`include:email-od.com`, DKIM CNAME→`dkim._domainkey.email-od.com`). Registrar = AWS acct `744245396565` (`AWS_PROFILE=kingsrook_root_admin`; `--profile` flag breaks the wrapper — use the env var). Inbound mail test was never confirmed (couldn't send from this VPN-blocked machine). - -## Key docs -`docs/AUDIT.md` (master audit) · `docs/GRAPHS.md` (mermaid) · `docs/PLAN-maintained-fork.md` (the strategy — thin patch + merge tracking + CI) · `docs/PLAN-republish-free.md` (one-shot excision, superseded) · `docs/EXECUTION-STATUS.md` (publish checklist) · `docs/audit/01–09-*.md` (deep dives). +## ⏳ NEXT (owner-gated — `docs/EXECUTION-STATUS.md` §3) +- **Apple Developer ID** (long pole): set `CODE_SIGN_IDENTITY` in `config/local.xcconfig`, re-sign Sparkle helpers, notarize → re-release signed/notarized, then drop the cask's quarantine postflight. +- **Real DOMAIN/appcast** (kof22.com ready): replace `fork.invalid` in `local.xcconfig`, serve `/appcast.xml`, flip `SUEnableAutomaticChecks` back on. +- **Wire CI:** `update_appcast.sh` uses the deprecated `sign_update -s` — switch to `--ed-key-file` (or `--account commandtabfree`) for the new key; create `sync`/`conflict`/`chokepoint-refresh` labels; external cron for `upstream_sync.yml`. +- **Real icon artwork** (replace placeholder). ## Gotchas -- Don't merge to master / don't `git revert 9147a4a8` (mixes paywall with a 1869-file reorg). -- `aws`: use `AWS_PROFILE=kingsrook_root_admin aws …` (the `--profile` flag fails on the local wrapper); SSO token expires (`aws sso login`). -- Bundle id is FROZEN (keychain/UserDefaults suite derives from it). +- Bundle id FROZEN (`com.koftwentytwo.commandtabfree`); keychain/UserDefaults suites derive from it. +- Don't `git revert 9147a4a8` (mixes paywall with a 1869-file reorg). +- Fork version line starts at **v100.0.0** (avoids collision with upstream tags merged into `master`). +- `aws`: use `AWS_PROFILE=kingsrook_root_admin aws …` (the `--profile` flag fails on the local wrapper).