Commit graph

358 commits

Author SHA1 Message Date
CRT
54dd012cfa Merge cli-workspace: multi-app workspace, credential profiles, release trains in the CLI and MCP
# Conflicts:
#	.cursor/rules/storebound.mdc
#	.github/copilot-instructions.md
#	AGENTS.md
#	CHANGELOG.md
#	GEMINI.md
#	docs/agents-core.md
2026-10-11 23:36:36 +08:00
CRT
2165322c02 CLI workspace for many apps and studios, credential profiles, release trains (release status / plan)
- storebound.workspace.json: app folders (globs), studios with accounts by credential profile, ignore list, the
  desktop's pairing overrides; ws init | list | status | check | validate | run | apps import | desktop export/import
- credential profiles in ~/.storebound/credentials/<profile>.json or env, --account <profile> on any command
- release status / release plan <version>, table or --json; MCP workspace_list, workspace_status, release_status,
  release_plan (read-only)
- pairing rules (cli/lib/identity.ts), release lanes (cli/lib/train.ts) and the per-app status read
  (cli/lib/app-status.ts) shared with the desktop instead of copied
- tests with sanitized fixtures, README, skills, CHANGELOG
2026-10-11 23:35:45 +08:00
CRT
ae58948abd storebound scan: offline rejection-risk scan of the project itself
Detects the stack (native iOS / Android, React Native, Expo, Capacitor, Cordova,
Flutter, Unity, Godot) and the SDKs from a maintained table with versions,
file:line and each vendor's disclosure page, then reports App Store and Google
Play rejection risks with 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 and outside payments, 3.1.2 subscription info, 5.1.2(i)
ATT, purpose strings, privacy link, privacy manifest, 2.3.10, 2.3.7, 2.3.8, 4.2
web wrappers, 2.5.1, 2.5.5, ATS, export compliance, 1.3 kids ads, review
prompts, privacy labels vs SDKs; Play target SDK 36, delete-account URL, App
access, foreground services, exact alarms, QUERY_ALL_PACKAGES, SMS / call log,
com.example package name.

Proposes Data safety / App Privacy / ATT / privacy manifest answers (detected
file:line or ask owner) as a diff against the config; --write adds only the
detected ones. scan.ignore records owner-accepted findings. MCP tool scan
(read-only), validate includes open findings, desktop Checks tab shows them.
Fixtures for iOS, Android, Capacitor, Unity, Flutter, clean and teaser.
2026-10-11 23:20:55 +08:00
CRT
f9a53f508e tools: also look in the Android SDK folder Android Studio installs and in Homebrew, for apps started without a shell PATH 2026-10-11 09:51:22 +08:00
CRT
3af1b3e5f4 play products: price, region and activation changes of existing products ask first (diff, terminal confirmation or --yes; refused without a terminal and under serve unless a desktop owner action confirmed); new products and listing text unchanged; store-iap-setup skill and MCP description; tests 2026-10-11 08:47:28 +08:00
CRT
52d1e379e3 play products --dry: name what a run would change per product (listings added / changed / removed, regional prices old -> new, dropped regions, activation); checked live with convertRegionPrices allowed, store unchanged; test on a sanitized recorded product 2026-10-11 08:44:43 +08:00
CRT
b4d924b132 Guarded read-only run of the Play POST read paths: errorIssues:search in UTC, issues failure keeps the vitals, read-only listing / images dry runs
A live run where only the token exchange, edit insert / delete and Reporting :query were let through:
- health / validate: errorIssues:search answered 400 "Unsupported timezone" for America/Los_Angeles (it takes
  hour-aligned UTC only); the failure dropped the crash and ANR rates and the reason was cut off in the query string.
  Issues are asked in UTC; a failing issues search is a vitals-issues warning; Reporting errors leave out the query.
- play listing --dry / play images --dry wrote into the edit (PUT details and listings, image clears and uploads,
  :validate) before discarding it. Now one throwaway edit is read (details, listings, image sha256) and compared
  with the local copy, then deleted.
