store art from the live stores: storebound art pull (App Store screenshot sets and previews per locale and display type from imageAsset.templateUrl at the original size, the App Store icon from the newest build or the public artwork; per Play language icon, feature graphic, phone / 7" / 10" / TV / Wear screenshots as the =s0 originals checked against Play's sha256) into store/renders with pulled.json (sha256, store, URL host, store checksum); upsert (a re-run changes nothing, differing local files kept unless --force, the upload's file of a slot compared: Play .jpg, App Store .png, the App Store icon as a picture); onboard runs it; apple screenshots / previews and play images see unchanged pulled files as the store's own; check: render sources are notes with pulled art; local renders check: pulled files pass, store-empty sets not demanded; art live / thumb / replace; desktop Store art tab: live thumbnails per store, language and set (same / differs / not pulled), Pull from stores, store-only apps read-only, Replace with a file (image_pick, art.replace) in the lightbox and the art editor; boot check store art case; tests/art-pull.test.ts; console parity 76 rows (57 complete, 19 with the reason); store-screenshots skill (pull first for live apps), pitfall 59

This commit is contained in:
CRTkafa 2026-10-14 02:18:38 +08:00
parent 49a73c90e4
commit 00be838b76
40 changed files with 1669 additions and 58 deletions

View file

@ -257,7 +257,7 @@ Specs: Apple [App Store Connect API 4.5.1](https://developer.apple.com/sample-co
| `appInfos_territoryAgeRatings_getToManyRelationship` | GET | `/v1/appInfos/{id}/relationships/territoryAgeRatings` | read | |
| `appInfos_updateInstance` | PATCH | `/v1/appInfos/{id}` | write (dry by default) | apple/appinfo |
| **appPreviewSets** (6) | | | | |
| `appPreviewSets_appPreviews_getToManyRelated` | GET | `/v1/appPreviewSets/{id}/appPreviews` | read | apple/previews |
| `appPreviewSets_appPreviews_getToManyRelated` | GET | `/v1/appPreviewSets/{id}/appPreviews` | read | apple/previews, art |
| `appPreviewSets_appPreviews_getToManyRelationship` | GET | `/v1/appPreviewSets/{id}/relationships/appPreviews` | read | |
| `appPreviewSets_appPreviews_replaceToManyRelationship` | PATCH | `/v1/appPreviewSets/{id}/relationships/appPreviews` | write (dry by default) | |
| `appPreviewSets_createInstance` | POST | `/v1/appPreviewSets` | write (dry by default) | apple/previews |
@ -282,7 +282,7 @@ Specs: Apple [App Store Connect API 4.5.1](https://developer.apple.com/sample-co
| `appPriceSchedules_manualPrices_getToManyRelated` | GET | `/v1/appPriceSchedules/{id}/manualPrices` | read | |
| `appPriceSchedules_manualPrices_getToManyRelationship` | GET | `/v1/appPriceSchedules/{id}/relationships/manualPrices` | read | |
| **appScreenshotSets** (6) | | | | |
| `appScreenshotSets_appScreenshots_getToManyRelated` | GET | `/v1/appScreenshotSets/{id}/appScreenshots` | read | apple/ppo, apple/screenshots, validate |
| `appScreenshotSets_appScreenshots_getToManyRelated` | GET | `/v1/appScreenshotSets/{id}/appScreenshots` | read | apple/ppo, apple/screenshots, art, validate |
| `appScreenshotSets_appScreenshots_getToManyRelationship` | GET | `/v1/appScreenshotSets/{id}/relationships/appScreenshots` | read | |
| `appScreenshotSets_appScreenshots_replaceToManyRelationship` | PATCH | `/v1/appScreenshotSets/{id}/relationships/appScreenshots` | write (dry by default) | |
| `appScreenshotSets_createInstance` | POST | `/v1/appScreenshotSets` | write (dry by default) | apple/screenshots |
@ -335,9 +335,9 @@ Specs: Apple [App Store Connect API 4.5.1](https://developer.apple.com/sample-co
| `appStoreVersionExperiments_getInstance` | GET | `/v1/appStoreVersionExperiments/{id}` | read | |
| `appStoreVersionExperiments_updateInstance` | PATCH | `/v1/appStoreVersionExperiments/{id}` | owner only (typed confirm) | |
| **appStoreVersionLocalizations** (14) | | | | |
| `appStoreVersionLocalizations_appPreviewSets_getToManyRelated` | GET | `/v1/appStoreVersionLocalizations/{id}/appPreviewSets` | read | apple/previews |
| `appStoreVersionLocalizations_appPreviewSets_getToManyRelated` | GET | `/v1/appStoreVersionLocalizations/{id}/appPreviewSets` | read | apple/previews, art |
| `appStoreVersionLocalizations_appPreviewSets_getToManyRelationship` | GET | `/v1/appStoreVersionLocalizations/{id}/relationships/appPreviewSets` | read | |
| `appStoreVersionLocalizations_appScreenshotSets_getToManyRelated` | GET | `/v1/appStoreVersionLocalizations/{id}/appScreenshotSets` | read | apple/screenshots, validate |
| `appStoreVersionLocalizations_appScreenshotSets_getToManyRelated` | GET | `/v1/appStoreVersionLocalizations/{id}/appScreenshotSets` | read | apple/screenshots, art, validate |
| `appStoreVersionLocalizations_appScreenshotSets_getToManyRelationship` | GET | `/v1/appStoreVersionLocalizations/{id}/relationships/appScreenshotSets` | read | |
| `appStoreVersionLocalizations_createInstance` | POST | `/v1/appStoreVersionLocalizations` | write (dry by default) | listing-store |
| `appStoreVersionLocalizations_deleteInstance` | DELETE | `/v1/appStoreVersionLocalizations/{id}` | owner only (typed confirm) | |
@ -371,7 +371,7 @@ Specs: Apple [App Store Connect API 4.5.1](https://developer.apple.com/sample-co
| `appStoreVersions_appStoreVersionExperimentsV2_getToManyRelationship` | GET | `/v1/appStoreVersions/{id}/relationships/appStoreVersionExperimentsV2` | read | |
| `appStoreVersions_appStoreVersionExperiments_getToManyRelated` | GET | `/v1/appStoreVersions/{id}/appStoreVersionExperiments` | read | |
| `appStoreVersions_appStoreVersionExperiments_getToManyRelationship` | GET | `/v1/appStoreVersions/{id}/relationships/appStoreVersionExperiments` | read | |
| `appStoreVersions_appStoreVersionLocalizations_getToManyRelated` | GET | `/v1/appStoreVersions/{id}/appStoreVersionLocalizations` | read | apple/listing, apple/previews, apple/screenshots, listing-store, onboard, validate |
| `appStoreVersions_appStoreVersionLocalizations_getToManyRelated` | GET | `/v1/appStoreVersions/{id}/appStoreVersionLocalizations` | read | apple/listing, apple/previews, apple/screenshots, art, listing-store, onboard, validate |
| `appStoreVersions_appStoreVersionLocalizations_getToManyRelationship` | GET | `/v1/appStoreVersions/{id}/relationships/appStoreVersionLocalizations` | read | |
| `appStoreVersions_appStoreVersionPhasedRelease_getToOneRelated` | GET | `/v1/appStoreVersions/{id}/appStoreVersionPhasedRelease` | read | apple/release, apple/status |
| `appStoreVersions_appStoreVersionPhasedRelease_getToOneRelationship` | GET | `/v1/appStoreVersions/{id}/relationships/appStoreVersionPhasedRelease` | read | |
@ -421,7 +421,7 @@ Specs: Apple [App Store Connect API 4.5.1](https://developer.apple.com/sample-co
| `apps_appPriceSchedule_getToOneRelationship` | GET | `/v1/apps/{id}/relationships/appPriceSchedule` | read | |
| `apps_appStoreVersionExperimentsV2_getToManyRelated` | GET | `/v1/apps/{id}/appStoreVersionExperimentsV2` | read | apple/ppo |
| `apps_appStoreVersionExperimentsV2_getToManyRelationship` | GET | `/v1/apps/{id}/relationships/appStoreVersionExperimentsV2` | read | |
| `apps_appStoreVersions_getToManyRelated` | GET | `/v1/apps/{id}/appStoreVersions` | read | apple/asc, apple/iap-submit, apple/listing, apple/release, apple/resubmit, apple/review-details, apple/status, lib/store-apps, listing-store, onboard, validate |
| `apps_appStoreVersions_getToManyRelated` | GET | `/v1/apps/{id}/appStoreVersions` | read | apple/asc, apple/iap-submit, apple/listing, apple/release, apple/resubmit, apple/review-details, apple/status, art, lib/store-apps, listing-store, onboard, validate |
| `apps_appStoreVersions_getToManyRelationship` | GET | `/v1/apps/{id}/relationships/appStoreVersions` | read | |
| `apps_appTags_getToManyRelated` | GET | `/v1/apps/{id}/appTags` | read | |
| `apps_appTags_getToManyRelationship` | GET | `/v1/apps/{id}/relationships/appTags` | read | |
@ -651,7 +651,7 @@ Specs: Apple [App Store Connect API 4.5.1](https://developer.apple.com/sample-co
| `builds_buildBetaDetail_getToOneRelationship` | GET | `/v1/builds/{id}/relationships/buildBetaDetail` | read | |
| `builds_diagnosticSignatures_getToManyRelated` | GET | `/v1/builds/{id}/diagnosticSignatures` | read | health |
| `builds_diagnosticSignatures_getToManyRelationship` | GET | `/v1/builds/{id}/relationships/diagnosticSignatures` | read | |
| `builds_getCollection` | GET | `/v1/builds` | read | apple/build, apple/encryption, apple/listing, apple/next-build, apple/resubmit, apple/status, apple/testflight, apple/upload, health, lib/store-apps, triage |
| `builds_getCollection` | GET | `/v1/builds` | read | apple/build, apple/encryption, apple/listing, apple/next-build, apple/resubmit, apple/status, apple/testflight, apple/upload, art, health, lib/store-apps, triage |
| `builds_getInstance` | GET | `/v1/builds/{id}` | read | |
| `builds_icons_getToManyRelated` | GET | `/v1/builds/{id}/icons` | read | |
| `builds_icons_getToManyRelationship` | GET | `/v1/builds/{id}/relationships/icons` | read | |
@ -1592,13 +1592,13 @@ Specs: Apple [App Store Connect API 4.5.1](https://developer.apple.com/sample-co
| **androidpublisher.edits.images** (4) | | | | |
| `androidpublisher.edits.images.delete` | DELETE | `androidpublisher/v3/applications/{packageName}/edits/{editId}/listings/{language}/{imageType}/{imageId}` | owner only (typed confirm) | |
| `androidpublisher.edits.images.deleteall` | DELETE | `androidpublisher/v3/applications/{packageName}/edits/{editId}/listings/{language}/{imageType}` | owner only (typed confirm) | play/images |
| `androidpublisher.edits.images.list` | GET | `androidpublisher/v3/applications/{packageName}/edits/{editId}/listings/{language}/{imageType}` | read | apps, play/images, validate |
| `androidpublisher.edits.images.list` | GET | `androidpublisher/v3/applications/{packageName}/edits/{editId}/listings/{language}/{imageType}` | read | apps, art, play/images, validate |
| `androidpublisher.edits.images.upload` | POST | `androidpublisher/v3/applications/{packageName}/edits/{editId}/listings/{language}/{imageType}` | write (dry by default) | play/images |
| **androidpublisher.edits.listings** (6) | | | | |
| `androidpublisher.edits.listings.delete` | DELETE | `androidpublisher/v3/applications/{packageName}/edits/{editId}/listings/{language}` | owner only (typed confirm) | |
| `androidpublisher.edits.listings.deleteall` | DELETE | `androidpublisher/v3/applications/{packageName}/edits/{editId}/listings` | owner only (typed confirm) | |
| `androidpublisher.edits.listings.get` | GET | `androidpublisher/v3/applications/{packageName}/edits/{editId}/listings/{language}` | read | |
| `androidpublisher.edits.listings.list` | GET | `androidpublisher/v3/applications/{packageName}/edits/{editId}/listings` | read | listing-store, play/listing, play/status, validate |
| `androidpublisher.edits.listings.list` | GET | `androidpublisher/v3/applications/{packageName}/edits/{editId}/listings` | read | art, listing-store, play/listing, play/status, validate |
| `androidpublisher.edits.listings.patch` | PATCH | `androidpublisher/v3/applications/{packageName}/edits/{editId}/listings/{language}` | write (dry by default) | listing-store |
| `androidpublisher.edits.listings.update` | PUT | `androidpublisher/v3/applications/{packageName}/edits/{editId}/listings/{language}` | write (dry by default) | listing-store, play/listing |
| **androidpublisher.edits.testers** (3) | | | | |

View file

@ -17,8 +17,8 @@ Columns:
real run; owner-only steps through the owner-action dialog).
- **Gap**: "none", or why a cell stays "no" on purpose.
Status: **after the editors (2026-10-14)**. The audit before them (Phase 1) had 70 rows, 62 of them with a gap. Now: 73
rows, 55 with nothing missing, 18 with the reason a cell stays "no" (no store API, an owner-only public step, a
Status: **after the editors and the live store art (2026-10-14)**. The audit before them (Phase 1) had 70 rows, 62 of them with a gap. Now: 76
rows, 57 with nothing missing, 19 with the reason a cell stays "no" (no store API, an owner-only public step, a
secret, or personal data).
## App Store Connect
@ -36,7 +36,7 @@ secret, or personal data).
| App Privacy > Privacy Policy URL | `apple listing` (app.privacyPolicyUrl) | yes | yes | yes | none |
| Version > Copyright | `apple listing` (app.copyright) | yes | yes | yes | none |
| Version > version string, build | `apple listing --version --build` | yes | yes | yes | none |
| Version > Screenshots (per device, locale) | `shots render`, `apple screenshots` (shots.scenes, the shots copy file) | yes | yes (scene order, the frame of each scene, the captions per language) | yes (`apple.screenshots`) | none |
| Version > Screenshots (per device, locale) | `art pull` (the live sets), `shots render`, `apple screenshots` (shots.scenes, the shots copy file) | yes (the live sets: `art.live` thumbnails per locale and display type; the local files) | yes (scene order, the frame of each scene, the captions per language; one image replaced with a picked file: `art.replace`) | yes (`apple.screenshots`; pulled files count as the store's own and upload nothing) | none |
| Version > App Previews | `shots record`, `shots video`, `apple previews` | yes | n/a | yes (`apple.previews`) | reason: a preview is cut from recorded clips, not a field; replacing one is a new recording (`shots.video` render job in the window) |
| App Information > Category, subcategories | `apple appinfo` (apple.info.categories) | yes | yes | yes (`apple.appinfo`) | none |
| App Information > Age Rating | `apple appinfo` (apple.info.ageRating), `console fill apple-age-rating` | yes | yes (every question) | yes | none |
@ -78,7 +78,7 @@ secret, or personal data).
| Main store listing > Short description | `play listing` (`### short`) | yes | yes | yes | none |
| Main store listing > Full description | `play listing` (`### full`) | yes | yes (stuffing and claims checks while typing) | yes | none |
| Release > Release notes (per language) | `play release`, `whats-new apply` (`### What's new`) | yes | yes | yes (with the release: `owner.play_production`) | none |
| Main store listing > Graphics (icon, feature graphic, screenshots) | `icons`, `shots render`, `play images` | yes | yes (scene order, frames, captions) | yes (`play.images`) | none |
| Main store listing > Graphics (icon, feature graphic, screenshots) | `art pull` (the live graphics), `icons`, `shots render`, `play images` | yes (the live graphics: `art.live` per language and type; the local files) | yes (scene order, frames, captions; one image replaced with a picked file: `art.replace`) | yes (`play.images`; pulled files count as the store's own and upload nothing) | none |
| Main store listing > Video (YouTube URL) | `play listing` (play.video) | yes | yes | yes | none |
| Store settings > Contact email | `play listing` app details (app.contactEmail) | yes | yes | yes | none |
| Store settings > Website | `play listing` app details (app.website) | yes | yes | yes | none |
@ -106,6 +106,8 @@ secret, or personal data).
| What | storebound | View | Edit | Store write | Gap |
| --- | --- | --- | --- | --- | --- |
| Pull the live texts into the files | `apple listing pull`, `play listing pull` | yes | n/a | n/a (writes the listing files after the diff) | none |
| Pull the live store art into the app folder (screenshots, previews, feature graphic, icons) | `art pull` (also run by `onboard`), store/renders/pulled.json | yes (`art.live`: live thumbnails, same / differs / not pulled per image) | n/a | n/a (`art.pull`: local files only after the dry run, read-only on the stores; differing local files kept) | none |
| Store-only app (no folder): listing text per language | `listing live`, `listing set` | yes | yes | yes (`listing.set`, one language per apply) | none |
| Store-only app (no folder): URLs, contact, catalog, art | (the config of an app folder) | yes (reads) | no | no | reason: those writes send what an app folder's config holds; "Link a folder" or "Start an app folder" turns the app into a full one |
| Store-only app (no folder): store art | `art live` | yes (`art.live`: live thumbnails per language and set, read-only) | no | no | reason: replacing store art uploads files from an app folder; "Link a folder" or "Start an app folder" turns the app into a full one, whose Pull from stores (`art.pull`) brings the live art into it |
| Store-only app (no folder): URLs, contact, catalog | (the config of an app folder) | yes (reads) | no | no | reason: those writes send what an app folder's config holds; "Link a folder" or "Start an app folder" turns the app into a full one |
| Uncommitted changes in the app folder | git status of the edited files | yes | n/a | n/a | none (storebound never commits) |