diff --git a/CHANGELOG.md b/CHANGELOG.md index 41a7d1924b..79cda98583 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,18 @@ > completion state and remaining P0 gates. No version bump or release claim is > made here while that status holds. +## [1.64.20.0] - 2026-07-24 + +**Shipping from Windows: honest about the Mac, smart about the workaround.** + +You cannot build an iOS app without Xcode, and Xcode only exists on macOS — that wall is Apple's. What the release can do from any machine: sign in, mint the upload credential, write metadata, upload screenshots, set pricing, and submit. So the contract now names the split instead of failing vaguely: on a non-Mac host, the build and upload legs route through a free GitHub Actions macOS runner using your minted key as a CI secret, and everything else stays local. No more "impossible on Windows," and no pretending the build works there either. + +### Itemized changes + +### Changed + +- `skills/ship/references/APPLE-RELEASE.md`: non-macOS hosts get the honest Mac-required split — build legs (archive, sign, upload) route through a macOS CI runner with the minted key as a secret; API legs stay local. + ## [1.64.19.0] - 2026-07-24 **Free or paid is your call, asked once, inside the question you already answer.** diff --git a/VERSION b/VERSION index 0431861069..133112d22c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.64.19.0 +1.64.20.0 diff --git a/package.json b/package.json index 881b816356..034b9a0e6c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.64.19.0", + "version": "1.64.20.0", "description": "GStack 2 \u2014 six portable Agent Skills with an optional host-neutral runtime.", "license": "MIT", "type": "module", diff --git a/scripts/gstack2/generate-skill-tree.ts b/scripts/gstack2/generate-skill-tree.ts index f12ce720e8..e492bc87fa 100644 --- a/scripts/gstack2/generate-skill-tree.ts +++ b/scripts/gstack2/generate-skill-tree.ts @@ -643,6 +643,8 @@ Applies when the ship target is an Apple platform app: the repository contains a One tool runs the entire release: machine-level fastlane — \`produce\` (app record and bundle ID), \`cert\` and \`sigh\` (signing), \`gym\` (archive and signed export), \`pilot\` (TestFlight), \`deliver\` (metadata, screenshots, Submit for Review), \`frameit\` (device frames). Install it when missing (\`brew install fastlane\`) with a one-line announcement, not a question — the release authorization covers machine-tool installs. Never install additional App Store CLI tools, and never mention API keys, \`.p8\` files, sessions, or any credential format to the user; they paid US$99 and want to ship, and the release itself adds no new dependency to the user's project. +A Mac is required only for the build legs. Archiving, signing, and the binary upload ride Xcode's macOS-only toolchain — Apple ships it nowhere else, and no tool routes around that. On a non-macOS host, say so plainly, then route exactly those legs through a macOS CI runner (a GitHub Actions \`macos\` runner executing the same \`gym\` and \`deliver\`/\`pilot\` commands, with the minted upload key supplied as a CI secret — key auth is precisely what CI wants); sign-in, key minting, metadata, screenshots, pricing, and submission judgment are plain API work that stays on the user's machine. Never claim the whole release is impossible off a Mac, and never pretend the build leg is possible there. + ## The one authorization moment The whole journey permits exactly two interactions, and no others. FIRST, up front: confirm the user holds a paid Apple Developer Program membership (US$99/year — the App Store and TestFlight both require it) and authorize the release. Pricing belongs to this same breath, once per app EVER: ask free or paid (and the price if paid) inside the authorization question — never as a separate interruption — after checking the decision store (\`bin/gstack-decision-search --scope repo --query "pricing"\`); persist the answer (\`bin/gstack-decision-log\`, scope \`repo\`) so no later release re-asks, and a paid answer names the one-time Paid Apps banking/tax agreement honestly right there, since nothing sells until it is signed. Price is a launch decision the agent never defaults silently: a free launch cannot be un-launched. Apple sign-in happens inside this same moment: run \`fastlane spaceauth -u \` through the host's interactive command path (in Claude Code, the user types \`! fastlane spaceauth -u \` so their password and one two-factor code go directly to Apple in-session; a separate terminal window is the fallback only when the host has no interactive path). Keep the printed session token out of the transcript — the cached cookie in \`~/.fastlane/spaceship/\` is the credential fastlane actually uses; never store, echo, or log the password or token, and re-run the same one command when the session expires. Immediately after the first sign-in, mint the permanent upload key from the session (step 4 of Archive and upload) — when that key already sits at \`~/.gstack/apple/api-key.json\` and no new app record is needed, skip the sign-in entirely: repeat releases authorize and proceed with zero sign-in. SECOND, only when preflight finds the icon or screenshots missing: the store-assets question below. Everything else — tool installs, upload, storefront, submission — is covered by the authorization and proceeds without asking. Auth menus, tool-choice questions, plan confirmations, and step-by-step narration requests are contract violations. diff --git a/skills/ship/references/APPLE-RELEASE.md b/skills/ship/references/APPLE-RELEASE.md index 74c7dece7a..9c9d037978 100644 --- a/skills/ship/references/APPLE-RELEASE.md +++ b/skills/ship/references/APPLE-RELEASE.md @@ -5,6 +5,8 @@ Applies when the ship target is an Apple platform app: the repository contains a One tool runs the entire release: machine-level fastlane — `produce` (app record and bundle ID), `cert` and `sigh` (signing), `gym` (archive and signed export), `pilot` (TestFlight), `deliver` (metadata, screenshots, Submit for Review), `frameit` (device frames). Install it when missing (`brew install fastlane`) with a one-line announcement, not a question — the release authorization covers machine-tool installs. Never install additional App Store CLI tools, and never mention API keys, `.p8` files, sessions, or any credential format to the user; they paid US$99 and want to ship, and the release itself adds no new dependency to the user's project. +A Mac is required only for the build legs. Archiving, signing, and the binary upload ride Xcode's macOS-only toolchain — Apple ships it nowhere else, and no tool routes around that. On a non-macOS host, say so plainly, then route exactly those legs through a macOS CI runner (a GitHub Actions `macos` runner executing the same `gym` and `deliver`/`pilot` commands, with the minted upload key supplied as a CI secret — key auth is precisely what CI wants); sign-in, key minting, metadata, screenshots, pricing, and submission judgment are plain API work that stays on the user's machine. Never claim the whole release is impossible off a Mac, and never pretend the build leg is possible there. + ## The one authorization moment The whole journey permits exactly two interactions, and no others. FIRST, up front: confirm the user holds a paid Apple Developer Program membership (US$99/year — the App Store and TestFlight both require it) and authorize the release. Pricing belongs to this same breath, once per app EVER: ask free or paid (and the price if paid) inside the authorization question — never as a separate interruption — after checking the decision store (`bin/gstack-decision-search --scope repo --query "pricing"`); persist the answer (`bin/gstack-decision-log`, scope `repo`) so no later release re-asks, and a paid answer names the one-time Paid Apps banking/tax agreement honestly right there, since nothing sells until it is signed. Price is a launch decision the agent never defaults silently: a free launch cannot be un-launched. Apple sign-in happens inside this same moment: run `fastlane spaceauth -u ` through the host's interactive command path (in Claude Code, the user types `! fastlane spaceauth -u ` so their password and one two-factor code go directly to Apple in-session; a separate terminal window is the fallback only when the host has no interactive path). Keep the printed session token out of the transcript — the cached cookie in `~/.fastlane/spaceship/` is the credential fastlane actually uses; never store, echo, or log the password or token, and re-run the same one command when the session expires. Immediately after the first sign-in, mint the permanent upload key from the session (step 4 of Archive and upload) — when that key already sits at `~/.gstack/apple/api-key.json` and no new app record is needed, skip the sign-in entirely: repeat releases authorize and proceed with zero sign-in. SECOND, only when preflight finds the icon or screenshots missing: the store-assets question below. Everything else — tool installs, upload, storefront, submission — is covered by the authorization and proceeds without asking. Auth menus, tool-choice questions, plan confirmations, and step-by-step narration requests are contract violations.