|
|
357319a775
|
--json prints only JSON on stdout (withJsonOutput around every command: logs, tables and prompts to stderr; printJson everywhere; test runs every --json command against the fake stores and parses stdout); prices ppp compares like with like: par = the store's own US-equivalent price (Play convertRegionPrices, Apple equalizations; offline base x fx x (1 + VAT) rounded up) scaled by the PPP price level; defaults only lower, only price levels <= 0.5, World Bank high-income at par, CN at par on Apple and skipped on Play, never above par (--only-decreases, --max-ratio, --min-ratio, --max-level, --include-high-income; --floor / --ceiling kept), top-10 revenue market drops > 20 % warned (sales reports, else a static list), unchanged regions out of the sheet; price changes of existing products only with --allow-price-changes, TTY or not (a terminal yes covered them), then their own question listing each old -> new, held section in dry runs (play products, prices import, play / apple subscriptions); pitfalls 61-63; tests
|
2026-10-14 17:36:00 +08:00 |
|
|
|
bab3f63227
|
whats-new drafts from player-facing notes first (whatsNew.source, docs/RELEASE-<version>.md, the CHANGELOG section of the version or Unreleased; --release, --from-git) and only then from the git log; internal jargon warnings (SDK / vendor names, developer and version-control words, file paths, issue ids, code identifiers) with plain alternatives in the draft and whats-new check, one list in cli/lib/jargon.ts, whatsNew.allowWords keeps a word; skill: write from what players feel, never from commit messages; tests
|
2026-10-14 14:45:19 +08:00 |
|
|
|
e9507d8884
|
check blocks an apple app without app.copyright (App Store Connect requires it; never filled in automatically); validate reads the live version's copyright and says whether the store has one; round-trip test that the config writers (upsertBlock, upsertNestedString, removeKeyPath) keep unknown keys and comments; tests
|
2026-10-14 14:37:47 +08:00 |
|
|
|
73db689386
|
privacy manifest discovery skips build-output and copy folders (hidden dirs like .native-build, build, DerivedData, node_modules, dist, Products, built .app / .xcarchive) in scan, check and privacy-manifest: a stale .native-build copy was checked instead of the real ios/ manifest; test
|
2026-10-14 13:14:49 +08:00 |
|
|
|
7219ded3e8
|
template compliance answers never reach a store: init writes unanswered (dataSafety, appPrivacy, reviewNotes, ageRating, accounts, reviewAccess), older configs are recognised by the template values; check / validate / scan block, play data-safety (also --dry), console plan / fill, apple review-details and appinfo refuse. onboard --declarations replaces them on a live app: name and copyright from the stores (a copyright with a private term is left out), the rows the code proves (scan proposal, sign-up methods from auth code and login SDKs), the rest as one owner question list. play data-safety --dry prints the answers that change (old -> new, account and deletion first) against the last uploaded CSV; pitfall 60; tests
|
2026-10-14 11:36:30 +08:00 |
|
|
|
34c2fa22e5
|
site: first-party, cookieless visit stats (self-hosted Umami at storebound.dev/s/, Do Not Track respected) with events for copy buttons, desktop downloads per OS, the teaser (play, 50 %, complete) and outbound docs / git / npm links; a privacy note in the footer; docs/site-analytics.md and tools/vds/ configs to rebuild the server side; scrub allows a page's public stats website id
|
2026-10-14 11:11:24 +08:00 |
|
|
|
83c14d3a8e
|
tests: console-fill idmsa frame test waits for the frame, its form and its click log instead of reading them right after the sign-in hint (race under load)
|
2026-10-14 09:13:04 +08:00 |
|
|
|
a8c7f77d87
|
acceptance: macOS results of 0.8.3 from 1c44095 (123/123 on Node 20, Node 22, Bun), docs/acceptance.md regenerated
|
2026-10-14 08:51:14 +08:00 |
|
|
|
1c44095b84
|
acceptance report expects all 9 runs (Linux, Windows, macOS x node20 / node22 / bun)
|
2026-10-14 08:45:32 +08:00 |
|
|
|
b29f1c407c
|
apple listing: asking for the version that is in review says it is locked (it said "already exists; a new version needs a higher number"); play images: a listing language missing from languages[] is skipped with the fix instead of stopping the run (play listing pushes its text). Both found by the live dry-run sweep; tests
|
2026-10-14 08:43:59 +08:00 |
|
|
|
9d6f741092
|
acceptance.yml: the release matrix on demand (Linux + Windows x node20/node22/bun, then the report); macOS results of 0.8.3 (123/123 on Node 20, Node 22, Bun) in docs/acceptance/, docs/acceptance.md generated
|
2026-10-14 08:38:12 +08:00 |
|
|
|
17883e1529
|
acceptance: create the --out folder (both CI runs passed every quick cell, then failed writing acceptance/<run>.json), log the warm-up cell
|
2026-10-14 08:33:12 +08:00 |
|
|
|
2c14e5318a
|
apple: no app info on App Store Connect is a clear error (it crashed apple listing / appinfo with "undefined is not an object (evaluating 'info.id')"); asset uploads use basename (a Windows path sent the whole C:\... path as fileName), reviews send --only and previews names split both separators; tests/matrix-bugs.test.ts
|
2026-10-14 08:29:31 +08:00 |
|
|
|
f58e192001
|
release acceptance matrix: tools/acceptance.ts runs every user-facing command from the packed npm tarball (npx --package=<tgz> on Node 20 / 22, bun x --bun after bun add <tgz>) in fresh temp folders with a fresh HOME, real piped stdin (n, EOF) and per-cell fake stores over HTTP (STOREBOUND_STORE_MOCK, loopback only); a cell passes only with the expected exit code and no crash text; report -> markdown matrix. Prompts go through stdinIsTTY (STOREBOUND_ASSUME_TTY drives them with piped stdin), STOREBOUND_DESKTOP_APP=none for the install prompt on a machine with the app. release.yml: required acceptance job matrix (Linux + Windows x node20/node22/bun) and report, the matrix attached to the release; ci.yml: the quick subset on Linux and Windows. Scan fixtures for React Native and Expo
|
2026-10-14 08:29:31 +08:00 |
|
|
|
ae681e3ecd
|
release: privacy scan of signed macOS artifacts leaves out Apple code signatures only (copies with codesign --remove-signature on every Mach-O, the DMG's koly signature blob zeroed); any other hit still fails; tests and docs
|
2026-10-14 08:21:35 +08:00 |
|
|
|
3a27c78f49
|
storebound 0.8.3: prompts read stdin with rt.readLine (node:readline) instead of Bun-only for await (const line of console), which crashed npx storebound desktop on Node/Windows; node-compat test bans Bun-only stdin iteration; Node prompt smoke, also on the Windows release runner
|
2026-10-14 08:07:40 +08:00 |
|
|
|
c3fed8efa2
|
storebound 0.8.3: version in package.json and every copy, CHANGELOG 0.8.3 section (docs: no private account names in the published package)
|
2026-10-14 07:54:56 +08:00 |
|
|
|
2e32377a0d
|
storebound 0.8.2: version in package.json and every copy, CHANGELOG 0.8.2 section with the release summary; site teaser cache key v=7
|
2026-10-14 06:32:32 +08:00 |
|
|
|
b211e3e410
|
teaser v9 final with the new reject shot: 1920x1080 master, web version and posters from the end card; site teaser and poster (cache key v=6), README poster
|
2026-10-14 06:10:39 +08:00 |
|
|
|
1f27bfbeed
|
tests copy the demo app as git has it: the example's gitignored .storebound/, renders, frames and video of a local checkout stay out of the temp copy (edit.test.ts failed on a local .storebound/, the boot check's store art case opened a local ios69 render instead of its pulled Play shot)
|
2026-10-14 06:10:39 +08:00 |
|
|
|
658807b219
|
tests/teaser: the stamp check back in the safe-margin test (typecheck)
|
2026-10-14 05:49:15 +08:00 |
|
|
|
49557b4c74
|
teaser: no text overflows anywhere: teaser.textCheck(t) checks every visible text node (scroll size within its element, its box inside its card, every card in frame as drawn), render.ts --animatic runs it at every frame of the whole teaser into animatic-checks.json and tests/teaser.test.ts requires zero problems; reject titles shortened ('No demo account', 'Manifest refused'); fixes it found: terminal and pile rows wrap instead of being cut with an ellipsis, the scan findings wrap, the pile shows only the rows that fit whole (no streaming past the edge), caption, edge word, labels and end card line heights fit their glyphs, builds and products push straight in so the terminal stays in frame
|
2026-10-14 05:47:42 +08:00 |
|
|
|
20a764b3ee
|
teaser: the reject shot redone (7-11 s, 4 s): the common rejections storebound catches as real scan finding cards landing one per beat (2.1(a) demo account, 5.1.1(v) account deletion, 5.1.2(i) ATT from tests/fixtures/scan/teaser; ITMS-91064 from the new teaser-manifest fixture), guideline + one plain line each, then our own REJECTED stamp hits the stack on the beat at 9.5 s, no shake (one 4 px 1-frame jolt), a 3% push, the picture darkens into the cut; caption 'Rejected. Again.'; later shots +1.5 s (42.5 s, every cut on a beat, music follows the scenes, a thud per card and a hit on the stamp); render.ts --animatic --range a,b and --sheet a,b,fps, and the reject cards' boxes per frame in animatic-checks.json; tests: real finding lines, beat timing, and every card inside 6% safe margins at every frame
|
2026-10-14 05:47:42 +08:00 |
|
|
|
511716bfd5
|
desktop boot check: the Store art tab's live thumbnails are read on demand (art live), so its 'Live store art not read yet' is not a missed background read
|
2026-10-14 05:35:59 +08:00 |
|
|
|
d1159313ac
|
teaser: render.ts --scale 2, the 3840x2160 master for 4K uploads (same page at device scale 2, desktop frames captured at @3x into out/desktop@3x, demo game renders at 2x into out/assets@2x, H.264 high about 40 Mbps, AAC 320 kbps, +faststart; no web version); desktop.ts captureDesktop takes a scale and an output folder
|
2026-10-14 05:31:31 +08:00 |
|
|
|
8a0a05dca2
|
onboard subscription-level test runs without the art step (--no-art, as the other onboard tests since art pull)
|
2026-10-14 05:31:02 +08:00 |
|
|
|
5ad3c0002d
|
onboard never writes duplicate subscription levels: the App Store groupLevel when it is set and unique in the group, else a stable order (App Store level, higher price per month = higher level, longer period, id) with a note per derived level; assignLevels in cli/lib/onboard.ts, tests with a live-shape App Store group (groupLevel 2 and 1) and Play-only / tied cases
|
2026-10-14 05:30:15 +08:00 |
|
|
|
346bf61166
|
pitfalls dry-run guard: cli/lib/git-ignore.ts's dry branch returns the planned .gitignore line (the plan, printed by its callers), allowed with the reason
|
2026-10-14 05:26:14 +08:00 |
|
|
|
fb3a7c186b
|
pulled store art never goes into the app repo: art pull --write, init and onboard add the renders folder (relative to the repo root, e.g. /store/renders/) to the repo's .gitignore when git check-ignore says it is not ignored yet, with one line saying so; tests
|
2026-10-14 05:25:37 +08:00 |
|
|
|
81915651bd
|
tests: art_pull in the local-write tools, art_live / art_thumb in the store-only reads, onboard tests without the art step
|
2026-10-14 05:25:37 +08:00 |
|
|
|
00be838b76
|
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
|
2026-10-14 05:25:37 +08:00 |
|
|
|
49a73c90e4
|
bun run ci defers the browser suites and the desktop boot check to Forgejo CI when the 1-minute load is above 2x the cores (deferBrowser in tools/ci-plan.ts, said at the start and in the summary); CI=full forces them, Forgejo runs CI=full
|
2026-10-14 05:24:38 +08:00 |
|
|
|
918146d4a6
|
CI green on a loaded shared machine: browser suites (now also glyph-ligatures and feature-fit, through the shared launch helper) in one dedicated shard started first at concurrency 2; timeouts scaled by load ÷ cores (tests/helpers/load.ts, max(1-, 5-min average), capped at 5x, logged) for browser tests, waits, launch/close, the other shards' default and the desktop boot check; one retry for a browser test that timed out while the factor was above 2, listed as 'retried under load' in the CI summary, never for an assertion failure; the six-type App Privacy walk no longer dumps every step (the --debug-dump check walks two types), wait timeouts print per-line times; play-edit-lock checks reads in flight instead of wall time; tests/load-retry.test.ts
|
2026-10-14 05:21:15 +08:00 |
|
|
|
21fa91afd1
|
onboard reads review access from the live App Store version (READY_FOR_SALE / READY_FOR_DISTRIBUTION, newest live first; the newest version only when nothing is live): a newer draft's empty review detail no longer hides the live demo account or turns signInRequired off; reviewVersion in cli/lib/onboard.ts, tests with a live version holding a demo account and a newer draft without
|
2026-10-14 02:08:39 +08:00 |
|
|
|
0c4689a81b
|
teaser v9 final: music reworked for the tight cut (drives from frame 0, an accent on every cut, tension in the pile and the rejection, a short drop into the request, layers building through the montage, the stop on Submit, the resolve on Waiting for review, a confident end under the card fading over the last 1 s; -16 LUFS, true peak <= -1.5 dBTP); 1920x1080 master, web version and posters from the end card; site teaser and poster (cache key v=5), README poster
|
2026-10-14 01:05:24 +08:00 |
|
|
|
c608b9f63e
|
teaser v9 animatic: 41 s story cut tight (hard cuts on the beat, 2-4 s shots, frame 0 moving, every shot opens on its subject, captions <= 6 words held >= 2 s, end card with npx storebound init held 4 s); render.ts --animatic (960x540 draft with sound, contact sheet, shot list, end-card layout checks); tests for the v9 timing rules
|
2026-10-14 01:05:24 +08:00 |
|
|
|
7ac028421a
|
store-only apps edit their listing on the store (storebound listing live / set: old -> new per field with the checks, a PATCH of only the edited fields; serve listing.set is the one store-only write, its token bound to the store ids; policy.rs STORE_ONLY_WRITES, write_with_confirm for store targets); screenshot captions per language and scene edited as a text edit of the shots copy JSON (JSON files keep their layout); Play content rating, target audience and App content answers in App info; docs/console-parity.md after the editors (73 rows: 55 complete, 18 with the reason) and tests/console-parity.test.ts keeping it honest
|
2026-10-14 00:54:56 +08:00 |
|
|
|
3cea2af4e1
|
desktop editors: edit in place what App Store Connect and Play Console let the owner edit (listings per language for both stores with live counters and the check / scan rules, store details, App info, age rating, App Review, Play store settings, Data safety and App Privacy answers, promotion blocks, catalog names / prices / offers, TestFlight information, scene order); storebound edit (project.edit) saves into the config by path keeping comments and formatting, the listing files and the review contact, dry run with the diff and the checks first; Apply shows each store's dry run in the window; unsaved edits survive tab switches with undo / redo; tests/edit.test.ts, apps/desktop/tests/edits.test.ts, boot check editor case
|
2026-10-14 00:37:08 +08:00 |
|
|
|
714352ec18
|
Play edits under a machine-wide per-package lock (parallel reads of one app no longer delete each other's edits; a read whose edit was deleted is redone once, writes are not); a store that failed to read is 'Couldn't read Google Play' and keeps its last good releases with 'couldn't refresh'; stores on different versions: neutral 'Current · Play x · App Store y' header and each lane its own state, 'Not on this store' only without a record; Play status decided from the public store page's live version (Live / In review / In review (live: x) / managed publishing / Rolling out / Halted / Draft; only a network failure says 'Couldn't check the store page', with the last known answer and its time); tests/play-edit-lock.test.ts, recorded page fixture, boot check auto-read cases (pitfall 58)
|
2026-10-14 00:26:17 +08:00 |
|
|
|
e59f439101
|
docs/console-parity.md: audit of every App Store Connect and Play Console field storebound reads or writes against the desktop (view, edit in place, store write), with the gaps
|
2026-10-14 00:09:54 +08:00 |
|
|
|
7b05e4b396
|
auto-read after the rebase: results through usable / failureText, issuesError notice kept, scheduler 'accounts' (no credentials word in the webview), fixtures and generated tables for health_issue
|
2026-10-13 23:41:36 +08:00 |
|
|
|
0fb4ce0001
|
desktop reads everything by itself: one background read scheduler (4 per store, starts spaced per account, App Store Connect X-Rate-Limit slows it below 20 % and pauses at 100 left, backoff with jitter on 429 / RESOURCE_EXHAUSTED, visible app first, one read per key), per-method TTLs over the saved reads, Settings auto-read (on) and interval (15 min, paused while hidden), Refresh all, a refresh icon and 'read 3 min ago' / 'couldn't refresh' per card, writes invalidate, status line with progress and quota; quota reaches the window through ToolResult.quota (cli/lib/quota.ts); Health top issues open with versions, sample stack (health --issue / --signature, read health_issue), Open in Play Console, Copy for AI and likely-cause hints (cli/lib/crash-hints.ts); tests/scheduler.test.ts, tests/quota-crash-hints.test.ts, boot check auto-read case
|
2026-10-13 23:37:39 +08:00 |
|
|
|
89256f1e80
|
Google API errors as typed findings, never raw JSON: cli/lib/google-errors.ts parses SERVICE_DISABLED (api-disabled: service, Cloud project, console page), PERMISSION_DENIED (no-app-access: which app, Users and permissions), 401 / invalid_grant (auth-revoked) and 429 (quota); health / analytics print one line with the URL, raw text in detail and the log; desktop Health tab: the line, 'Turn it on in Google Cloud' and 'Check again', raw text in a collapsed Details; Portfolio shows a Cloud project blocking several apps once. Findings exit codes are results: the sidecar reports outcome (ok / findings / declined / failed) and the command's own error line; scan / check / validate / health exit 1 with findings show and cache the findings; no bare 'Exit code N' anywhere. tests/google-errors.test.ts, boot check errors cases (api-disabled, scan-findings, scan-failed) (pitfall 57)
|
2026-10-13 23:20:04 +08:00 |
|
|
|
f69c10d3a0
|
tests: serve portfolio.status play fixture carries the public store page (200)
|
2026-10-13 20:48:01 +08:00 |
|
|
|
88a37e4735
|
tests: unique package names for the public page cache test (the temp-folder cache outlives a run)
|
2026-10-13 20:47:22 +08:00 |
|
|
|
be9ff8b788
|
Play 'Live' only when the public store page proves it: play status checks https://play.google.com/store/apps/details?id=<pkg> (no auth, 4 s timeout, cached 5 min; publicPage in the JSON), a completed production release with a 404 page is 'Sent to Google (in review or not yet published)', 200 is live for the first release or when the page shows the versionName, otherwise 'Released to production (Google may still be reviewing)', offline is unknown; new phases sent / released in the desktop Releases tab, Portfolio, release status | plan; versions matched across the stores without trailing .0 parts (App Store 1.0 and Play 1.0.0 are one row and one train, each side shows its own string); tests/play-public-version-match.test.ts, desktop boot check release-state cases (page 404 and 200) (pitfall 56)
|
2026-10-13 20:46:48 +08:00 |
|
|
|
aa72204a06
|
site: the highlighted download card keeps its own text colour for the details line (grey on the accent fill was unreadable); style.css cache key
|
2026-10-13 10:12:12 +08:00 |
|
|
|
6b91cc58a9
|
storebound 0.8.1: version in package.json and every copy, CHANGELOG 0.8.1 section with the release summary
|
2026-10-13 09:59:18 +08:00 |
|
|
|
19d34286d5
|
Feature graphic fits the phone: shots.feature.fit 'contain' (default) sizes the device so its rotated box stays inside 1024x500 with a 24 px margin in both templates, 'bleed' keeps the crop, scale 0.5-1.5, config validated; shots render records measured device boxes (report.json devices) and shots check fails a feature graphic whose device leaves the canvas (warns for a screenshot's front device off a side or the top); tests/feature-fit.test.ts (rotated-box geometry, both templates rendered at 1024x500, bleeding fixture) (pitfall 55)
|
2026-10-13 09:50:15 +08:00 |
|
|
|
6e2dbf03cc
|
site: main.js cache key 20261013b so Cloudflare serves the per-OS signing notice
|
2026-10-13 09:48:04 +08:00 |
|