feat(preview): add flows config preview command - #14
Merged
Conversation
… plus reference script
…case output, leaner reference script
…ion, unprefixed gzip fragment, screens guard)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
flows config preview <config_file>: turns a local flow config into a render URL for the dashboard's/flow-previewroute. No API call, no--app, no browser automation.What changed
flows config preview <config_file>— reads a local JSON config, normalizes it, and builds the render URL. Flags:--screen,--device(defaultiphone-14),--orientation(portrait|landscape, defaultportrait),--json.lib/preview.ts— normalization + URL/fragment building. Accepts a dashboard-api envelope ({config, remote_configs, …}) or a bare builder config; both become{flow, remoteConfigs}.screensmust be an array, mirroring the render page's own payload guard, so a config the page would reject fails here with a message instead of rendering nothing.lib/app-url.ts— dashboard host fromADAPTY_APP_URL(defaulthttps://app.adapty.io). The/flow-previewpath is fixed; there is no URL flag.auth login— now rehosts the API-issued verification link ontoADAPTY_APP_URL, so pointing the CLI at a local or staging dashboard keeps the browser there. Only when the env var is set: the API serves that link fromauth.adapty.ioby default, and forcing the app host unconditionally would break production.Design
Fragment format —
#config=<base64url(gzip(utf8(json)))>, gzipped unconditionally, no prefix. Matches the render page's decoder, which compresses too, so there is no plain shape to mark it apart from. The payload keys stay camelCase ({flow, remoteConfigs}) because that object is a wire contract with the UI, unlike the CLI's own snake_case output.Output depends on where stdout goes, because the URL is far too long to read:
--json{render_url}, never opens a browserCapture is the caller's job. The CLI owns the fragment format (it must stay in lockstep with the page's decoder) but not screenshotting, so Playwright is not a dependency and no reference script ships here — that lives with the flow skill. Callers pipe the URL into whatever takes the shot:
adapty flows config preview flow.json --screen scr_abc | node capture.mjs --out shot.pngScope limit, documented in help and both docs
This is a quick-look escape hatch for small configs. Past roughly 32KB of pretty-printed JSON the render page becomes slow and unreliable — trim to the screen you are working on rather than throwing a whole flow at it.
Separately, the URL is long even when it renders fine (~113K characters for a 668KB flow), so it must never be printed or read; agents that let it land in their transcript burn context for zero information.
--help, the README callout andskills/adapty-cli/references/cli-commands.mdall say so, with the pipe form first and--url "$(…)"as the fallback for tools that want a flag.There is deliberately no file-based hand-off flag. An earlier
--payload-outemitted the payload to a file and the fragment in the URL, which repeated the whole config in output an agent has to read (227KB on a real flow). Verified since then: a 113KB fragment navigates and decodes fine in headless Chrome, and a pipe carries it with no size limit, so the flag was dropped rather than fixed.Testing
test/lib/preview.test.ts,test/lib/app-url.test.tsandtest/commands/flows-preview.test.tscover normalization (both input shapes, thescreensguard, malformed JSON), URL building (default and overridden host, fixed route, query params, screen omitted), the gzip fragment round-tripping byte-for-byte the way the page decodes it,auth loginlink rehosting with and without the env var, and the piped-vs---jsonoutput shapes — including a guard that the output never grows to twice the fragment, which is what caught the duplication above.Whole suite: 164 passing, lint and
check:agent-docsclean.🤖 Generated with Claude Code