apple: macOS (tvOS, visionOS) versions are no longer invisible: every version and review submission lookup is per platform; status, listing, listing pull, resubmit, submit, release and screenshots take --platform and otherwise pick the platform that has the version they need (refuse naming both when several do); status, validate, release status, the report and the desktop label versions with their platform; MCP and owner actions get platform; pitfall 77
This commit is contained in:
parent
1736300784
commit
47dfd372fe
30 changed files with 423 additions and 127 deletions
|
|
@ -27,6 +27,7 @@ export interface ToolDef {
|
|||
const only: JsonSchema = { type: 'string', description: 'Comma-separated ids / language codes to limit the run to (optional)' };
|
||||
const lang: JsonSchema = { type: 'string', description: 'Comma-separated language ids from the config (default: all)' };
|
||||
const variant: JsonSchema = { type: 'string', pattern: '^[a-z0-9][a-z0-9-]*$', description: 'A/B variant id from shots.variants (default: the base renders)' };
|
||||
const platform: JsonSchema = { type: 'string', enum: ['ios', 'macos', 'tvos', 'visionos'], description: 'App Store platform of the version (default: the one that has the version this needs; when several do, the command asks for it)' };
|
||||
const source: JsonSchema = { type: 'string', enum: ['web', 'ios-sim', 'android-emu', 'folder'], description: 'Default: from the config' };
|
||||
const APP_NAMES = '^[^,\\x00-\\x1f]{1,120}(,[^,\\x00-\\x1f]{1,120}){0,99}$';
|
||||
const opt = (flag: string, v: unknown): string[] => (v === undefined || v === null || v === '' ? [] : [`--${flag}`, String(v)]);
|
||||
|
|
@ -55,8 +56,8 @@ export const TOOLS: ToolDef[] = [
|
|||
args: i => [...opt('store', i.store), ...flag('originality', i.originality), ...(i.originality ? opt('against', i.against) : [])] },
|
||||
{ name: 'validate', title: 'Store readiness report', command: ['validate'], write: false, network: true,
|
||||
description: 'Read-only readiness report for App Store Connect and/or Google Play with ordered blockers (build, encryption, metadata, screenshots, review details and demo account, age rating, prices, IAPs, subscriptions, privacy, delete-account and terms URLs, app-ads.txt, tracks, products, base plans).',
|
||||
props: { store: { type: 'string', enum: ['both', 'apple', 'play'], default: 'both' } },
|
||||
args: i => (i.store === 'apple' ? ['--apple'] : i.store === 'play' ? ['--play'] : []) },
|
||||
props: { store: { type: 'string', enum: ['both', 'apple', 'play'], default: 'both' }, platform },
|
||||
args: i => [...(i.store === 'apple' ? ['--apple'] : i.store === 'play' ? ['--play'] : []), ...opt('platform', i.platform)] },
|
||||
{ name: 'report', title: 'Shareable readiness report', command: ['report'], write: false, network: true,
|
||||
description: 'One self-contained HTML page with the scan, check and validate results (read-only; validate only for the stores whose credentials are there, else the page says why): summary per store, findings by store and severity with guideline, evidence, fix and console link, the compliance questions only the owner can answer. Writes only .storebound/reports/readiness-<date>.html (masked: no credentials, key ids, emails or demo account) and returns its path and the summary; never opens a browser.',
|
||||
props: { format: { type: 'string', enum: ['html', 'md'], default: 'html' }, offline: { type: 'boolean', default: false, description: 'Skip validate (no store reads)' } },
|
||||
|
|
@ -141,7 +142,8 @@ export const TOOLS: ToolDef[] = [
|
|||
{ name: 'analytics_setup', title: 'Start App Store analytics reports', command: ['analytics', 'setup'], write: true, network: true, idempotent: true,
|
||||
description: 'Create the ONGOING App Store Connect analytics report request once (needs an Admin key; reports start 1-2 days later). Changes nothing public.' },
|
||||
{ name: 'apple_status', title: 'App Store status', command: ['apple', 'status'], write: false, network: true,
|
||||
description: 'Read-only App Store Connect overview: versions and their states, recent builds, in-app purchases, review submissions.' },
|
||||
description: 'Read-only App Store Connect overview: versions of every platform (iOS, macOS, ...) and their states, recent builds, in-app purchases, review submissions with their platform.',
|
||||
props: { platform }, args: i => opt('platform', i.platform) },
|
||||
{ name: 'apple_next_build', title: 'Next iOS build number', command: ['apple', 'next-build'], write: false, network: true,
|
||||
description: 'Next safe CFBundleVersion: one above every build uploaded for the app.' },
|
||||
{ name: 'apple_signing_status', title: 'Code signing status', command: ['apple', 'signing', 'status'], write: false, network: true,
|
||||
|
|
@ -203,11 +205,11 @@ export const TOOLS: ToolDef[] = [
|
|||
description: 'Upload (replace when changed) the App Review screenshot of every in-app purchase. Never submits.' },
|
||||
{ name: 'apple_listing', title: 'Push App Store version + text', command: ['apple', 'listing'], write: true, network: true, idempotent: true,
|
||||
description: 'Create / update the editable version (manual release), attach a build by explicit number, and push name / subtitle / description / keywords / promo / what\'s new per locale. dry_run prints the plan: version keep / update / create / refuse with the reason, per locale old -> new per field; draft locales are skipped (owner terminal run with --include-drafts).',
|
||||
props: { version: { type: 'string', pattern: '^\\d+(\\.\\d+){0,2}$' }, build: { type: 'string', description: 'Exact build number to attach (use the number you just uploaded, never "latest")' }, only },
|
||||
required: ['version'], args: i => [...opt('version', i.version), ...opt('build', i.build), ...opt('only', i.only)] },
|
||||
props: { version: { type: 'string', pattern: '^\\d+(\\.\\d+){0,2}$' }, build: { type: 'string', description: 'Exact build number to attach (use the number you just uploaded, never "latest")' }, only, platform },
|
||||
required: ['version'], args: i => [...opt('version', i.version), ...opt('platform', i.platform), ...opt('build', i.build), ...opt('only', i.only)] },
|
||||
{ name: 'apple_screenshots', title: 'Upload App Store screenshots', command: ['apple', 'screenshots'], write: true, destructive: true, network: true, idempotent: true,
|
||||
description: 'Sync 6.9" and 6.5" (+ 13" iPad with apple.ipad) screenshots per locale from the renders folder (or an A/B variant folder; MD5-idempotent; changed sets are replaced). Slow: prefer the terminal with a log.',
|
||||
props: { only, variant }, args: i => [...opt('only', i.only), ...opt('variant', i.variant)] },
|
||||
props: { only, variant, platform }, args: i => [...opt('only', i.only), ...opt('variant', i.variant), ...opt('platform', i.platform)] },
|
||||
{ name: 'apple_appinfo', title: 'App Store app info', command: ['apple', 'appinfo'], write: true, network: true, idempotent: true,
|
||||
description: 'Categories, age rating declaration, content rights, Free price and availability (when missing).' },
|
||||
{ name: 'apple_review_details', title: 'App Review information', command: ['apple', 'review-details'], write: true, network: true, idempotent: true,
|
||||
|
|
@ -217,8 +219,8 @@ export const TOOLS: ToolDef[] = [
|
|||
props: { build: { type: 'string', description: 'Build number (default: every build without an answer)' } }, args: i => opt('build', i.build) },
|
||||
{ name: 'apple_phased_release', title: 'Phased release on / pause', command: ['apple', 'release'], write: true, network: true, idempotent: true,
|
||||
description: 'Turn on the 7-day phased release for the upcoming version, or pause an active one (pausing is not a rollback). Resume / complete / release are owner-only terminal commands.',
|
||||
props: { action: { type: 'string', enum: ['on', 'pause'] }, version: { type: 'string' } }, required: ['action'],
|
||||
args: i => ['--phased', String(i.action), ...opt('version', i.version)] },
|
||||
props: { action: { type: 'string', enum: ['on', 'pause'] }, version: { type: 'string' }, platform }, required: ['action'],
|
||||
args: i => ['--phased', String(i.action), ...opt('version', i.version), ...opt('platform', i.platform)] },
|
||||
{ name: 'shots_capture', title: 'Capture raw frames', command: ['shots', 'capture'], write: true, network: false, idempotent: true,
|
||||
description: 'Raw app or game frames per language into shots.frames from a web build (Playwright), the iOS Simulator (simctl), an Android emulator / device (adb) or a folder check. Local files only; a simulator it boots is shut down again, an emulator is never booted. dry_run lists the plan and the simctl / adb commands.',
|
||||
props: { lang, only: { type: 'string', description: 'Comma-separated shot names' }, device: { type: 'string', enum: ['phone', 'tablet'] }, source,
|
||||
|
|
@ -342,8 +344,8 @@ export const TOOLS: ToolDef[] = [
|
|||
args: i => [...opt('only', i.only), ...flag('with-version', i.with_version), '--json', '--dry'] },
|
||||
{ name: 'apple_listing_pull', title: 'Pull App Store texts', command: ['apple', 'listing', 'pull'], write: true, network: true, idempotent: true,
|
||||
description: 'Read the live App Store texts (name, subtitle, description, keywords, promotional text, what\'s new per locale) and diff them against the App Store listing file. dry_run shows the diff; with dry_run false the file is updated (local file only).',
|
||||
props: { version: { type: 'string', pattern: '^\\d+(\\.\\d+){0,2}$', description: 'Version to read (default: the editable one, else the newest)' } },
|
||||
args: i => [...opt('version', i.version), '--json', ...(i.dry_run === false ? ['--write'] : [])] },
|
||||
props: { version: { type: 'string', pattern: '^\\d+(\\.\\d+){0,2}$', description: 'Version to read (default: the editable one, else the newest)' }, platform },
|
||||
args: i => [...opt('version', i.version), ...opt('platform', i.platform), '--json', ...(i.dry_run === false ? ['--write'] : [])] },
|
||||
{ name: 'play_listing_pull', title: 'Pull Google Play texts', command: ['play', 'listing', 'pull'], write: true, network: true, idempotent: true,
|
||||
description: 'Read the live Play listings (title, short and full description per language; one throwaway edit, deleted) and diff them against the Play listing file. dry_run shows the diff; with dry_run false the file is updated (local file only).',
|
||||
args: i => ['--json', ...(i.dry_run === false ? ['--write'] : [])] },
|
||||
|
|
@ -365,7 +367,7 @@ export const TOOLS: ToolDef[] = [
|
|||
args: () => ['--json'] },
|
||||
{ name: 'whats_new_apply', title: 'Apply release notes per language', command: ['whats-new', 'apply'], write: true, network: false, idempotent: true,
|
||||
description: 'Write the checked per-language release notes into both listing files (Play "What\'s new" per Play code, App Store whatsNew per locale). Refuses while a language is over a limit or untranslated. Local files only; nothing is sent to a store.',
|
||||
args: () => ['--json'] },
|
||||
props: { platform }, args: i => [...opt('platform', i.platform), '--json'] },
|
||||
{ name: 'listing_translate', title: 'Listing translation drafts', command: ['listing', 'translate'], write: true, network: false, idempotent: true,
|
||||
description: 'Add a section per target language to both listing files (App Store: name, subtitle, promotionalText, keywords, description; Google Play: title, short, full) with the source language\'s text and a status=translate marker. Then translate each field in place within the store limits (App Store subtitle 30, promotional text 170, keywords 100 comma-separated without duplicates or name words, description 4000; Play title 30, short 80, full 4000), set the marker to status=draft and run listing_check. The owner reviews the drafts (storebound listing reviewed). Reviewed sections are kept. Local files only.',
|
||||
props: { to: { type: 'string', pattern: '^[A-Za-z0-9_-]+(,[A-Za-z0-9_-]+)*$', description: 'Comma-separated target languages (config ids, App Store locales or Play codes)' },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue