Play console steps without an API as agent plans: play-store-settings (App category; play listing cannot set it), play-app-content (every card in order, one owner batch) and its cards (privacy policy, ads, sign in details, advertising ID, government, financial, health), play-production-countries and play-production-release; IARC plan with the Terms of Use agreement, follow-ups (console.contentRating.details, products[].randomRewards, social) and the Summary's final Save; config play.category / countries / managedPublishing, console.appContent; check, validate, play status and play release reminders; inPageLoop helper and material checkbox clicks; App Privacy published signal; first IAPs via apple iap-submit --with-version. Pitfalls 27, 28

This commit is contained in:
CRTkafa 2026-10-12 10:16:34 +08:00
parent dbd9f2973c
commit b7bfe89151
37 changed files with 1624 additions and 121 deletions

View file

@ -7,7 +7,8 @@
// ~/.storebound/console-accounts.json) and the workspace's account ids; --lookup also asks the App Store Connect API
// for the app id by bundle id (a GET; needs the API key). Pure logic in cli/lib/console-plan.ts. MCP: console_plan.
import type { Ctx } from '../lib/ctx';
import { FORM_IDS, formMeta, isForm } from '../lib/console-answers';
import { formMeta, isForm, isPlanForm, PLAN_FORM_IDS } from '../lib/console-answers';
import { reviewDemoAccount } from '../lib/credentials';
import { consolePlan, type PlanIds, planText } from '../lib/console-plan';
import { printJson } from '../lib/log';
@ -16,18 +17,21 @@ export async function run(ctx: Ctx): Promise<void> {
const args = ctx.args, json = args.has('json');
const form = args._[0];
if (!form) {
const forms = FORM_IDS.map(id => { const m = formMeta(id, config); return { id, store: m.store, title: m.title, fillable: m.fillable }; });
const forms = PLAN_FORM_IDS.map(id => {
if (isForm(id)) { const m = formMeta(id, config); return { id, store: m.store, title: m.title, fillable: m.fillable, scripted: m.fillable }; }
return { id, store: 'play' as const, title: consolePlan(id, config).title, fillable: true, scripted: false };
});
if (json) return printJson({ forms });
console.log('storebound console plan <form> [--json] [--lookup] (then drive the page yourself; `storebound console verify <form>` checks it)\n');
for (const f of forms) console.log(` ${f.id.padEnd(22)} ${f.store.padEnd(6)} ${f.title}${f.fillable ? '' : ' (guide only)'}`);
for (const f of forms) console.log(` ${f.id.padEnd(26)} ${f.store.padEnd(6)} ${f.title}${f.fillable ? (f.scripted ? '' : ' (agent only, no console fill)') : ' (guide only)'}`);
return;
}
if (!isForm(form)) throw new Error(`console plan: unknown form "${form}" (one of ${FORM_IDS.join(', ')})`);
if (!isPlanForm(form)) throw new Error(`console plan: unknown form "${form}" (one of ${PLAN_FORM_IDS.join(', ')})`);
const { withAccountIds, readAccounts } = await import('./accounts');
const cfg = withAccountIds(config);
const pkg = cfg.play?.packageName;
const cached = pkg ? readAccounts().play[pkg] : undefined;
const ids: PlanIds = { playDeveloperId: cfg.play?.developerId ?? cached?.developerId ?? null, playAppId: cfg.play?.appId ?? cached?.appId ?? null };
const ids: PlanIds = { playDeveloperId: cfg.play?.developerId ?? cached?.developerId ?? null, playAppId: cfg.play?.appId ?? cached?.appId ?? null, demoAccount: !!reviewDemoAccount(root) };
if (form.startsWith('apple-') && !cfg.apple?.appId && cfg.apple?.bundleId) {
const { appleAppId } = await import('./app-id');
// without --lookup only the cache is read: the lookup refuses, so no request is made