- play.read(): one helper for read-only edits (status, next-version-code), always deleted, warns if the delete fails;
  next-version-code counts distinct codes.
- tests on sanitized recorded answers (tests/play-post-reads.test.ts)
2026-10-11 08:41:55 +08:00
CRT
5d485e01b5 Real-account read check of the desktop tabs: analytics snapshot stops when every store failed, compare names why a store has no days (Growth shows it), listing screenshot count skips contact sheets; Growth chart as an index on one axis; recorded price answers round-trip the price sheet 2026-10-11 08:06:26 +08:00
CRT
be38af2dad Merge desktop-complete: prices, app info, growth, store art, exports, onboarding, UX audit 2026-10-11 07:49:56 +08:00
CRT
513c33330d serve: every CLI area for the desktop app (prices.current, project.declarations / listing_text / renders / render, import.fastlane for a new folder; owner.prices_import, owner.ppo_start / stop)
prices export --json reads the current prices without writing; inspect --declarations gives Data safety, the App
Privacy answers it suggests, app info, export compliance and App Review details with every question only the owner
can answer; play data-safety keeps the uploaded CSV in .storebound/ so changes since the upload show (Play cannot read
the form back); shots gallery --json carries the renders folder; inspect --render returns one render as a data: URL
from inside the renders folder only.
2026-10-11 07:40:59 +08:00
CRT
d26244fdc9 store-locales: verify App Store and Play codes against the official lists (2026-10-11), drop zu, aliases for the 2025 languages, tests 2026-10-11 07:37:18 +08:00
CRT
1637765c6f Merge desktop-d5: desktop release pipeline, updater, privacy gate, storebound desktop
# Conflicts:
#	CHANGELOG.md
2026-10-11 05:25:54 +08:00
CRT
10423ae915 storebound desktop: open the desktop app (with the current app folder) or show the download for this system; --download saves it to ~/Downloads after checking SHA-256 and the minisign signature, never installs 2026-10-11 05:16:59 +08:00
CRT
72dda418ea Merge fastlane-import: storebound import fastlane
# Conflicts:
#	CHANGELOG.md
2026-10-11 05:06:15 +08:00
CRT
de681dd967 import fastlane: config, App Store and Play listings, languages and screenshot frames from a fastlane setup
storebound import fastlane [--dir] [--out] [--profile] [--dry] (MCP import_fastlane, dry run by default) reads
Appfile / Deliverfile plain option lines, deliver and supply metadata and screenshots, and writes
storebound.config.ts, store/appstore.md, store/listing.md, the Play icon and feature graphics, and frames with a
folder capture source. App Store and Play language codes are paired (cli/lib/store-locales.ts). Existing files are
never overwritten (.imported copies with a diff hint); keys, team ids, the review contact and demo account are only
named in the report. Fixture tests/fixtures/fastlane-sample, skill migrate-from-fastlane, README and CHANGELOG.
2026-10-11 04:57:03 +08:00
CRT
44e64cf9c6 apps / health / catalog / validate: fixes from a read-only run against live store accounts
- API error bodies on one line (errorBody): Google and App Store Connect pretty-print errors, which hid
  SERVICE_DISABLED from the Play account check (reported permission instead of api-disabled), broke tables
  and turned serve's apps.list error into a JSON fragment
- apps list: failure says the reason and the fix (same words as apps check)
- newest App Store version by createdDate, iOS first (the API groups versions by platform); all versions
  read so no platform is missed; per-app reads four at a time
- apps check (apple): team app count from meta.paging.total with a one-app read
- Play Money without units (prices under 1.00) read as 0.xx, not NaN (catalog diff, subscription diffs)
- health: App Store Connect 404 for perfPowerMetrics / diagnosticSignatures means no field data yet;
  Play vitals behind a disabled Reporting API say so with the fix
- validate: gracRatingClassificationNumber optional, socialMediaAgeRestricted only when socialMedia is yes,
  socialMedia unanswered is a warning
