d2ce185441
One product per machine: the CLI and the desktop app share one version, the store accounts and the app folder list
...
- one version: package.json's version is the desktop app's too (desktopVersion removed); tools/desktop-version.ts
keeps the plugin manifests and the app's copies equal, desktop-release publish refuses another version, release
order app first then npm publish; the unpublished desktop 0.1.0 candidate is noted in the docs and CHANGELOG
- storebound desktop installs (per user, no admin: macOS DMG -> /Applications or ~/Applications, Windows NSIS /S,
Linux AppImage + .desktop with the storebound:// handler), updates an older app, notes a newer one (downgrade only
with --force), asks once ([Y/n], --yes, exit 3 without a terminal), opens on the folder; --dry / --json / --download;
the install steps are pure plans (cli/lib/desktop-install.ts); the version's own manifest dl/<version>/latest.json
- credentials: one store, the CLI's credential profiles in ~/.storebound/credentials; the desktop writes and reads
them (profiles.rs, files 0600), moves old keychain accounts into profiles on first start, shows profiles the CLI
made; precedence env > named profile > project file > default profile; config `account`, "account" in the
project's credentials.json; storebound accounts list | import (dedup by key id / service account e-mail, key files
copied 0600, project file keeps keystore and review contact, backup, --dry, never prints values) | use
- app folders: one list ~/.storebound/projects.json shared by the desktop (registry.rs), storebound desktop,
apps folders | add | remove, ws init and ws without a workspace file
- desktop: notice when a folder pins another storebound version; storebound-desktop --version
- tests: version drift, desktop decisions and per-OS plans, credential precedence and import, registry (TS + Rust),
keychain migration and profile round trip (Rust), boot check with old keychain state and the new shared state
2026-10-13 06:17:37 +08:00
bba46b5c7f
apple testflight distribute: a build's groups read per group (GET /v1/betaGroups/{id}/relationships/builds) instead of GET /v1/betaGroups?filter[builds]=, which App Store Connect refuses with 400 although the spec declares it; internal all-builds groups reported as already available and never sent the build; a re-run adds nothing; configured groups missing on App Store Connect point at groups sync, unknown ones list what exists; APPLE_LIVE_REJECTED (refused by storebound api too), tests/asc-query-guard.test.ts checks every App Store Connect GET with a query in cli/ against the spec's declared parameters, and the fake App Store Connect answers 400 to undeclared or live-refused parameters (pitfall 42)
2026-10-13 06:03:16 +08:00
f741c15829
console: Play App content card Saves are the agent's (declaration-save; Send changes for review, Submit, Publish, Restart review stay forbidden), one owner batch per plan with the IARC Terms tick before the run, console plan play-app-content --all, New App fields typed not set, play.appId from the Create app redirect (console verify --url --write) and storebound play app-id across app list pages
2026-10-13 05:44:29 +08:00
1366e7e231
scan, privacy answers and credentials from a second game's first release (lessons 35-37): review-prompt needs rating context, not a bare "rate"; account signals skip import lines and module paths, config-only accounts say "from config"; accounts.inApp without deletion code stays a medium 5.1.1(v) finding; privacy-manifest --propose builds NSPrivacyCollectedDataTypes from appPrivacy.types and check warns on an empty list; appPrivacy.types is authoritative in the App Privacy sheet (unlisted = not collected), ad / support / AR types default to not collected without tracking or ad SDKs; Play advertising ID from SDKs, the AD_ID permission, app-ads.txt or the flag, never from a Device ID alone; scan.ignore[].evidence and warnings for entries that match nothing; empty credentials template, placeholder values count as missing (check, doctor)
2026-10-13 05:39:09 +08:00
86cd79dd45
desktop-release add: evidence-linux / evidence-windows files (run, commit, sizes, hashes, scan) and a check that every artifact of a version comes from one commit (--commit against the folder's other evidence); docs: check the downloads against the run before add
2026-10-13 05:09:17 +08:00
0b6c8cd7a0
teaser v8: a 58 s story instead of a feature list (the game is done; the stores pile up; one missing line; hand it to your AI; a montage of builds, screenshots, products, forms, consoles; the scan turns green; one button is yours; Waiting for review; the end card), one short line per scene, cuts on the 120 BPM beat; music rewritten for the arc (calm, tension, near silence, a driving build, a stop, a resolve), mastered with one gain instead of dynamic loudnorm; the pile shows real console plan, Data safety CSV and price sheet lines, the builds beat real apple / play build dry runs; desktop.ts captures submit-ready (Send for review before the press); tests check every line, the beat-aligned cuts and the caption times; two unused teaser icons dropped
2026-10-13 04:48:33 +08:00
d5ffc159c0
0.7.1: README links and images absolute (npmjs.com rendered relative paths as 404s); test keeps README free of relative links
2026-10-13 04:37:25 +08:00
ba8cfd2594
0.7.0: version (package, plugin and extension manifests), changelog section with summary; check no longer counts owner-only App content steps (IARC Terms, demo account typing) as missing config answers; the check shot shows a ready project (init plus icons, apple.name, App content answers, demo account): all good
2026-10-13 04:19:39 +08:00
36a8bf9625
CLI runs on Node 20+: npx storebound (bunx keeps working)
...
- cli/lib/rt.ts: the runtime layer on node: modules (spawn / spawnSync with Bun's defaults, exit codes and
"Executable not found", which with PATHEXT, sleep, serve, Glob, hasher, gunzip, stdin, SQLite, packageRoot,
config imports with a type-stripping fallback for Node 20); every Bun.* use in cli/ goes through it
- tools/gen-embedded.ts -> cli/lib/embedded.ts: templates/, cli/shots/*.html and Play's Data safety form embedded
(replaces Bun text imports; the bundle and the compiled sidecar carry them), checked fresh by bun run ci
- package.json: bin dist/storebound.mjs (Node ESM bundle, tools/build-node.ts, prepack), engines node >=20
- bun run ci: node bundle + node smoke (real node: --version, help, check same as Bun, scan, release plan --help,
init, MCP handshake + tool call); Forgejo CI sets up Node 20; tests/node-compat.test.ts guards cli/
- install writes npx MCP commands when run with Node; bin/storebound falls back to Node
- docs: npx storebound init (Node 20+) or bunx storebound init
2026-10-13 04:03:28 +08:00
614c32bcba
teaser v7: 62 s, two new scenes (consoles: the real console plan of apple-app-privacy, then the app's plan panel stopping at Publish; resubmit: back from App Review, Resubmit), submit renewed as the app's own send-for-review (dry-run plan with Continue, then Waiting for review); v6's desktop scene folded into it; console plan lines checked against real output, cuts on the beat, image decodes batched with retries
2026-10-13 03:49:42 +08:00
710c3a53d0
README, docs and site: one story (the whole job, no avoidable rejections, the desktop app, your AI, install)
...
README is a short front page (about 120 lines) with one real visual per section; every former section moved
unchanged into docs/*.md with a docs/README.md index (journey, rejections, getting-started, commands, growth,
studios, store-art, listing-languages, api, skills, mcp, safety, faq, project). The site tells the same story on one
page: the teaser in the hero, real CLI output as text, the desktop app as a section with light/dark captures of eight
screens and the per-system downloads (desktop/latest.json); /desktop/ redirects to /#download. New capture tools:
tools/site-desktop-shots.ts (fixture-mode desktop frames) and tools/site-term-shots.ts (real CLI output as text and
WebP). tests/docs-links.test.ts checks README, docs and site links resolve.
2026-10-13 03:29:59 +08:00
deb218943c
ci workflow: CI=full on the command itself (the runner's CI=true overrode the workflow env, so the desktop Rust tests and clippy were skipped on pushes that did not touch src-tauri)
2026-10-13 03:02:17 +08:00
54c3bbac2c
ci workflow: Playwright browser cache keyed by playwright-core's browsers.json (the repo has no bun.lock, the key was empty)
2026-10-13 02:57:18 +08:00
b9579e2a2e
shots / console: resolve playwright only from an installed node_modules copy; in a project without playwright Bun auto-installed the newest one into its global cache, whose browsers were never downloaded (capture-web on Linux CI: 'headless shell: not installed'; macOS hid it with Google Chrome)
2026-10-13 02:55:12 +08:00
56591f4118
ci on Linux: --no-sandbox for the Chromium storebound starts itself as root on Linux or in a container (sandboxArgs; Chromium refuses root without it), never on macOS / Windows / a normal user; workflow caches Playwright's browsers; capture-web prints the capture's stderr when a run fails
2026-10-13 02:51:48 +08:00
8c7274edcc
desktop-release: a DMG notarization without an answer (notarytool killed or timed out) says so instead of an empty reason
2026-10-13 02:32:23 +08:00
12b01f065c
desktop-release: architecture guard before signing (tauri build --no-sign, guard, then tauri bundle signs / notarizes): every Mach-O in the app must contain arm64, nothing Intel-only, Info.plist must not force Intel (LSRequiresNativeExecution false, LSArchitecturePriority x86_64 first); guard repeated on the signed app, the DMG and the updater bundle, recorded in evidence.json
2026-10-13 02:32:09 +08:00
9ba8471002
ci speed: desktop boot check runs its cases in parallel (one browser, killed at the end; a page per case; condition waits instead of fixed sleeps: element, text or a quiet window of host calls and DOM); shots capture / render close the browser with a 3 s cap, then kill it; console engine waits injectable for tests (WAITS / engineWaits: poll rounds, a missing step ends once its loaded page stays quiet, team switch settle, field-miss grace), fillPage looks up each data type's dialog once per round and skips dialog sections when no dialog is open; browser tests run 4 at a time per file (testScope().concurrent with a scope per test, --max-concurrency in ci), 20 ms rounds; capture-web counts boots per test and runs its browser tests concurrently; console-session / -persist Chrome tests concurrent; recorded test timings smoothed (mergeTimings) so one loaded run does not skew the shard split
2026-10-13 02:22:25 +08:00
f2d7062bcb
docs desktop-release: the Linux job starts the AppImage and the deb under Xvfb
2026-10-13 02:09:58 +08:00
b375f1a5e2
desktop bundle: long description (the deb's description said '(none)')
2026-10-13 02:09:58 +08:00
2e66aa42b6
desktop: the notification plugin's refused is_permission_granted probe at page load (macOS, Linux; the webview has no plugin API) is no longer logged as a start error in webview.log
2026-10-13 02:09:58 +08:00
7901beee1e
desktop (Linux): a missing update-desktop-database or xdg-mime no longer stops the app at start (the setup hook failed with 'No such file or directory'); storebound:// registration failure is a host.log warning
2026-10-13 02:09:58 +08:00
187911320b
desktop workflow: start the AppImage and the deb under Xvfb; the UI must reach the sidecar (host.log), no error lines
2026-10-13 02:09:58 +08:00
3952716ef8
desktop-release: never run the x86_64 slice on the build Mac (Rosetta makes macOS warn the owner that the app will not open in the next macOS); every Mach-O in the bundle checked with lipo (arm64 + x86_64), self-test and sidecar version run natively only; pitfall 34
2026-10-13 02:01:35 +08:00
7e09947e62
console verify App Privacy: real page text (category-only summary sections, ' | ' joined lines, Apple's commas); tracking label without 'data data'; Play Data safety page path confirmed
2026-10-13 01:38:50 +08:00
2b101f0fd8
desktop: Releases > Send for review (App Store submission state, builds by number, Submit / Resubmit / in-app purchases; Play versionCodes by number, Send to production, managed publishing, console plans for countries and Send changes for review), plan panel before every owner dialog with streamed progress; App info console steps for every console plan form with verify; Catalog price-change owner actions and the declined state; Data safety deletion answer; TestFlight create missing groups; Android SDK in Dependencies; upload progress in job toasts; boot check send-for-review cases on D1 and D3 state
2026-10-12 12:08:43 +08:00
33eb24a3dc
apple submit --build <n> (first submission, the resubmit steps; plan table with --json under serve); desktop owner actions to send for review: owner.apple_submit, owner.apple_resubmit, owner.apple_iap_submit, owner.play_production, and the price gate owner actions (owner.prices_play_products / _play_subscriptions / _apple_subscriptions; owner.prices_import passes --allow-price-changes after the dialog); OWNER_ALLOWED_ARGS ties each forbidden flag to its one action, dry runs never carry owner flags, MCP still has no submit or production release; submit dialog text in the host; system.tools androidSdk, project.inspect playRelease, declarations dataDeletion
2026-10-12 12:08:07 +08:00
2e7dd44ae6
play build versionCode source check: follow a variable (def / ext. / val) to its definition; a variable read from the property is not flagged
2026-10-12 11:34:41 +08:00
0b1451800c
apple iap-submit: DEVELOPER_REJECTED IAP / subscription / group versions (left by a canceled submission) are submitted as they are, plan says 'add (developer rejected, re-submitted as is)', --new-version only for APPROVED / REJECTED, empty draft reused; fake ASC models cancel and re-add. play build / check: warn before Gradle when defaultConfig does not read -PversionCode / -PversionName, with the exact Groovy / Kotlin line (built with AGP 8.13); android.injected.version.code does not override bundleRelease; post-build versionCode mismatch is a hard stop. play-production-release plan: 'Do you want to restart your review?' dialog, Restart review is never-press. Pitfalls 31-33
2026-10-12 11:32:05 +08:00
41d2ffcc24
apple testflight groups: bare lists the groups and what the config would create (read-only); groups sync (or --yes) creates; flows: bare = read, sync = write; MCP tool runs groups sync
2026-10-12 10:48:59 +08:00
1724296e59
apple resubmit: REJECTED review submission items are marked resolved before the submit (PATCH reviewSubmissionItems resolved: true; the version item by default, IAP / subscription items with --resolve-iaps), plan table 'mark resolved' rows; on 409 'not ready yet' the items are re-read and a REJECTED item out of scope stops the run at once naming it and how to resolve it, backoff only when none is left; an empty READY_FOR_REVIEW draft is never canceled (409 'not in cancellable state'): left as is, no cancel command, apple status labels it harmless and treats the cancel 409 as such; fake ASC blocks submit on REJECTED items and refuses to cancel empty drafts. Pitfall 30
2026-10-12 10:45:05 +08:00
0da5ee9d01
apple resubmit after a rejection: iap-submit reuses the open review submission (UNRESOLVED_ISSUES gets only missing items and is resubmitted, a draft is reused, one waiting for or in review means nothing is sent), never a second draft; 409 ITEM_PART_OF_ANOTHER_SUBMISSION names the other submission instead of the list-lag message, a draft the run created is canceled and the named one used; submit retried with backoff and heartbeat while Apple says not ready yet; new apple resubmit --build <n> (build by number, plan table, --yes); apple status lists UNRESOLVED_ISSUES items and the resubmit command. Pitfall 30
2026-10-12 10:34:12 +08:00
c8213be2b6
ITMS-91064: NSPrivacyTracking and NSPrivacyTrackingDomains must agree in every privacy manifest (true needs domains, domains need true); check, scan and privacy-manifest fail on either mismatch with the exact ITMS text; App Privacy tracking no longer demands the app manifest's true: SDK manifests that declare tracking (Pods, frameworks, SwiftPM, Carthage, plugins, the built IPA) are info, known tracking SDKs info, else a warning; privacy-manifest --propose writes true only with appPrivacy.trackingDomains; apple upload checks every manifest in the IPA (XML or binary) before any network call, apple build after the export. Pitfall 29
2026-10-12 10:27:21 +08:00
b7bfe89151
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
2026-10-12 10:16:34 +08:00
dbd9f2973c
play data-safety: PSL_SUPPORT_DATA_DELETION_BY_USER is the general 'can users request deletion?' question; a delete-account URL answers yes (with PSL_DATA_DELETION_URL), dataSafety.dataDeletion for apps without one; check flags a no next to a delete-account URL
2026-10-12 09:46:58 +08:00
e01a27d7b7
price changes of existing products need --allow-price-changes (play products, play/apple subscriptions, prices import): --yes and flow run --apply --yes confirm creates, first prices and other updates only; without the flag the run writes the rest, names each held change and exits 3 (declined), dry runs mark them owner, flows refuse the flag; lib/price-gate.ts, tests/price-gate.test.ts. CLI wording: console fill leaves what it cannot open or fill to the calling agent's browser tool (console plan / verify) instead of 'yourself'; other 'by hand' output points at the config; do-it-dont-ask test scans cli/ output
2026-10-12 09:38:57 +08:00
b5b8f2da9d
play data-safety: PSL_SUPPORT_DATA_DELETION_BY_USER as Play's single choice (partialDeletion true | false | 'auto90'), drop the removed PSL_DATA_COLLECTION_USER_REQUEST_DELETE (deletionRequest deprecated, check notes it); ship Google's empty form (cli/data/play-data-safety-form.csv, exported 2026-10-12), take every Answer requirement from it and report pairs not in it (formPairIssues) in check, declarations and play data-safety. Pitfall 21
2026-10-12 09:34:12 +08:00
dfc28c15f8
agent rules: first rule "Do it, don't ask" (agents-core and every adapter, README, store-pitfalls lead, first-release, declarations and console skills); the agent runs the real command after the dry run, the owner presses only final public or irreversible buttons and answers compliance facts in one batch; handoff text removed from skills; tests/do-it-dont-ask.test.ts. Pitfall 26
2026-10-12 09:28:45 +08:00
fc524cd2d4
play build: find the Android SDK like Android Studio (ANDROID_HOME, ANDROID_SDK_ROOT, sdk.dir, default folder), pass it in the env, stop before Gradle when missing; doctor shows it. apple upload: size, per-part lines, 20 s heartbeat (api, altool, processing wait), per-part and per-call timeouts, --timeout exits 7 with the resume hint. Pitfall 25
2026-10-12 08:59:45 +08:00
366362d62b
flow run: a declined confirmation stops the flow; --apply --yes confirms write steps
...
confirm() prints 'declined: <reason>' and exits 3 whenever the answer is no or nobody can answer (not a
terminal without --yes, serve without the owner's dialog), so no command reports success after declining.
flow run stops at such a step with 'step N declined: <reason>' (status declined), never ok. flow run
--apply --yes passes --yes to write steps only; --yes without --apply is refused. Pitfall 24.
2026-10-12 08:51:58 +08:00
5fbb9e63e3
build.prebuild and a Capacitor web-asset staleness guard for apple build / play build
...
apple build and play build run build.prebuild (or apple.prebuild / play.prebuild) first, once per flow run;
--no-prebuild skips it, --dry only prints it. A Capacitor project's copied public/index.html must then be newer
than the last source commit and <webDir>/index.html, else the build stops (--allow-stale-web overrides). check
warns when stale without a prebuild; the build output and dry plan show the web bundle's sha256 and mtime.
The Capacitor project is also found in a monorepo (apps/native etc.); several ask for play.build.dir /
apple.build.*. Pitfall 23.
2026-10-12 08:51:38 +08:00
f694af80eb
pitfall 22: AAB proto manifest field numbers
2026-10-12 08:46:03 +08:00
78be1304ec
AAB manifest: read aapt2 Resources.proto field numbers (element name 3, attribute 4, child 5); real AGP bundles failed with 'AAB manifest without package / versionCode'
2026-10-12 08:45:43 +08:00
720cb2a13a
play images: same languages as play listing (drafts skipped unless --include-drafts); a language with no Play listing (404) is skipped with an info line, never fatal
2026-10-12 08:45:43 +08:00
147cee9721
templates: app / subscription-app answer dataSafety.partialDeletion; teaser Data safety row count 766
2026-10-12 08:40:36 +08:00
97ab76e9c8
play data-safety: write the conditional required rows (PSL_ACCOUNT_DELETION_URL from accounts.deletionUrl, PSL_SUPPORT_DATA_DELETION_BY_USER from dataSafety.partialDeletion, PSL_DATA_DELETION_URL); a rule table checks every conditional row in check, declarations and --dry before Play answers 400
2026-10-12 08:40:36 +08:00
c9a7f095c4
console: agent-first mode (console plan / console verify), verified App Privacy and Play Create app facts
...
- `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.
2026-10-12 08:39:12 +08:00
a9261a8052
play images: tablet, TV and Wear sets are optional; play.tablets switch (default: tablet renders exist); a missing optional set never deletes Play's images without --prune
...
A phone-only project aborted with 'no sevenInchScreenshots'. Play requires the 512 icon, the 1024x500 feature graphic and at least 2 screenshots (Play Console Help answer 9866151). play images uploads what exists and prints an info line for missing optional sets; play.tablets true makes missing tablet sets an error in shots render/check/gallery, validate and play images. Pitfall 19.
2026-10-12 08:21:03 +08:00
18fde37b9b
console fill: labels match straight and curly quotes (Developer’s Advertising, the user’s identity); an App Privacy dialog step with no inputs (the definitions page) is passed with Next
2026-10-12 07:52:13 +08:00
0035931734
console fill: never copy Google session cookies by default (device-bound); own profile in a Chrome started without automation switches
...
Google binds its session cookies to the device (Device Bound Session Credentials) and signs out
sessions whose cookies look stolen, which can sign the owner out of their real Chrome. The default is
now storebound's own profile per store; storebound starts Chrome itself (--user-data-dir,
--remote-debugging-port=0, no --enable-automation, navigator.webdriver false) and attaches over CDP.
--use-chrome-session google|apple is an explicit opt-in that warns. /signin/rejected is said plainly.
2026-10-12 07:46:38 +08:00