- `storebound console plan <form> [--json] [--lookup]`: read-only plan for an AI agent that drives the browser itself: start URL (deep links), ordered steps, answer sheet with the console's exact labels (certain / ask owner, curly quotes noted), never-press list, verified UI facts, driving guidance (in-page async loop + window.__log), verify instructions. All six forms. - `storebound console verify <form> [--from-text <file|->]`: App Privacy per-type summaries from page text, Play Create app from input states, content rating / target audience summaries, App Store record and age rating from the API; exit 1 on a mismatch. - MCP: console_plan, console_verify (read-only); console fill stays off MCP. - App Privacy (verified 2026-10-12): two information steps, unlabeled purpose checkboxes (nearest parent text), "Definitions and Examples" never pressed; fixture and engine follow. - Play Create app (verified 2026-10-12): /developers/<id>/create-new-app, App package name + read-only Check availability, material-radio inner [role=radio] click, app dashboard URL and play.appId, service account "Add app" as an owner step. - console-autofill skill rewritten agent-first; agents-core rule 10; README; pitfalls 12, 18 (confirmed sign-out), 19; CHANGELOG; play-first-release.
54 lines
4.3 KiB
HTML
54 lines
4.3 KiB
HTML
<!doctype html>
|
|
<!-- Play Console > Create app (/console/u/0/developers/<id>/create-new-app). Structure verified on a real console
|
|
(2026-10-12, driven through Claude in Chrome; structure only, no data copied): App name (textbox, 30 max), App
|
|
package name (textbox, 150 max) with a read-only "Check availability" button that answers "Package name
|
|
available", Default language, App or game and Free or paid as <material-radio> elements (an inner [role=radio]
|
|
with aria-checked; the native input inside does NOT update the form's model: until the inner [role=radio] is
|
|
clicked the form shows "Select app or game" / "Select free or paid"), and the two declarations (agreements the
|
|
owner ticks). The final "Create app" is the owner's click. Placeholder data only.
|
|
window.__model: the form's model (what Angular would hold). -->
|
|
<html lang="en"><head><meta charset="utf-8"><title>Create app - Play Console</title><script src="/_common.js"></script></head>
|
|
<body>
|
|
<h1>Create app</h1>
|
|
<form onsubmit="return false">
|
|
<h2>App details</h2>
|
|
<p><label>App name <input type="text" maxlength="30"></label></p>
|
|
<p><label>App package name <input type="text" maxlength="150" id="pkg"></label> <button type="button" id="check">Check availability</button> <span id="avail"></span></p>
|
|
<p><label>Default language <select><option value="">Choose a language</option><option>English (United Kingdom) – en-GB</option><option>English (United States) – en-US</option><option>Turkish – tr-TR</option></select></label></p>
|
|
<div role="radiogroup" aria-label="App or game">
|
|
<material-radio><div role="radio" aria-checked="false" tabindex="0" aria-labelledby="t-app"><input type="radio" name="type" tabindex="-1" style="opacity:0;position:absolute;width:1px;height:1px"></div><span id="t-app">App</span></material-radio>
|
|
<material-radio><div role="radio" aria-checked="false" tabindex="0" aria-labelledby="t-game"><input type="radio" name="type" tabindex="-1" style="opacity:0;position:absolute;width:1px;height:1px"></div><span id="t-game">Game</span></material-radio>
|
|
<p class="hint" data-group="type">Select app or game</p>
|
|
</div>
|
|
<div role="radiogroup" aria-label="Free or paid">
|
|
<material-radio><div role="radio" aria-checked="false" tabindex="0" aria-labelledby="p-free"><input type="radio" name="price" tabindex="-1" style="opacity:0;position:absolute;width:1px;height:1px"></div><span id="p-free">Free</span></material-radio>
|
|
<material-radio><div role="radio" aria-checked="false" tabindex="0" aria-labelledby="p-paid"><input type="radio" name="price" tabindex="-1" style="opacity:0;position:absolute;width:1px;height:1px"></div><span id="p-paid">Paid</span></material-radio>
|
|
<p class="hint" data-group="price">Select free or paid</p>
|
|
</div>
|
|
<h2>Declarations</h2>
|
|
<fieldset><legend>Developer Program Policies</legend>
|
|
<label><input type="checkbox"> Confirm app meets the Developer Program Policies</label>
|
|
</fieldset>
|
|
<fieldset><legend>US export laws</legend>
|
|
<label><input type="checkbox"> Accept US export laws</label>
|
|
</fieldset>
|
|
<button type="button">Cancel</button> <button type="submit">Create app</button>
|
|
</form>
|
|
<style>material-radio { display: inline-block; margin-right: 12px } [role=radio] { display: inline-block; width: 14px; height: 14px; border: 1px solid #555; border-radius: 50%; vertical-align: middle } [role=radio][aria-checked=true] { background: #1a73e8 }</style>
|
|
<script>
|
|
window.__model = { type: null, price: null };
|
|
document.querySelectorAll('[role=radiogroup]').forEach(g => {
|
|
const key = g.querySelector('input').name;
|
|
g.querySelectorAll('material-radio [role=radio]').forEach(r => r.addEventListener('click', () => {
|
|
// only a click on the inner [role=radio] updates the model (the native input does not)
|
|
g.querySelectorAll('[role=radio]').forEach(x => x.setAttribute('aria-checked', String(x === r)));
|
|
r.querySelector('input').checked = true;
|
|
window.__model[key] = document.getElementById(r.getAttribute('aria-labelledby')).textContent;
|
|
g.querySelector('.hint').hidden = true;
|
|
}));
|
|
});
|
|
document.getElementById('check').addEventListener('click', () => {
|
|
document.getElementById('avail').textContent = document.getElementById('pkg').value ? 'Package name available' : 'Enter a package name';
|
|
});
|
|
</script>
|
|
</body></html>
|