Skip to main content

release

Use when the user says "release", "cut a release", "ship a new version", "release new version", "do the desktop release", or "tag a release". Computes the next version, generates the changelog, pushes a `v*-macos` tag, and monitors the Codemagic CI build that produces and publishes the macOS desktop release. NEVER builds locally.

설치로 이동

소스 정보

저장소
mediar-ai/fazm
최근 소스 활동
2026년 5월 28일 16:37
감지된 SKILL.md 언어
영어
스타
335
포크
40

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
release
description
Use when the user says "release", "cut a release", "ship a new version", "release new version", "do the desktop release", or "tag a release". Computes the next version, generates the changelog, pushes a `v*-macos` tag, and monitors the Codemagic CI build that produces and publishes the macOS desktop release. NEVER builds locally.
allowed-tools
Bash, Read, Edit, Grep
# Fazm Desktop Release Skill (Codemagic-only) Cut a new Fazm Desktop release. **All builds run in Codemagic CI** triggered by a `v*-macos` git tag. There is no local build path. ## CRITICAL RULES 1. **NEVER build the .app locally for a release.** No `xcodebuild`, no `xcrun swift build`, no shell wrapper that produces release artifacts. The local build path (`release.sh`) was deleted on purpose 2026-05-02. It silently stripped overlay assets and shipped two broken versions (v2.7.0 and v2.7.1) without `browser-overlay-init.js` because it lacked the codemagic.yaml hard-check. Codemagic has stricter checks; use it. 2. **NEVER push the same `v*-macos` tag twice.** Each Codemagic build generates a fresh EdDSA signature for the Sparkle ZIP. Re-pushing the tag (or re-running the build) produces a new ZIP with a different signature while the OLD ZIP can still be cached on the appcast — Sparkle then refuses the update with "improperly signed" for every user. If you need to retry, **bump to the next patch version** (e.g. `v2.7.2+2007002-macos`). 3. **NEVER edit `codemagic.yaml` mid-release.** If a step fails, root-cause first; do not patch CI to silence it. Once you know the fix, land it on `main`, bump version, push a fresh tag. 4. **NEVER skip the changelog step.** Codemagic's "Prepare changelog" step commits the consolidated CHANGELOG.json back to `main`; if `unreleased` is empty, the GitHub release notes will be empty too. 5. **Do not promote to beta or stable without explicit user approval.** Each promotion (staging → beta → stable) is a separate user decision. 6. **NEVER add a write to `gs://fazm-prod-releases/desktop/latest.json` to `codemagic.yaml`.** That manifest is what new website signups read via the stub installer. The CI workflow is shared by all `-macos` tags, and every `-macos` tag registers as the **staging** channel in Firestore; if CI also writes the global manifest, every staging build silently ships to every new signup, bypassing the entire promotion gate. The ONLY writer is `scripts/promote_release.sh`, fired on explicit promotion to beta or stable. This regression has been introduced twice already (`404836cc` 2026-03-20, undoing `e7741d9f` 2026-03-19) and bled 35 staging builds (2.9.13 through 2.9.47) to ~250 new users between March and May 2026. `verify-release.sh` step 2 now hard-fails on it. If a CI step seems to "need" to update the global manifest, you are misreading the channel model; read `Desktop/Sources/UpdaterViewModel.swift:269` and `scripts/promote_release.sh:120-135` before touching anything. ## How a release works (architecture) ``` git tag v$VERSION+$BUILD-macos → git push origin <tag> → Codemagic triggers ↓ build · sign · notarize · staple · DMG · Sparkle ZIP ↓ gh release create + Firestore register ↓ appcast.xml deploy → users update ``` - **Codemagic project**: `fazm-desktop-release` (workflow defined in `codemagic.yaml`) - **App ID**: `69a8b2c779d9075efc609b8d` - **API token**: `$CODEMAGIC_API_TOKEN` (set in `~/.zshrc`) - **Triggering tag patterns**: `v*-macos` (production) and `v*-macos-staging` (pre-release) - **Final artifacts**: `Fazm.zip` (Sparkle auto-update), `Fazm.dmg` (manual install), arch-specific zips on GCS, stub installer DMG The full pipeline (in order, defined in `codemagic.yaml`): 1. Extract version + build number from tag 2. Set up keychain + Developer ID 3. Build acp-bridge (TypeScript → JS, runs `npm install` which triggers `patch-playwright-overlay.cjs` postinstall) 4. Prepare universal ffmpeg / Node / cloudflared (arm64 + x86_64) 5. Resolve SPM packages 6. Build mcp-server-macos-use, whatsapp-mcp (both arm64 + x86_64) 7. Clone Google Workspace MCP 8. Build Swift app (universal binary) 9. Create universal app bundle — **includes the overlay file copy AND the `_fazmOverlayScript` hard-check** 10. Sign app (Developer ID, all native binaries in node_modules) 11. Notarize, staple 12. Create arch-specific zips for stub installer 13. Upload dSYMs to Sentry 14. Create + sign + notarize + staple DMG 15. Create Sparkle ZIP + EdDSA sign 16. Prepare changelog (consolidates `unreleased` → versioned, commits back to main) 17. Create GitHub release (uploads `Fazm.zip` and `Fazm.dmg`) 18. Register release in Firestore (channel = `staging` initially) 19. Deploy appcast.xml 20. Upload arch-specific zips to GCS 21. Build + upload stub installer ## Pre-release checklist (run locally BEFORE pushing the tag) ```bash # 1) Verify settings search coverage xcrun swift scripts/check_settings_search.swift # 2) Verify changelog has unreleased entries python3 -c " import json data = json.load(open('CHANGELOG.json')) entries = data.get('unreleased', []) if not entries: print('FATAL: unreleased is empty — add entries before tagging'); exit(1) print('\n'.join(entries)) " # 3) Working tree must be clean and on main git status --porcelain # must be empty git rev-parse --abbrev-ref HEAD # must be 'main' # 4) Sanity-check the bridge builds locally (catches TS errors before CI) cd acp-bridge && PATH=/opt/homebrew/bin:$PATH npm install --no-audit --no-fund && npm run build && cd .. # 5) Verify the playwright overlay patch still applies cleanly grep -q "_fazmOverlayScript" acp-bridge/node_modules/playwright-core/lib/coreBundle.js \ || { echo "FATAL: overlay patch did not apply locally — Codemagic will fail too"; exit 1; } # 6) Staging-gate invariant: codemagic.yaml MUST NOT write the global # desktop/latest.json. That file is owned by scripts/promote_release.sh. # Strips comments (lines starting with whitespace + '#') before searching # so the DO-NOT-REVERT banner in codemagic.yaml does not trigger this guard. if grep -vE '^\s*#' codemagic.yaml | grep -qE 'gs://[^"]*desktop/latest\.json'; then echo "FATAL: codemagic.yaml has a write to gs://.../desktop/latest.json outside scripts/promote_release.sh." echo " This is the exact March 2026 regression (commit 404836cc)." echo " Read CRITICAL RULE #6 in this skill before continuing." exit 1 fi ``` If any check fails, **fix it on `main` first**. Tagging a broken commit wastes ~20 min of CI time. ## Cutting the release ### Step 1: Compute next version Versions are `MAJOR.MINOR.PATCH+BUILD`. Build number is monotonically increasing; the convention has been `MMmmppp + 2000000` (e.g. v2.7.1 → build `2007001`). ```bash LAST_TAG=$(git tag -l 'v*-macos' | grep -v staging | sort -V | tail -1) echo "Last release tag: $LAST_TAG" # Auto patch bump: 2.7.1 → 2.7.2, 2007001 → 2007002 → tag v2.7.2+2007002-macos # For minor/major bumps, ask the user. ``` ### Step 2: Push the tag ```bash TAG="v${VERSION}+${BUILD}-macos" git tag "$TAG" git push origin "$TAG" ``` That single push triggers Codemagic. Do **not** push to `main` separately for the release; Codemagic itself commits the consolidated changelog back during the build. ### Step 3: Monitor the build ```bash TOKEN=$CODEMAGIC_API_TOKEN APP_ID=69a8b2c779d9075efc609b8d TAG="v${VERSION}+${BUILD}-macos" # Wait briefly for Codemagic to register the tag, then locate the build sleep 30 BUILD_ID=$(curl -s -H "x-auth-token: $TOKEN" \ "https://api.codemagic.io/builds?appId=$APP_ID&limit=10" | \ python3 -c " import json, sys for b in json.load(sys.stdin).get('builds', []): if b.get('tag') == '$TAG': print(b['_id']); break ") echo "Build: $BUILD_ID" # Poll status (build takes ~20-30 min) while true; do STATUS=$(curl -s -H "x-auth-token: $TOKEN" \ "https://api.codemagic.io/builds/$BUILD_ID" | \ python3 -c "import json, sys; print(json.load(sys.stdin)['build']['status'])") echo "$(date +%T) status=$STATUS" case "$STATUS" in finished) echo "✓ Build succeeded"; break ;; failed|canceled) echo "✗ Build $STATUS — fetch logs via the codemagic skill"; break ;; esac sleep 30 done ``` If a step fails, fetch the per-step log via the `codemagic` skill and root-cause it. **Do not retry the same tag**; bump to the next patch version after the fix lands. ### Step 4: Verify the release ```bash ./verify-release.sh "$VERSION" ``` This script automatically: - Checks the appcast serves the correct version - Downloads `Fazm.zip` (what auto-updaters get) and verifies signature, notarization, Gatekeeper acceptance - Launches the app and confirms it starts - Checks the DMG download endpoint If verification fails, **immediately roll back** with the `rollback` skill (`.claude/skills/rollback/SKILL.md`) — do **not** try to "fix the live release" by pushing another tag. ### Step 5: Smoke-test on staging A fresh release lands on the `staging` channel. Run `/test-release` on the **remote MacStadium machine** (staging channel only). See `.claude/skills/test-release/SKILL.md`. Report results. **Wait for explicit user approval** before promoting. ### Step 6: Promote (only when user explicitly says so) ```bash ./scripts/promote_release.sh "$TAG" # staging → beta # After user approves again: ./scripts/promote_release.sh "$TAG" --stable # beta → stable ``` Each promotion is a separate user decision. Re-test on the appropriate machine after each. ## Failure handling ### Codemagic step fails 1. Identify the failing step from the build log (use the `codemagic` skill) 2. Land the fix on `main` 3. Bump to the next patch version (do **not** re-push the same tag) 4. Push the new tag ### Notarization fails (unsigned binary) - Check the notarytool log for the unsigned path - Add a `codesign --force --options runtime --timestamp $CS_PAGESIZE --sign "$SIGN_IDENTITY" "$path"` line to the "Sign app" step in `codemagic.yaml` - Land it, bump version, retag ### Stapling fails (Apple CDN propagation) - Common transient. Bump to the next patch version and retry. The build is fast on cache hit; notarization is usually quick the second time. ### Hard-check fails (`overlay asset … missing` or `coreBundle.js NOT patched`) - The patch script `acp-bridge/scripts/patch-playwright-overlay.cjs` did not match the current Playwright MCP shape (see commit `4584c94f` for the most recent successful update) - Fix the OLD_BLOCK / NEW_BLOCK in the patch script to match the new shape - Land the fix, bump version, retag - Do **not** set `FAZM_ALLOW_MISSING_OVERLAY=1` in CI just to ship — that ships a broken indicator ### "Improperly signed" reported by users after release - Means the same tag was built twice with different EdDSA signatures, or the Sparkle ZIP on GitHub does not match the signature in the appcast - **Do not retag.** Bump to the next patch version and push a fresh release. The new appcast entry will carry the new ZIP and matching signature. ## After a release ships - Append a changelog entry to `unreleased` in `CHANGELOG.json` for any subsequent user-visible change. The next release rolls those into its versioned entry automatically. - Use `./scripts/sentry-release.sh` to monitor crash health on the new version (see the `sentry-release` skill). ## What was deleted and why - **`release.sh`** (root) — local build pipeline. Deleted 2026-05-02. It had no overlay-asset copy step and no hard check, so it shipped v2.7.0 and v2.7.1 missing `browser-overlay-init.js`, silently breaking the "Browser controlled by Fazm" indicator. Codemagic has full feature parity (and stricter checks). Local builds are forbidden for release artifacts; use `./run.sh` only for dev iteration on `Fazm Dev.app`. - **`Bash(./release.sh:*)`** in `.claude/settings.local.json` — removed at the same time so agents can't accidentally invoke a path that no longer exists. ## Key files - **CI workflow**: `codemagic.yaml` - **Verification**: `verify-release.sh` - **Promotion**: `scripts/promote_release.sh` - **Changelog**: `CHANGELOG.json` - **Overlay patch**: `acp-bridge/scripts/patch-playwright-overlay.cjs` (postinstall, must match current `@playwright/mcp` shape) - **Rollback skill**: `.claude/skills/rollback/SKILL.md` - **Codemagic skill**: `.claude/skills/codemagic/SKILL.md` - **Test skill**: `.claude/skills/test-release/SKILL.md`
GitHub에서 보기