- tests with sanitized recorded responses (tests/store-real-shapes.test.ts)
2026-10-11 04:50:26 +08:00
CRT
f106ec4423 Merge desktop-d3: studios and accounts, store import, pairing, ignore list, settings, confirm-gated writes 2026-10-11 04:33:03 +08:00
CRT
ba58895d3a Desktop D3 writes in the window: push listing text, upload graphics, screenshots and previews, render jobs, catalog sync and price export, Play rollout share / halt / resume / complete and iOS phased release controls, TestFlight What to Test, internal groups and testers, reply editor with approve and send; every one a dry run, a native dialog, then the real run 2026-10-11 04:25:53 +08:00
CRT
f47c00bed0 D3 writes: owner actions (Play rollout share / halt / resume / complete, iOS phased release, send one approved reply) answer the command's confirmation only with a verified host token; reviews reply edits a draft; native dialog names owner actions; token binding tests for every write the window offers 2026-10-11 04:19:47 +08:00
CRT
c2cb428413 check: name the missing file and the fix instead of a raw ENOENT; clearer demo account message; hero shows the new output 2026-10-11 03:54:03 +08:00
CRT
53f9e6dd75 CLI: storebound apps list | check (apps on a store account, account health with fixes); serve apps.list, account.check and store-only apps through a generated config 2026-10-11 03:53:52 +08:00
CRT
0ace432e87 CLI for desktop D2: doctor, inspect --icon / --listings, reviews drafts / approve, init --dry from embedded templates, iOS phased release share, playwright as optional peer (sidecar bundles playwright-core) 2026-10-11 03:34:45 +08:00
CRT
94d2f3d6ca Desktop: adapt to 0.5.0 (app.platforms, subscriptions, catalog diff), Dependencies polish, ~ for the home folder
- inspect reports platforms, subscription ids and the catalog each store should sell; app identity
  and parity follow app.platforms and per-item platforms; catalog.diff joins the JSON methods
- Portfolio: one Platforms column, compact catalog, paths truncated and shown with ~; the confirm
  dialog and run logs show ~ instead of the home folder
2026-10-11 02:15:48 +08:00
CRT
ab13d95898 serve: app-centric portfolio (apps across iOS / Android, release trains, catalog parity) and local tool detection
- portfolio.status returns apps: identity with both platforms, offline config check, release trains
  (current = highest version live on a store, next = highest above it; per-store phase, build,
  rollout fraction) and catalog parity (config vs both stores) when live
- inspect --json adds product ids and the subscription count
- system.tools: ffmpeg, ffprobe, Chrome / Chrome for Testing, Xcode tools, simctl, adb, git with
  versions and source; STOREBOUND_TOOL_PATH (front of PATH for every command) and STOREBOUND_CHROME
  (Playwright executablePath) let the desktop app hand over its own copies
2026-10-11 01:57:33 +08:00
CRT
d74d99bcc9 serve --stdio: desktop JSON-RPC profile on the MCP core, confirm tokens, --json results, sidecar builds
- cli/serve.ts: session.hello with a per-session secret, typed methods per tool, project.inspect,
  portfolio.status over many project folders, progress notifications, cancellation
- cli/lib/confirm-token.ts: single-use HMAC tokens bound to method + canonical params + expiry;
  writes are dry runs without one; no submit / release / publish method exists
- cli/lib/runner.ts: shared child runner for mcp and serve, works from a compiled binary
- --json on check, testflight / ppo status, next-build, next-version-code, analytics compare,
  prices import; inspect command; confirm() always answers no under serve
