Lilita One lacks most of Latin Extended-A (Turkish s-cedilla, g-breve, dotted I ...), so Turkish titles were drawn with a silent browser fallback while shots check passed. shots fonts now reads the cmap of every face (pure TS, TTF/OTF/WOFF/WOFF2), adds a Noto fallback per missing character or fails with language + characters; render measures which face drew each character (CDP probes) and records it in report.json; check errors on fallbacks the config did not choose (shots.fonts.fallback) and on system-font glyphs. Default game title font: Paytone One.
531 lines
51 KiB
Markdown
531 lines
51 KiB
Markdown
# Changelog
|
|
|
|
## Unreleased
|
|
|
|
- Screenshot glyphs (a Turkish render showed fallback glyphs for "ş" / "ğ" while `shots check` passed): the cause was
|
|
not subsetting (css2 `text=` already takes glyphs from every subset) but the title font: Lilita One has no ş ğ İ and
|
|
most of Latin Extended-A, so Chrome silently drew them with another font.
|
|
- `shots fonts` checks every character of every language (copy.json + config languages) against the cmap of the
|
|
faces that draw it (new pure-TS cmap reader for TTF / OTF / TTC / WOFF / WOFF2, no dependency), adds an automatic
|
|
Noto fallback per missing character (Noto Sans Display for titles at a heavy weight, Noto Sans, Noto Sans
|
|
<Script>, Symbols) and logs it; a character no fallback covers fails with the language and the characters. Writes
|
|
`.storebound/fonts/fonts.json` (faces and per-language stacks).
|
|
- `shots render` refuses fonts that no longer cover the copy, uses the per-language stacks, and measures in the page
|
|
(CDP platform fonts of one probe per face and character) which face drew every character; `report.json` keeps it
|
|
per image (`fonts`). `shots check` (and `validate`, `shots gallery`) raise an ERROR for glyphs drawn by a fallback
|
|
the config did not choose or by a system font, and warn for renders without font data.
|
|
- New `shots.fonts.fallback: ['Noto Sans Display']` to accept a fallback. Default game title font is now Paytone One
|
|
(covers Latin Extended and Vietnamese) in the template, the demo and the built-in default; README and the
|
|
store-screenshots skill document the default stack per script.
|
|
- Fixes from a live monorepo game (username accounts, Capacitor in `apps/native`):
|
|
- `scan` no longer turns accounts into "Email Address" / `PSL_EMAIL`: accounts mean User ID; email is "detected"
|
|
only with real evidence (an email field or keyboard, an `email` property in a body / schema / type, an email
|
|
validation or endpoint, an email sign-in call, an SDK that collects it, or `accounts.signUp`), otherwise a question.
|
|
- New `accounts.signUp` (`username`, `username-password`, `email-password`, `email-link`, `phone`, `oauth`, `other`):
|
|
`scan` proposes the account data and `dataSafety.accountCreation` from it (`scan --write` writes it); a username
|
|
with no password is Play's "Username and other authentication" (`PSL_ACM_USER_ID_OTHER_AUTH`).
|
|
- Built output (bundles, dist / build, the Capacitor webDir, minified files) is low-trust evidence: `scan` prefers
|
|
the own sources and `*.test.*` / `*.spec.*` files are no longer app sources.
|
|
- `privacy-manifest --ios` finds Capacitor / Cordova / React Native plugins without `--sdk-dirs`: node_modules next to
|
|
the app's package.json and above it, workspace packages, local SwiftPM packages (CapApp-SPM), nested Pods.
|
|
- `scan` reads the native dependencies behind each npm plugin (its podspec, Package.swift, android/build.gradle), so an
|
|
ad SDK wrapped in a Capacitor plugin (Unity LevelPlay) is detected; LevelPlay's Swift package is matched too.
|
|
- `storebound flow list | validate | run <name>`: repo-local workflows in `store/workflows/*.yml` (or
|
|
`storebound.workflows.yml|json|ts`): named steps run in order with progress, `${VAR}` params and captures, `if:`
|
|
conditions, sub-flows, before / after / onError hooks. Writes run as dry runs unless `--apply`; owner steps (submit,
|
|
release, rollout ...) are listed as "your click" and never run; `--from <step>` and `--resume` continue after a
|
|
failure. `init` writes `release.yml` and `beta.yml` for the app and game profiles. A small YAML subset reader keeps
|
|
zero runtime dependencies. MCP: `flow_list`, `flow_run` (dry mode). Skill: `release-flows`.
|
|
- `storebound listing translate --to <langs>`: per-language listing drafts in both listing files (App Store name,
|
|
subtitle, promotional text, keywords, description; Play title, short, full) for the agent to translate, or a
|
|
`--translate "<command>"` hook per field; store limits and keyword rules (commas, duplicates, name words, 100) are
|
|
enforced, drafts stay marked until `listing reviewed`; `listing check`, and `check` warns about drafts. No LLM call
|
|
in the CLI. MCP: `listing_translate`, `listing_check`. Skill: `listing-localization`.
|
|
- `scan`: Apple 2.2 "beta / demo / trial / test" wording in the app name and the App Store text (`beta-wording`);
|
|
`scan --originality [--against <folders>]` puts the 4.3 / Play repetitive content check into the scan report.
|
|
- `prices export` includes auto-renewable subscriptions (Apple current and scheduled prices, Play base plan regional
|
|
prices; `--no-subscriptions` leaves them out); `prices import` skips those rows and names the subscription commands.
|
|
- Site: "Catch rejections before you submit", a Desktop app section with real fixture-mode screenshots, an "Everything
|
|
else" command grid and the FAQ on `storebound originality`.
|
|
- Fixes from a read-only run of every read path on live App Store Connect and Google Play accounts:
|
|
- `apple signing status | ensure` no longer fails on an Xcode-managed profile (listed under the bundle id, 404 on
|
|
`/v1/profiles/{id}`); with automatic signing it shows as "Xcode-managed".
|
|
- `release status | plan` and `ws status` show a version that is only in TestFlight as a train at "testing" (the
|
|
plan says to create the App Store version with that build), and the build number of an older attached build.
|
|
- `scan` skips `.claude` (agent worktrees) and other linked git worktrees, takes an absolute `--config`, and no
|
|
longer reads "rate-limits ... rewardedBreak()" as a reward for rating.
|
|
- `api --all-pages` drops the first page's `nextCursor` / `limit` from the merged result; `apple iap-submit --json`
|
|
lists no requests when nothing is left to submit; `reports apple-sales | apple-finance` explain a wrong vendor
|
|
number.
|
|
|
|
## 0.6.0 · 2026-10-12
|
|
|
|
- Growth extras, each with `--dry`, `--json`, tests on sanitized fixtures and a skill:
|
|
- `prices ppp`: purchasing power price sheets from a bundled, dated World Bank ICP PPP dataset (CC BY 4.0,
|
|
`tools/update-ppp.ts` refreshes it), the Big Mac index or a CSV; clamped, snapped to store price points, written
|
|
in the `prices import` format with a diff.
|
|
- `ads apple status | campaigns | report`: Apple Ads reports (spend, taps, installs, CPA per campaign / keyword,
|
|
CSV export); `bid | budget | pause` are dry first and ask in a terminal, never over MCP.
|
|
- `web init | check`: apple-app-site-association, assetlinks.json (Play app signing SHA-256, also read from the
|
|
Play API with `--version-code`), the Smart App Banner tag and a minimal landing page; `web check` verifies the
|
|
live files (content type, no redirects, JSON, ids match).
|
|
- `apple adhoc devices | register | profile | options | export` (release-testing / ad-hoc ExportOptions.plist,
|
|
devices with masked UDIDs, registration asks first) and `play share` (internal app sharing upload, prints the link).
|
|
- `revenuecat diff | sync`: optional RevenueCat REST API v2 adapter for products, entitlements and the default
|
|
offering; sync only creates and attaches, asks first, never over MCP.
|
|
- `console fill <form>`: AI-assisted Playwright autofill for the App Store app record, age rating, App Privacy and
|
|
the Play content rating and target audience forms. A visible Chromium with a profile the owner signs in to; it
|
|
never types passwords and never clicks Save / Submit / Publish / Next; UI changes fall back to guidance. Desktop:
|
|
"Fill in console" on the App info tab (dry run, native confirm, then the browser). Never over MCP.
|
|
- New config: `prices.ppp`, `web`, `apple.teamId`, `apple.adhoc`, `revenuecat`, `console`. New MCP tools (safe
|
|
parts only): `prices_ppp`, `web_init`, `web_check`, `apple_adhoc_devices`, `apple_adhoc_options`,
|
|
`ads_apple_status`, `ads_apple_campaigns`, `ads_apple_report`, `revenuecat_diff`.
|
|
- `apple appinfo` answers the new `socialMedia` / `socialMediaAgeRestricted` age rating questions with false
|
|
unless `apple.info.ageRating` says otherwise.
|
|
|
|
- `storebound scan` on Google Play now matches the App Store side: rejections, blocked updates, suspensions and
|
|
policy strikes that the project files can prove, each verified against the live Play Policy Center / Play Console
|
|
Help page (cited with the date in `cli/lib/scan/play-rules.ts`). New rules: the restricted permissions and their
|
|
Console declarations (background location, READ_MEDIA_IMAGES / READ_MEDIA_VIDEO, MANAGE_EXTERNAL_STORAGE,
|
|
AccessibilityService with or without isAccessibilityTool, REQUEST_INSTALL_PACKAGES, Health Connect,
|
|
USE_FULL_SCREEN_INTENT, VpnService), prominent disclosure and the in-app privacy policy (User Data), Data safety
|
|
answers narrower than the SDKs' disclosures, Families (`play.targetAges`: ad SDKs not on Google's self-certified list
|
|
or older than their certified version, AD_ID and location in child-only apps, mixed audiences), the AD_ID permission
|
|
on targetSdk 33+, 16 KB page sizes (Unity before 6000.0.38f1 / 2022.3.56f1 / 2021.3.48f1, React Native before 0.77,
|
|
NDK before r28 without the flags, AGP before 8.5.1 with uncompressed libraries, prebuilt .so files; updates blocked
|
|
from 2027-02-01), the closed-testing requirement of new personal accounts (`play.accountType`,
|
|
`play.accountCreated`: 12 testers for 14 days), Play metadata (title over 30 characters, emoji, ALL CAPS, rank /
|
|
price / promotion terms, other apps, repeated keywords and keyword lists), interstitials shown from the launcher
|
|
activity's onCreate, card / PayPal SDKs or "buy on our website" next to in-app products (`play.billingPrograms`),
|
|
and brand names in the package or app name (low). Detection reads activities, services and receivers with their
|
|
intent filters, accessibility-service configs, strings.xml, the NDK / AGP versions, CMake / ndk-build files,
|
|
extractNativeLibs, useLegacyPackaging, Unity ProjectVersion.txt, .so files, and the merged manifest under
|
|
build/intermediates when the project was built locally. Device admin has no Play policy page and gets no rule. The
|
|
App Store rules are unchanged. New fixtures (play-android, play-native, play-families, play-listing) and Android parts
|
|
in the clean fixture; the README rule table has a column per store.
|
|
- `storebound scan` (MCP tool `scan`, desktop Checks tab): an offline, read-only scan of the project itself for App
|
|
Store and Google Play rejection risks before you submit. Detects the stack (native iOS / Android, React Native,
|
|
Expo, Capacitor, Cordova, Flutter, Unity, Godot) and the SDKs from a maintained table (`cli/lib/scan/sdks.ts`: ads,
|
|
analytics, attribution, crash, sign-in, payments, push, with versions, file:line and each vendor's data disclosure
|
|
page) and reports each risk with the guideline, evidence, fix, severity and skill: 2.1(a) demo account and
|
|
placeholder text, 5.1.1(v) account deletion, 4.8 login services, 3.1.1 Restore Purchases and outside payments,
|
|
3.1.2(c) subscription information, 5.1.2(i) App Tracking Transparency, 5.1.1(ii) / (iv) purpose strings, 5.1.1(i)
|
|
privacy link, privacy manifests (ITMS-91053 / 91061), 2.3.10 other platforms, 2.3.7 keywords, 2.3.8 "For Kids", 4.2
|
|
web wrappers, 2.5.1 UIWebView and private URL schemes, 2.5.5 IPv6, ATS, export compliance, 1.3 kids ads, 5.6.1 /
|
|
3.2.2(x) review prompts, privacy labels vs SDKs, and on Play the API 36 target SDK requirement (since 2026-08-31),
|
|
the delete-account URL, App access, foreground service types, exact alarms, QUERY_ALL_PACKAGES, SMS / call log and
|
|
the reserved com.example package name. It also proposes the Data safety / App Privacy / ATT / privacy manifest
|
|
answers, each "detected (file:line)" or "ask owner", as a diff against the config; `--write` adds only the detected
|
|
answers (new `appPrivacy` block for tracking). `scan.ignore` records findings the owner accepts, with the reason.
|
|
`validate` includes the open findings (`--no-scan` skips), `check` now asks for unanswered dataSafety booleans.
|
|
Fixtures for iOS, Android, Capacitor, Unity, Flutter, a clean project and the teaser under `tests/fixtures/scan/`.
|
|
- CLI workspace for many apps and studios (until now only in the desktop app): `storebound.workspace.json` (or `.ts`)
|
|
in a folder above the app folders names the app folders (globs), studios with their store accounts by credential
|
|
profile (never a key), an ignore list and the desktop's pairing overrides. Commands: `ws init`, `ws list`,
|
|
`ws status` (apps x stores, read in parallel with a concurrency limit), `ws check`, `ws validate`,
|
|
`ws run <command> --apps a,b|--all` (read commands; writes as dry runs unless `--apply`; submit, release, rollout,
|
|
send, start / stop never), `ws apps import --account <profile>` (store apps paired with the folders by the desktop's
|
|
rules) and `ws desktop export | import` (the same model as the desktop's `state.json`; keys stay in the keychain or
|
|
the profiles). MCP: `workspace_list`, `workspace_status` (read-only).
|
|
- Credential profiles: `~/.storebound/credentials/<profile>.json` (or env `STOREBOUND_PROFILE_<NAME>_<KEY>`), picked
|
|
with `--account <profile>` on any command or by the workspace, so many store accounts work from one terminal.
|
|
- Release trains in the CLI: `release status` (both stores on one train per version: build > testing > review > live
|
|
> rollout %) and `release plan <version>` (what is left on each store in fix order, from check, validate and the
|
|
store state; owner steps named, never done), as tables or `--json`. MCP: `release_status`, `release_plan`.
|
|
- Shared code instead of copies: the pairing rules (`cli/lib/identity.ts`) and the release lanes (`cli/lib/train.ts`)
|
|
moved out of the desktop's webview into `cli/lib/`, and the per-app status read behind `portfolio.status`
|
|
(`cli/lib/app-status.ts`) is the one `ws status` and `release` use. The desktop re-exports them unchanged.
|
|
- Every endpoint: `storebound api` calls any operation of the App Store Connect API (1303 operations, OpenAPI 4.5.1)
|
|
and the Google Play Developer APIs (Android Publisher v3: 145 methods, Play Developer Reporting v1beta1: 25; v1alpha1
|
|
has no methods of its own), from the official specs pinned in `specs/` (URLs, dates, SHA-256 in
|
|
`specs/SOURCES.json`). `tools/gen-api.ts` turns them into one row per operation (`cli/api/apple.gen.ts`,
|
|
`cli/api/play.gen.ts`) plus generic helpers (`cli/api/client.ts`: URL and parameter building, retries on 429 / 5xx
|
|
with Retry-After, `--all-pages` over Apple's `links.next` and Google's page tokens), typed from the rows
|
|
(`cli/api/types.ts`: path and required parameters, loosely typed JSON:API requests and responses). About 44 KB more
|
|
in the npm tarball. Same credentials as every other command (`ascJwt` is now shared from `cli/apple/asc.ts`).
|
|
- `storebound api apple|play <operationId | METHOD path> [--param k=v ...] [--body file.json] [--upload file]
|
|
[--out file] [--all-pages] [--json] [--dry] [--yes]`: GETs (and the read-only Reporting `:query` POSTs) run;
|
|
every write prints the exact request and is only sent with `--yes` in an interactive terminal; owner-only
|
|
operations (`cli/api/gate.ts`: deletes, submissions, releases, phased release changes, product page tests, prices,
|
|
testers and users, review replies, Play `edits.commit`, activation, refunds, app signing) also need the operation
|
|
id typed. Under MCP or the desktop app no write is sent at all.
|
|
- `storebound api list [--store] [--search]` and `storebound api coverage`: every operation, counts per API and
|
|
resource, and which ones storebound's commands already call (a scan of `cli/`, `cli/api/wrapped.gen.ts`); the full
|
|
table is `docs/api-coverage.md`. CI fails when the tables, the scan or the doc are stale against `specs/`.
|
|
- MCP: one new read-only tool, `api_get` (GET operations only; not in the desktop profile). New skill `store-api`.
|
|
- Signing through the App Store Connect API: `apple signing status` (read-only; also an MCP tool) and
|
|
`apple signing ensure` (dry first, asks once). Bundle id capabilities from `apple.signing.capabilities` (added,
|
|
never removed), an Apple Distribution certificate when this machine holds no key for a valid one (RSA 2048 key
|
|
and CSR made in TypeScript, key kept 0600 in `.storebound/signing/`, never printed; `--keychain` imports key and
|
|
certificate), App Store profiles per bundle id (app + `apple.signing.extraBundleIds`) reused while active or
|
|
created, installed for Xcode 16+ (`~/Library/Developer/Xcode/UserData/Provisioning Profiles`) and older Xcode
|
|
(`~/Library/MobileDevice/Provisioning Profiles`). A 403 on a Developer ID certificate is explained (Account Holder
|
|
only), as are the certificate limit and a key without the Admin role.
|
|
- `apple build`: finds the workspace / project and scheme (native, Capacitor, React Native, Flutter with
|
|
`flutter build ios --config-only`, Unity-iPhone), takes the next free build number from App Store Connect,
|
|
writes ExportOptions.plist (`method` app-store-connect, `destination` export, team, signing style, profiles) and
|
|
runs xcodebuild archive and -exportArchive with the API key; full logs in `build/ios/`, the IPA checked at the end.
|
|
- `apple upload`: the IPA through the App Store Connect API build upload (Build Uploads, API 4.1: reserve, upload
|
|
parts, commit with the MD5, poll) or `--via altool` (`altool --upload-package` with the API key); the build number
|
|
is checked against App Store Connect first, then storebound waits until the build is VALID (exit 0), INVALID /
|
|
FAILED (1) or the timeout (7). Dry first, asks.
|
|
- `play build`: Gradle `bundleRelease` (Flutter: `flutter build appbundle`; Capacitor / React Native `android/`,
|
|
Unity exports with `launcher/`) with the next free versionCode and the upload key from `ANDROID_KEYSTORE*` (env or
|
|
`.storebound/credentials.json`), handed to Gradle as injected signing properties through the environment, never on
|
|
the command line. The versionCode is read back from the AAB's manifest. `play upload --track internal|alpha|beta`:
|
|
versionCode checked, `--dry` read-only, a real run asks; production stays `play release --production draft`.
|
|
- `originality --against <folders>` (also an MCP tool): offline Guideline 4.3 check against the owner's other apps:
|
|
name and listing text similarity, icon and screenshot perceptual hashes (dHash + pHash; PNG decoded in TypeScript,
|
|
JPEG / WebP through ffmpeg when installed), project structure (file layout, identical files), an overall score,
|
|
near-duplicate flags and suggestions; exit 1 when a pair is flagged. The portfolio-originality skill uses it.
|
|
- New skill `build-and-sign`; appstore-first-release and play-first-release use the new commands. Zero new
|
|
dependencies: plist (XML + binary), ZIP, aapt2 manifest and PNG readers are small TypeScript modules.
|
|
- Store operations. Every new command has `--dry` and `--json`; what customers can see, redeem or lose (submitting,
|
|
codes, offers, pre-orders, expiring builds, making a page visible) asks first in the terminal and is not an MCP
|
|
tool. API details come from the App Store Connect API 4.5.1 OpenAPI spec, Apple's and Google's reference pages and
|
|
App Store Connect Help (cited at the top of each `cli/lib/*.ts`); tests run the commands against recorded,
|
|
sanitized answers (`tests/store-ops-*.test.ts`, harness in `tests/helpers/store-mock.ts`).
|
|
- TestFlight: `apple testflight wait --build N` (polls until VALID / FAILED, progress lines, `--timeout`, exit 0 /
|
|
1 / 7) and `apple testflight expire --keep N | --older-than D` (newest, attached and processing builds stay;
|
|
`PATCH /v1/builds/{id}` `expired: true`). `apple upload` waits for processing with the same loop
|
|
(`waitForBuild` in `cli/apple/testflight.ts`) instead of a copy of its own.
|
|
- `apple iap-submit`: IAP, subscription and subscription group versions into a review submission
|
|
(`reviewSubmissionItems` with `inAppPurchaseVersion` / `subscriptionVersion` / `subscriptionGroupVersion`, API
|
|
4.4.1+; the deprecated `inAppPurchaseSubmissions` are not used). It applies Apple's rules: the first item of each
|
|
type only together with a new app version (`--with-version`), later ones alone once the app has an approved
|
|
version, a new subscription with its unapproved group, at most 200 items; `--no-submit` stops at the draft,
|
|
`--new-version` makes a new draft version of an approved or rejected product. MCP: the read-only plan
|
|
`apple_iap_review_plan`.
|
|
- Pulls: `apple listing pull`, `play listing pull` (live texts back into `store/*.md`, diff first, `--write` to
|
|
write) and `catalog pull` (IAP and subscription texts as a proposal diff; the config is never rewritten,
|
|
`--write` saves `.storebound/pull/catalog.json`).
|
|
- `whats-new --languages a,b,c`: one file per language in `store/whats-new/`, translated by your agent (skill) or a
|
|
`--translate "<command>"` hook of yours (no translation service or key in the CLI); `whats-new check` (Play 500,
|
|
App Store 4000, untranslated or identical to the source) and `whats-new apply`.
|
|
- Offers: `apple offer-codes` (offer codes for one-time purchases, `inAppPurchaseOfferCodes`; custom and one-time-use
|
|
codes only with `--codes`, saved to `.storebound/offer-codes/`), `apple win-back` (win-back offers,
|
|
`winBackOffers`), `apple promoted` (promoted purchases: create disabled, order, `--enable`), `apple preorder
|
|
status | enable | end` (territory availabilities, `endAppAvailabilityPreOrders`). Google Play pre-registration and
|
|
promo codes have no API: console guide in the new `app-store-promotion` skill.
|
|
- `apple cpp list | create | upload | submit | visible` (custom product pages, screenshots from a shots variant) and
|
|
`apple events list | create | upload | submit` (in-app events with schedule, localizations, card and details
|
|
images checked against Apple's sizes).
|
|
- `reports apple-sales | apple-finance | play-earnings | play-sales`: Apple `salesReports` / `financeReports`
|
|
(vendor number from `ASC_VENDOR_NUMBER` in env or `.storebound/credentials.json`) and the Play earnings / sales
|
|
zips from the reports bucket into `.storebound/reports/`, with a summary per product and currency and a CSV.
|
|
Zero dependencies: the same small ZIP reader (`cli/lib/zip.ts`, on `node:zlib`) that reads IPAs and AABs.
|
|
- `triage`: TestFlight crash reports (signature from each crash log, text and `.ips`), TestFlight screenshot feedback
|
|
and Play error reports of the top issues, grouped by signature with devices, OS versions and builds; tester emails
|
|
are never requested.
|
|
- `aso rank`: the app's rank per keyword and storefront in the public iTunes Search API results plus the first
|
|
competitors, one request every 3.5 s (Apple allows about 20 a minute), snapshots in `.storebound/aso/`. Subtitles
|
|
are not in any public API and are not shown.
|
|
- `ads scan --ios <path>`: AdAttributionKit / SKAdNetwork checks of Info.plist and sources (ad network ids and their
|
|
case, `AttributionCopyEndpoint`, re-engagement copies, `NSAdvertisingAttributionReportEndpoint`, attribution
|
|
windows and cooldown ranges, conversion value updates); the ads-mediation-checks skill explains each finding.
|
|
- New MCP tools (dry by default where they write local files): `apple_testflight_wait`, `apple_iap_review_plan`,
|
|
`apple_listing_pull`, `play_listing_pull`, `catalog_pull`, `whats_new_languages`, `whats_new_check`,
|
|
`whats_new_apply`, `reports`, `triage`, `aso_rank`, `ads_scan`, `apple_cpp_list | create | upload`,
|
|
`apple_events_list | create | upload`, `apple_preorder_status`.
|
|
|
|
- New logo: a glossy indigo box with an upward arrow (`brand/master/logo-mark.png`, `brand/README.md`). Every logo
|
|
file comes from it through `tools/brand-assets.py`: desktop app icons (PNG sizes, `.icns`, a `.ico` with its own
|
|
image per size, Windows tiles), the site's favicon.ico, maskable web app icons with a manifest, apple-touch-icon,
|
|
the header and footer marks (PNG next to the text wordmark), the desktop window's mark and `site/og.png`. Below
|
|
48 px a bold "s" monogram on the same tile. The old hand-written SVG mark and `site/favicon.svg` are gone, and the
|
|
no-hand-written-SVG guard no longer has a brand exception.
|
|
- Desktop: the signed release showed only its background colour and never started the sidecar. Cause: Tauri's
|
|
`freezePrototype` freezes `Object.prototype` before the bundle runs, and d3-color / d3-format (under the visx charts)
|
|
assign `constructor` / `toString` on plain objects while loading, which throws on a frozen prototype; the bundle
|
|
stopped before React drew anything. Saved state was not the cause. A Vite plugin (`apps/desktop/build/freeze-safe.ts`)
|
|
makes those assignments safe. So the window is never blank again: error boundaries for the whole window and each
|
|
screen and tab (Copy details, Reload, Reset saved state with a backup), `public/boot.js` for a bundle that fails to
|
|
load, `logs/host.log` and `logs/webview.log` in the app data folder (rotated, home as `~`, no keys or e-mail
|
|
addresses), a versioned `state.json` with an explicit migration from the D1-D3 format (original kept as
|
|
`state.json.v1.bak`; broken entries dropped one by one), "Folder not found" with Locate… / Remove for app folders
|
|
that are gone, and a boot check in CI and the macOS release (`tools/desktop-boot-check.ts`: the built window with the
|
|
release CSP and the frozen prototype on empty, D1 and D3 saved states).
|
|
|
|
- Icons: Phosphor replaces lucide (desktop: `@phosphor-icons/react` per-icon imports, "regular" weight, "fill" for the
|
|
active nav item and notices; site and fixture art: Phosphor's own files). Store marks are now the real App Store and
|
|
Google Play logos from simple-icons, in the neutral text colour next to the store's name; the trademark note is in
|
|
docs/desktop.md and the site footer. The no-hand-written-SVG guard allows only the vendored files, byte-equal to
|
|
their packages.
|
|
|
|
- Fixes from a guarded read-only run of the Play paths that need POST / DELETE (edit insert and delete, Reporting API
|
|
`:query`, nothing else let through) against a live account:
|
|
- `health` / `validate`: Play's top issues search (`errorIssues:search`) answered 400 "Unsupported timezone": it
|
|
takes only hour-aligned UTC intervals, unlike the metric timelines (America/Los_Angeles days). It now asks in UTC.
|
|
A failing issues search no longer throws away the crash and ANR rates already read (a `vitals-issues` warning and
|
|
"not read" in the table instead of "vitals not readable"), and Reporting API errors leave out the query string so
|
|
the reason is not cut off in tables.
|
|
- `play listing --dry` and `play images --dry` are read-only now: one throwaway edit, the current details,
|
|
listings and images (sha256 of each uploaded file) compared with the local copy, the edit deleted. Before, the
|
|
dry runs wrote into the edit (PUT details and listings; for images every image set cleared and uploaded) and
|
|
called `:validate` before discarding it. The output says per language what would change.
|
|
- `play products --dry` names what a run would change per product (listings added / changed / removed, regional
|
|
prices old -> new, dropped regions, activation) instead of "update · 174 regions" for every existing product.
|
|
- `play products` asks before changing what an existing product costs or where it is sold (regional prices, the
|
|
other-regions price, dropped regions, activating a purchase option), the same way `play subscriptions` does: the
|
|
diff, then a terminal confirmation (or `--yes`). Without one (MCP, CI, serve without a desktop owner-action token)
|
|
those changes are skipped with a warning; new products and listing text still go through. `apple iap` and
|
|
`apple appinfo` only create a price schedule or availability where none exists, so they need no gate; price
|
|
changes on both stores stay with `prices import` (confirmation, the desktop Prices "Apply" owner action).
|
|
- `play status`, `play next-version-code`: the read-only edit goes through one helper that always deletes it and
|
|
warns when the delete fails; `next-version-code` counts distinct version codes (one code on two tracks is one).
|
|
|
|
- Fixes from a second read-only run (GET only) of the desktop read paths against live accounts: `analytics snapshot`
|
|
no longer writes a snapshot when every store failed (no ONGOING report request yet, no `play.reportsBucket`); it
|
|
exits with both reasons, so the desktop dry run shows them. `analytics compare --json` adds `errors` (why a store has
|
|
no days), and the Growth tab shows that reason instead of zero totals and "one day of data". Listing completeness
|
|
no longer counts a contact sheet in the language folder as a screenshot. Price sheet round trip (export, then
|
|
compare) checked on recorded App Store and Play price answers (`tests/desktop-real-reads.test.ts`).
|
|
|
|
- Growth tab chart: impressions, downloads and conversion are drawn as an index (100 = each line's own average over
|
|
the days shown) on one axis, so downloads no longer lie flat under impressions; hover still shows the real numbers.
|
|
|
|
- **`storebound import fastlane`** (`--dir`, `--out`, `--profile`, `--dry`; MCP `import_fastlane`, dry run by default):
|
|
reads Appfile / Deliverfile (plain `key("value")` lines only; Ruby logic is reported, never run), deliver and supply
|
|
metadata and screenshots, and writes `storebound.config.ts`, `store/appstore.md`, `store/listing.md`, the Play icon
|
|
and feature graphics, and screenshot frames with a `folder` capture source. App Store and Play language codes are
|
|
paired into one `languages[]` entry (`cli/lib/store-locales.ts`). Existing files are never overwritten (a
|
|
`<name>.imported.<ext>` copy plus a diff hint). Keys, team ids, the App Review contact and demo account are only
|
|
named in the report; submission flags, `price_tier`, the age rating config, lanes and signing are listed with their
|
|
storebound counterpart. New skill `migrate-from-fastlane`.
|
|
|
|
- Store language codes checked against the official lists (2026-10-11): the 50 App Store Connect locale shortcodes
|
|
and the 86 Google Play listing codes all match; Zulu (`zu`) is no longer a Play listing language and was dropped;
|
|
`import fastlane` also accepts region-less folders of the 2025 App Store languages (`ta`, `sl`, `ur`, ...) and
|
|
App Store spellings in Play folders (`pa-IN`, `ur-PK`, `sl-SI`, ...). Sources are cited in `cli/lib/store-locales.ts`.
|
|
|
|
- Fixes from a read-only run against live store accounts: `apps check` says `api-disabled` (not `permission`) when the
|
|
Play Developer Reporting API is off, and `apps list` / serve `apps.list` fail with that reason and the fix instead of
|
|
a JSON fragment (API error bodies are kept on one line everywhere); the newest App Store version is the newest by
|
|
date (the API groups versions by platform), per-app reads run four at a time; the account check counts every app
|
|
of the team; Play prices under 1.00 (no `units` in the answer) no longer read as NaN in `catalog diff` and
|
|
subscription price diffs; `health` treats App Store Connect's 404 for builds without field data as no diagnostics;
|
|
`validate` no longer blocks on age rating fields accepted submissions leave empty (`gracRatingClassificationNumber`,
|
|
`socialMediaAgeRestricted` unless social media is yes; `socialMedia` is a warning).
|
|
- **Desktop D5: release pipeline.** The desktop app is a separate signed download from storebound.dev/desktop/ (DMG,
|
|
Windows installer, AppImage / deb) that updates itself; the npm package stays the CLI, MCP server and skills.
|
|
`storebound desktop` opens the app (in an app folder it adds or selects that folder through
|
|
`storebound://open?path=`, after the app's own dialog) or prints the download for this system; `--download` saves
|
|
it to ~/Downloads after checking its SHA-256 and minisign signature, and never installs. One desktop version
|
|
(`desktopVersion` in package.json, checked in CI), a privacy scan of every artifact (`tools/privacy-scan.ts`),
|
|
path-free builds, `tools/desktop-release.ts` (universal macOS app + DMG, Developer ID + notarization when the
|
|
certificate exists, otherwise an ad-hoc `-unsigned` preview; self-test of the exact artifacts; signed latest.json),
|
|
a Forgejo workflow for Linux and Windows, the root-owned publish step on the server and a downloads page
|
|
(`site/desktop/`). Settings > Updates checks and installs signed updates on request. See `docs/desktop-release.md`.
|
|
|
|
- **Desktop machine interface** (`serve --stdio`): JSON-RPC session for the coming desktop app, built on the MCP core.
|
|
Typed methods with argument schemas, structured results, progress notifications, cancellation, `project.inspect`
|
|
and `portfolio.status`: apps across iOS and Android with identity, config check, release trains (current and next
|
|
version on both stores) and catalog parity (`live` reads App Store and Play status). `system.tools` reports ffmpeg,
|
|
Chrome, Xcode tools, simctl, adb and git with versions; `STOREBOUND_TOOL_PATH` / `STOREBOUND_CHROME` point the CLI
|
|
at app-managed copies. Writes are dry runs unless the host
|
|
sends a single-use confirm token bound to the method, arguments and a short expiry (HMAC with a per-session secret
|
|
handed over on stdin). No submit / release / publish method exists. Under `serve`, terminal confirmations always
|
|
answer no.
|
|
- `--json` on `check` (and `check --aso`), `apple testflight status`, `apple ppo status`, `apple next-build`,
|
|
`play next-version-code`, `analytics compare` and `prices import` (read-only diff); new `inspect` command.
|
|
- **Desktop app shell** (`apps/desktop`, not released yet): Tauri 2 + React 19, app-centric (Portfolio, App with
|
|
Releases / Catalog / Listings / Health / Reviews / TestFlight, App folders, Accounts, Dependencies, Settings), store
|
|
keys in the OS keychain, native confirm dialogs with the dry run before any write. See `docs/desktop.md`.
|
|
- `--json` on `catalog diff` goes through the same machine-readable result line.
|
|
- **`storebound doctor`** (`--json`): ffmpeg, ffprobe, Chrome, playwright, Xcode tools, simctl, adb and git with
|
|
versions (the same detection as the desktop Dependencies screen) and the install commands for this OS. It runs none.
|
|
- `playwright` is an optional peer dependency (it was only documented before). The compiled desktop sidecar bundles
|
|
`playwright-core` and renders with the app's Chrome for Testing (`STOREBOUND_CHROME`), so desktop users need neither.
|
|
- `inspect --icon` / `inspect --listings` (listing completeness per language on both stores, rendered screenshots),
|
|
`reviews drafts [--json]` (local reply drafts with the send checks), `reviews approve <draft> [--undo] [--dry]`,
|
|
`init --dry`; templates are embedded so `init` works from a single-file binary.
|
|
- `apple status --json` includes the phased release of the newest live versions; release trains now count a staged
|
|
rollout or iOS phased release (also halted / paused) as the current train.
|
|
- **Desktop D2** (`apps/desktop`): redesigned shell (command palette, toasts with progress and cancel, skeletons,
|
|
illustrated empty states, first-run guide), release timeline per app, catalog parity matrix, listing completeness,
|
|
health sparklines against the Play thresholds, reviews inbox with star distribution and draft approval, TestFlight
|
|
groups and builds, store readiness with fix hints; offline cache of the last reads (SQLite, "last read" stamps);
|
|
one-click ffmpeg (pinned SHA-256) and Chrome for Testing (Google's code signature) downloads into app data;
|
|
English and Turkish with an i18n check, 7:1 text contrast checked in both themes.
|
|
- `tools/build-sidecars.ts`: single-file executables for macOS (arm64, x64), Linux (x64, arm64) and Windows (x64),
|
|
re-signed ad hoc on macOS and checked for build-machine paths. The MCP server now also runs from such a binary.
|
|
|
|
## 0.5.0 · 2026-10-11
|
|
|
|
Apps and games: storebound is for every mobile app, not only games, and the in-app catalog is complete on both stores.
|
|
|
|
- **Positioning**: "Take a mobile app or game from nothing to Submit for review on Google Play and the App Store"
|
|
across the README, the site (new "Apps and games" section, app screenshot style, og image), package, plugin and
|
|
adapter descriptions, CLI help, MCP server instructions and the skills. Game-specific advice stays, marked for games.
|
|
- **`init --profile app|game|subscription-app`** (default `app`): per profile a config, `declarations.md`,
|
|
`app-privacy.md`, the Data safety section, listing and screenshot copy and a privacy policy. app = utility /
|
|
productivity app with an optional account and analytics, no ads; subscription-app = accounts + auto-renewable
|
|
subscriptions with the disclosure text; game = the 0.4 templates. Every answer is flagged "edit to match your app".
|
|
Configs without `app.profile` keep working as games.
|
|
- **App screenshot style** (`shots.style: 'app'`, the default for the app profiles): calm gradient, a clean device frame,
|
|
headline + subline, no sparkles or badges (badges only as quiet chips), status bar text that follows the frame, Inter
|
|
by default, app palettes (mist, paper, mint, sand, rose, sky, ocean, slate), its own feature graphic. Game style
|
|
unchanged. New demo `examples/demo-app` ("Tidy Lists").
|
|
- **App identity**: `app.platforms` (default from the `apple` / `play` sections) and `platforms` on a product or
|
|
subscription to sell it on one store only; one shared catalog and shared listings, per-platform settings in
|
|
`apple` / `play`.
|
|
- **Subscriptions on both stores**: `apple subscriptions` (groups and display names, subscriptions with period, level,
|
|
family sharing, localizations, availability, prices from the USA price point and its equalizations plus overrides
|
|
and `--csv` rows of the prices sheet incl. scheduled changes, introductory offers per territory, promotional offers,
|
|
offer code campaigns, custom codes only with `--codes` after a terminal confirmation, review screenshots) and
|
|
`play subscriptions` (listings with benefits, one auto-renewing base plan with grace period and regional prices from
|
|
`convertRegionPrices`, overrides and CSV, activation, the intro offer for new subscribers and extra offers chosen by
|
|
your app through offer tags). Both print a plan, `--dry` stops there, a terminal run asks first; without a terminal
|
|
(MCP) only new records are created and live price changes wait for the owner. Skill `store-subscriptions`.
|
|
- **Full IAP catalog**: product type `non_renewing` (Apple NON_RENEWING_SUBSCRIPTION; a consumed one-time product on
|
|
Play), and **`catalog diff`**: the config's products and subscriptions against both stores (missing, extra, type,
|
|
billing period, level, US and override prices, localizations, offers) plus regions where the two stores price the
|
|
same item differently (same currency, `--threshold`). Read-only, exit 1 on mismatches.
|
|
- **Review access**: `apple review-details` sends `demoAccountRequired` / `demoAccountName` / `demoAccountPassword`
|
|
from `reviewDemoAccount` in `.storebound/credentials.json` (or `REVIEW_DEMO_USER` / `REVIEW_DEMO_PASSWORD`), masked
|
|
in every log line, and adds the sign-in steps (`reviewAccess.instructions`) and where account deletion is
|
|
(`accounts.inApp`) to the notes (4000-byte check). Skill `review-access`.
|
|
- **Account deletion**: `accounts { enabled, deletionUrl, inApp }`; skill `account-deletion` (Apple 5.1.1(v), Play's
|
|
in-app + web requirement and Data safety). `dataSafety.extra` adds CSV rows for questions Google does not document
|
|
(e.g. the delete-account URL id from a Console export).
|
|
- **Checks**: `check` reports the profile (delete-account URL, Data safety consistent with accounts, demo account
|
|
present, terms URL with subscriptions, subscription review screenshots); `validate` adds subscription states,
|
|
localizations, group names and review screenshots (App Store), active base plans (Play), the delete-account and
|
|
terms URLs answering, the demo account on App Review and a Terms of Use link in the descriptions.
|
|
- **Ad mediation**: `ads-levelplay-checks` became `ads-mediation-checks` (AdMob Ad Inspector, AppLovin MAX Mediation
|
|
Debugger, LevelPlay as a section, app-ads.txt, SKAdNetwork); the old name stays as a pointer skill.
|
|
- **MCP tools**: `apple_subscriptions`, `play_subscriptions` (dry run by default), `catalog_diff` (read-only). Custom
|
|
offer codes and live price changes are not reachable through MCP.
|
|
- Unverified until a live account run (see the README): free promotional offers / offer codes without a price point,
|
|
inline subscription prices and intro offers via `PATCH /v1/subscriptions/{id}`, Play relative-discount and untargeted
|
|
offers, the Play billing period strings and the undocumented Data safety ids.
|
|
|
|
## 0.4.0 · 2026-10-10
|
|
|
|
Wave 2: TestFlight and life after launch (stability, reviews, prices, analytics, experiments), plus MCP 2026-07-28.
|
|
|
|
- **TestFlight through the API** (`apple testflight status | groups | testers | what-to-test | info | distribute`):
|
|
beta groups from `apple.testflight.groups` (internal / external, public links; created when missing, never changed
|
|
or deleted), testers from a CSV in `.storebound/` (the config refuses a path outside it; emails masked in every log
|
|
line; asks before Apple emails invitations; `--remove`, `--invite`), "What to Test" per locale from the App Store
|
|
listing (`### whatToTest`, else the `whats-new` notes), Test Information and Beta App Review contact / notes, a build
|
|
by its exact number to groups, Beta App Review submission behind `--submit-review` and a confirmation. Skill
|
|
`testflight`.
|
|
- **Crash and vitals health** (`health [--weekly]`): Play Developer Reporting API (user-perceived crash and ANR rates,
|
|
28-day user-weighted, worst device models, top error issues) and App Store power and performance metrics,
|
|
diagnostic signatures and TestFlight crash reports. Play's bad behavior thresholds (1.09 % crash, 0.47 % ANR, 8 % per
|
|
device, developer.android.com/topic/performance/vitals): over = blocker, from 80 % = warn, also in `validate`
|
|
(`--no-health`). Weekly Markdown report with week-over-week change in `.storebound/health/`. Skill `store-health`.
|
|
- **Review replies** (`reviews list | draft | send`): App Store customer reviews / responses and Play reviews; drafts
|
|
as Markdown in `.storebound/replies/` (never overwritten), `send` only sends drafts with `approved: true` after a
|
|
confirmation and refuses incentives, rating requests and Play replies over 350 characters. Skill `review-replies`.
|
|
- **Price sheet** (`prices export | import`): one CSV of product x store x region; diff table first, then (after a
|
|
confirmation) one App Store price schedule per changed product (base territory, every manual price, future-dated
|
|
changes with `start_date`) and the Play purchase option's regional prices (`convertRegionPrices` for regions without
|
|
a price, `--reconvert`). `store-iap-setup` skill: price sheet section.
|
|
- **Analytics snapshots** (`analytics setup | snapshot | compare`): App Store Analytics Reports API (Discovery and
|
|
Engagement + Downloads, md5-checked segments, newest processing per day) and the Play statistics exports in the
|
|
`pubsite_prod_rev_` bucket (`play.reportsBucket`); snapshots in `.storebound/analytics/`, `compare` lines them up
|
|
with the git history of the store files. Skill `store-analytics`.
|
|
- **MCP 2026-07-28**: stateless requests with per-request `_meta` and `server/discover` (supported versions,
|
|
capabilities, instructions; `resultType`, server info in every result's `_meta`, cacheable `tools/list`, -32022 for
|
|
unsupported versions); `initialize` clients (2025-11-25 and older) keep working on the same process.
|
|
- **Product Page Optimization through the API** (`apple ppo status | create | upload | start | stop`): v2 tests with
|
|
one treatment per `shots` variant, a localization per locale and the variant renders in the treatment screenshot
|
|
sets; start / stop ask first. Play store listing experiments stay console-only (documented).
|
|
- **`iphone-medium` size key** (1206 x 2622, `APP_IPHONE_61`), off by default; `apple.iphoneMedium: true` renders,
|
|
checks and uploads it. Apple scales the 6.5" set down when it is missing.
|
|
- **MCP tools**: `apple_testflight_status`, `apple_testflight_groups`, `apple_testflight_what_to_test`,
|
|
`apple_testflight_info`, `apple_testflight_distribute` (internal groups only), `health`, `health_report`,
|
|
`reviews_list`, `reviews_draft`, `prices_diff`, `prices_export`, `analytics_snapshot`, `analytics_compare`,
|
|
`analytics_setup`, `apple_ppo_status`, `apple_ppo_create`, `apple_ppo_upload`. Not exposed: tester changes and
|
|
invitations, external distribution and Beta App Review, sending replies, applying prices, starting / stopping tests.
|
|
- Agent rules: owner-only steps now include review replies, tester invitations, price changes and experiments; personal
|
|
data (tester lists, reply drafts, health and analytics files) stays in `.storebound/`.
|
|
- `apple screenshots --dry` no longer creates empty screenshot sets.
|
|
|
|
## 0.3.1 · 2026-10-10
|
|
|
|
Positioning: storebound is the whole road from zero to "Submit for review", screenshots are one step of it.
|
|
|
|
- **README** rebuilt around the end-to-end journey: a new diagram (`docs/img/journey.svg`) and a step table for both
|
|
stores showing what storebound does through the APIs, what the skills walk your agent through in the consoles
|
|
(IARC, target audience, ads, advertising ID, App Privacy, app records, the first Play production send) and what
|
|
stays your own click (Send for review / Submit for Review, releases). "API or console, honestly" summary, a new FAQ
|
|
("Does it fill the questionnaires?"), quick start along the journey with the npm package, skills in journey order;
|
|
the screenshot and video showcase moved to a "Store art" section.
|
|
- Package, plugin, Codex, Gemini and marketplace descriptions follow the new positioning.
|
|
- `package.json` `bin` path normalised (`cli/index.ts`), so npm keeps the `storebound` command.
|
|
|
|
## 0.3.0 · 2026-10-10
|
|
|
|
Screenshots and videos from any engine, reviewed before they leave your machine.
|
|
|
|
- **Capture from anything** (`shots capture --source`): `web` (Playwright, unchanged), `ios-sim` (simctl boot, 9:41
|
|
status bar, launch arguments / deep links, `-AppleLanguages`, warm-up after a cold boot, shuts down only what it
|
|
booted), `android-emu` (demo-mode status bar, per-app language, `am start` with deep links / extras, screencap; never
|
|
boots, wipes or reboots), `folder` (your own frames, checked for aspect and size). Status bar cropped per device
|
|
class. `--dry` prints every simctl / adb command.
|
|
- **13" iPad** end to end with `apple.ipad: true`: `ipad13` size (2064 x 2752, 3:4 layout), iPad frame defaults, the
|
|
`APP_IPAD_PRO_3GEN_129` set in `apple screenshots`, required by `validate`.
|
|
- **Store rules as data** (`cli/shots/spec.ts`, sources cited): pixel sizes per store type, alpha, Play JPEG / 24-bit
|
|
PNG and 8 MB, counts per set, feature graphic, app preview rules. Used by the new `shots check` (local, exit 1 on
|
|
errors, `--variants`, `--json`) and by `validate` (local renders become blockers next to the store state).
|
|
- **`shots gallery`**: one self-contained `index.html` next to the renders (no network): every language x size x
|
|
scene, app previews with posters, variant tabs, filters, light / dark, issues outlined with their message.
|
|
- **A/B variants**: `shots.variants` (scene order / subset, copy overrides, palettes) rendered with
|
|
`shots render --variant b | --variants`, the feature graphic included; `--variant` on `play images`,
|
|
`apple screenshots` and `shots jpeg`. The skill explains Play store listing experiments and App Store Product Page
|
|
Optimization and what stays manual there.
|
|
- **App previews and promo video**: `shots record` (web via Chromium screencast, `simctl io recordVideo`, `adb
|
|
screenrecord`, or a folder of clips), `shots video` (886 x 1920 iPhone, 1200 x 1600 iPad, YouTube 9:16 / 16:9,
|
|
captions from the screenshot copy in every script, silent or music track, poster, ffprobe checks),
|
|
`apple previews` (preview sets per locale, MD5-idempotent, poster frame time code, files checked before upload),
|
|
`play listing` sends `play.video` (Play takes a YouTube URL, no upload).
|
|
- Contact sheet packed into a grid; Play 7" / 10" tablets drawn in an Android tablet body.
|
|
- **MCP**: `shots_check` (read-only), `shots_capture`, `shots_render`, `shots_gallery`, `shots_record`, `shots_video`
|
|
(local files, dry run by default), `apple_previews` (dry run by default); `variant` on the upload tools.
|
|
- **Skills**: new `app-previews`; `store-screenshots` covers sources, iPad, checks, gallery, variants, experiments and
|
|
the iPhone display class Apple now marks as required (6.9" stays the default, scaled down by Apple).
|
|
- **Demo game** `examples/demo-game/` ("Prism Puddle", fictional, procedural art) that storebound renders for the
|
|
showcase in this README; `--dry` on `shots render`, `shots video`, `shots gallery`.
|
|
- README rewritten; `CONTRIBUTING.md`, `SECURITY.md`. Playwright stays a dev dependency; runtime dependencies stay 0.
|
|
|
|
## 0.2.0 · 2026-10-10
|
|
|
|
Works with any AI coding tool now, plus the release and review side of shipping.
|
|
|
|
- **One source, many tools**: skills stay plain Agent Skills (`name` + `description` only); `tools/gen-adapters.ts`
|
|
writes the Claude Code plugin + `.mcp.json`, Codex plugin, Gemini CLI extension + `GEMINI.md`, `AGENTS.md`,
|
|
`.github/copilot-instructions.md` and a Cursor rule. CI fails when they are stale. Shared agent rules in
|
|
`docs/agents-core.md`.
|
|
- **`storebound mcp`**: stdio MCP server (2025-11-25), one tool per command, write tools dry run by default, nothing
|
|
public or irreversible exposed. No SDK, still zero runtime dependencies.
|
|
- **`storebound install --agent claude|codex|cursor|copilot|windsurf|gemini|opencode`**: skills + MCP entry into a
|
|
game project, idempotent, never touches other entries, `--dry`.
|
|
- New commands: `validate` (read-only readiness report for both stores, ordered blockers, exit 1),
|
|
`apple release --phased on|pause|resume|complete` and `--manual-release`, `apple status --wait-review`
|
|
(exit 0 / 1 / 7), `apple next-build`, `apple encryption`, `play rollout --fraction|--halt|--resume|--complete`,
|
|
`play next-version-code`, `check --aso`, `whats-new --since <tag>`, `privacy-manifest --ios <path>`, `version`.
|
|
- New skills: review-rejections, portfolio-originality, release-management, store-preflight, privacy-manifest,
|
|
export-compliance, aso-basics, whats-new.
|
|
- Updated skills: select builds by explicit number, first availability record UI fallback, phased + manual release
|
|
by default, IAP versions in review submissions (API 4.4.1, reported, verify), privacy manifest cross-links, tool-neutral
|
|
CLI instructions.
|
|
- Fix: Apple IAP description limit is 45 characters (App Store Connect Help), not 55.
|
|
- Config: `apple.usesNonExemptEncryption`, `apple.screenshotTypes`, `ads.appAdsTxt`.
|
|
- `bun run ci`: adapters check, tests, typecheck, secrets / personal data scrub.
|
|
|
|
## 0.1.0 · 2026-10-10
|
|
|
|
First public cut, extracted from the scripts I used to ship my own game.
|
|
|
|
- `storebound` CLI: `init`, `check`; Play `products`, `listing`, `images`, `data-safety`, `release`, `status`;
|
|
App Store `bundle`, `iap`, `iap-review`, `listing`, `screenshots`, `appinfo`, `review-details`, `status`
|
|
(incl. canceling a review submission); `icons`; `shots capture | fonts | render | jpeg`.
|
|
- Per-project `storebound.config.ts`; credentials only from env or `.storebound/credentials.json`.
|
|
- Claude Code plugin + marketplace with 8 skills: play-first-release, appstore-first-release, store-iap-setup,
|
|
store-screenshots, app-icons, store-declarations, privacy-policy, ads-levelplay-checks.
|
|
- Templates: config, Play + App Store listing copy, screenshot copy (5 languages incl. Arabic + Japanese), Data
|
|
safety CSV, App Privacy answers, Play declarations, studio-wide privacy policy page.
|
|
- Tests for config validation, copy parsing, Data safety CSV, price mapping, script fonts, args.
|