- tools/build-sidecars.ts: bun build --compile for five targets, ad-hoc re-sign on macOS, path leak check
- tests/serve.test.ts: methods, token binding / expiry / replay, shared vector, stdio and compiled smoke
2026-10-11 01:57:33 +08:00
CRT
c48eead0e0 0.5.0: mobile apps and games positioning (README, site, og image, skills, CLI, MCP, adapters), MCP tools for subscriptions and catalog diff, tests, changelog 2026-10-11 01:47:09 +08:00
CRT
b21e4a0920 App screenshot style (shots.style app): calm gradient, device frame, headline + subline; demo app Tidy Lists 2026-10-11 01:47:09 +08:00
CRT
7f0bb7c2dd init --profile app|game|subscription-app (default app): per-profile config, declarations, App Privacy, Data safety, listing and screenshot copy 2026-10-11 01:47:09 +08:00
CRT
44699eac8c Full IAP catalog: non-renewing products, per-platform availability, catalog diff (cross-store parity report) 2026-10-11 01:47:08 +08:00
CRT
162834444a Subscriptions on both stores: Apple groups, levels, equalized prices, intro and promotional offers, offer codes; Play base plans, regional prices, offers 2026-10-11 01:47:08 +08:00
CRT
20c0221b1d Review access and account deletion: demo account from .storebound (masked) to App Review, accounts config, profile checks in check and validate, Data safety extra rows 2026-10-11 01:47:08 +08:00
CRT
d3cc7e43d4 Product Page Optimization through the API (apple ppo) and an optional 6.3" iPhone size key
apple ppo status | create --variant b[,c] | upload --variant b | start | stop: v2 experiments (platform IOS, traffic
proportion), one treatment per shots variant (max 3), a treatment localization per App Store locale, and the variant
renders synced into the treatment screenshot sets (shared MD5-idempotent set sync with apple screenshots, which no
longer creates sets on --dry). start / stop ask first and are not MCP tools; MCP: apple_ppo_status, apple_ppo_create,
apple_ppo_upload. Play experiments stay console-only (documented).
apple.iphoneMedium (off by default): iphone-medium size key, 1206 x 2622 (1179 x 2556 accepted), uploaded as
APP_IPHONE_61; rendered, checked, required and uploaded only when enabled. Apple's scaling rule documented in the config
and the store-screenshots skill.
2026-10-10 23:28:10 +08:00
CRT
20db1345e4 MCP 2026-07-28: stateless revision with server/discover and per-request _meta, still 2025-11-25 compatible
Dual-era server: requests that carry io.modelcontextprotocol/protocolVersion are served statelessly (server/discover
with supportedVersions, capabilities, instructions, ttlMs / cacheScope; resultType complete and serverInfo in every
result's _meta; cacheable tools/list; -32022 UnsupportedProtocolVersion with data { supported, requested }; -32602 when
clientCapabilities is missing). initialize / ping / unannotated requests keep the 2025-11-25 (and older) behaviour.
Tests for both handshakes, including one stdio process serving a modern probe and a legacy client.
2026-10-10 23:28:10 +08:00
CRT
952a3a6e37 Analytics snapshots: storebound analytics setup | snapshot | compare, store-analytics skill
App Store Connect Analytics Reports API (ONGOING request, Discovery and Engagement + Downloads Standard reports,
daily instances, md5-checked gzip segments, newest processing per day) and the Play statistics exports in the
pubsite_prod_rev_ Cloud Storage bucket (UTF-16 CSV, store listing visitors / acquisitions, daily user installs;
play.reportsBucket). Snapshots in .storebound/analytics/<date>.json; compare lines them up with the git history of the
store files (7 days before vs after each change). MCP: analytics_snapshot, analytics_compare, analytics_setup.
2026-10-10 23:28:10 +08:00
CRT
104cd79117 Price sheet: storebound prices export | import (CSV of product x store x region)
export reads the current App Store manual (and with --with-automatic the equalized) prices and the Play purchase
option regional prices into one CSV. import parses and checks the sheet, prints a diff table (change %), and after a
confirmation writes one App Store price schedule per changed product (base territory + every manual price, future-dated
changes via start_date, price point ids looked up per territory) and the Play regional configs (CSV over current,
convertRegionPrices for regions without a price, --reconvert). MCP: prices_diff (read-only), prices_export; applying
stays a terminal command. store-iap-setup skill: price sheet section.
2026-10-10 23:28:10 +08:00
CRT
c99febc45b Review replies: storebound reviews list | draft | send, review-replies skill
App Store customerReviews / customerReviewResponses and Google Play reviews.list / reviews.reply. draft writes one
Markdown file per unanswered review to .storebound/replies (front matter approved: false, never overwritten); send
only sends approved, unsent drafts that pass the checks (Play 350 characters, no incentives or rating requests,
personal data / link / tone warnings) after a confirmation, and marks them sent. MCP: reviews_list, reviews_draft;
send is never exposed.
2026-10-10 23:28:10 +08:00
CRT
56e107dbbe Crash and vitals health: storebound health [--weekly], validate findings, store-health skill
Play Developer Reporting API v1beta1 (crashRateMetricSet / anrRateMetricSet DAILY queries in America/Los_Angeles,
user-perceived 28-day rates, worst device models, errorIssues:search) and App Store Connect perfPowerMetrics,
diagnostic signatures and TestFlight crash submissions. Thresholds 1.09 % crash / 0.47 % ANR / 8 % per device
(developer.android.com/topic/performance/vitals): over = blocker, from 80 % = warn, in validate too (--no-health).
Weekly Markdown report with week-over-week change in .storebound/health/. MCP: health (read-only), health_report.
2026-10-10 23:28:10 +08:00
CRT
3f12452e3f TestFlight through the App Store Connect API: apple testflight status | groups | testers | what-to-test | info | distribute
Beta groups from apple.testflight.groups (created when missing, never changed), testers from a CSV in .storebound/
(masked in logs, confirmation before Apple emails invitations, --remove / --invite), What to Test per locale from the
App Store listing (whatToTest or whatsNew), Test Information and Beta App Review details, builds by exact number to
groups, Beta App Review submission behind --submit-review and a confirmation. Pure planners in cli/lib/testflight.ts,
shared CSV / table / JSON:API helpers. MCP: apple_testflight_status, _groups, _what_to_test, _info, _distribute
(internal groups only). Skill testflight.
2026-10-10 23:28:10 +08:00
CRT
b63c5dc1cf store-screenshots skill: MCP use; iPhone required class (medium Dynamic Island) and why 6.9" stays the default 2026-10-10 22:24:58 +08:00
CRT
ccd48465a6 MCP: shots_check (read-only), shots_capture / render / gallery / record / video (local, dry by default), apple_previews; variant on uploads 2026-10-10 22:24:58 +08:00
CRT
5b4902496d shots render --dry: plan per language and variant 2026-10-10 22:24:58 +08:00
CRT
b97242b863 Register shots record, shots video and apple previews 2026-10-10 22:22:52 +08:00
CRT
6470c486f6 play listing sends the promo video URL (play.video) 2026-10-10 22:22:52 +08:00
CRT
2914f04129 apple previews: app preview sets per locale, MD5-idempotent, poster frame time code, local checks first, --dry 2026-10-10 22:22:52 +08:00
CRT
0cf5b8cdae shots video: dry run, clips under half a second skipped instead of the remainder 2026-10-10 22:22:52 +08:00
CRT
ea18406712 shots record: gameplay clips from a web build (Chromium screencast), iOS Simulator, Android emulator or a folder 2026-10-10 22:22:52 +08:00
CRT
d304cdab6d shots gallery: self-contained review page of every render with issues highlighted 2026-10-10 22:16:38 +08:00
CRT
bd12bd0690 --variant on play images, apple screenshots and shots jpeg; shared set up-to-date check 2026-10-10 22:16:38 +08:00
CRT
595bdbcf78 Contact sheet packed into a grid, Android tablet body for Play tablet sizes, variant in the feature graphic 2026-10-10 22:16:38 +08:00
CRT
aecdcb1c50 Store image checks in shots check and validate
- Apple sizes accepted portrait or landscape; Play screenshots any accepted size (320-3840 px, at most 2:1);
  Play rejects 16-bit PNGs; feature graphic exactly 1024 x 500
- Required sets per language (Apple only with an App Store locale, Play only with a Play code)
- shots check scans A/B variant folders only with --variants
- validate adds the local renders checks: store errors are blockers, overflow flags warnings (--no-local skips)
2026-10-10 21:54:47 +08:00