feat(browse): add record command for video evidence of interactive bugs - #2497
Open
Topherhindman wants to merge 4 commits into
Open
feat(browse): add record command for video evidence of interactive bugs#2497Topherhindman wants to merge 4 commits into
record command for video evidence of interactive bugs#2497Topherhindman wants to merge 4 commits into
Conversation
launch(), recreateContext(), and recreateContext()'s clean-slate fallback each built their own BrowserContextOptions from the same manager fields. Every context-level setting has to be repeated in all three or it silently fails to survive a rebuild, and the three copies had already drifted in shape. Collapse them onto one builder so a new context option is added in one place. No behavior change: the resulting options are identical.
A screenshot proves what a page looked like; it cannot show what a page
did. Timing bugs — double-submit, loading flicker, focus jumping, a drag
that lands wrong — are the ones a developer most needs to see happen,
and they are exactly the ones a still frame loses.
Playwright records at the context level and flushes each page's .webm on
context close, so start and stop both route through recreateContext(),
which already preserves cookies, storage, and open tabs. Refs do not
survive that rebuild, so stop says so rather than leaving the caller to
find out on the next click.
Three things the reporting has to get right, because each one silently
costs the caller evidence they think they have:
- recreateContext() reports a degraded rebuild by return value, not by
throwing, and that rebuild is the flush. Dropping it would print
"Recording stopped" over a list of files while the caller's tabs had
just been reset, so start and stop both carry it out.
- stop reads the recording directory rather than the live pages. A tab
closed mid-recording still produced a video; enumerating open pages
would miss it. Files present before the recording began are excluded
so a reused directory does not re-report an earlier take.
- starting over an active recording reports the take it superseded.
That video is already on disk, and a caller who is not handed its
path has lost it.
handoff and connect leave the manager headed with the recording still
flagged, where recreateContext() refuses to run. The videos have already
flushed by then, so stop skips the rebuild there and hands them back
instead of raising.
record is control-scoped: it rebuilds the context out from under every
open tab, and it writes whatever is on screen — including anything typed
into a login form — to disk.
Covers when video beats a screenshot, that the context rebuild invalidates refs, and the limits: headless-only, control scope, stop before the daemon idles out, and a tab that never paints records nothing. BROWSER.md gains the command rows and lists record with the other context-recreation triggers.
Generated by bun run gen:skill-docs --host all.
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
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.
Why
A screenshot proves what a page looked like. It cannot show what a page did. The bugs that most need evidence are the ones in the timing — a double-submit that fires before React re-renders, a loading flicker, focus jumping, a drag that lands wrong — and those are exactly the ones a still frame loses.
browsealready owns a Chromium and Playwright already records video at the context level, so the primitive is a few lines from free. This adds it behind$Bso any skill (and any agent driving browse directly) can attach a repro clip instead of describing one.What
Headless only, control scope, defaults to a timestamped directory under
TEMP_DIR.Design notes
Context lifecycle. Recording is a
BrowserContextoption, so start and stop each go throughrecreateContext(), which already preserves cookies, storage, and open tabs. The first commit is a prerequisite refactor:launch(),recreateContext(), and its clean-slate fallback each built their ownBrowserContextOptionsfrom the same fields, so any context-level setting had to be written three times or it silently failed to survive a rebuild. They now share onebuildContextOptions(). That is a standalone improvement — the three copies had already drifted in shape — and it is what keepsrecordVideofrom becoming a fourth thing to remember in three places.Reporting is the hard part, not the recording. Three ways this can quietly cost the caller evidence they believe they have, all handled:
recreateContext()reports a degraded rebuild by return value, not by throwing — and that rebuild is the flush. Dropping it prints "Recording stopped" over a list of files at the same moment the caller's tabs were reset.startandstopboth carry it out.stopreads the recording directory, not the live pages. A tab closed mid-recording still produced a video; enumerating open pages misses it. Names present before the recording started are excluded, so reusing a directory across takes does not re-report the earlier one.Headed mode.
handoff/connectleave the manager headed with the recording flag still set, andrecreateContext()refuses to run there. The videos have already flushed by that point, sostopskips the rebuild and hands them back rather than raising.Scope.
recordsits inSCOPE_CONTROL, not meta: it rebuilds the context out from under every open tab (same blast radius asstate) and writes whatever is on screen — including anything typed into a login form — to disk. Read-only and write-scoped tokens cannot record; there is a test pinning that.Tests
browse/test/record.test.ts— 20 tests, ~12s, real browser against the local test server.Live capture asserts EBML magic bytes rather than "a file exists",
--sizeasserts the frame dimensions parsed out of the WebM header (no ffprobe dependency), and there is coverage for the closed-tab case, cookie survival across both rebuilds, the superseded take, a degraded flush, an unreadable directory, the headed path, directory reuse, path policy, and every argument error.Two of these are mutation-checked — dropping the size option from the context options, or discarding the flush warning, each turns the suite red.
Teardown
await bm.close()s the browser instead of callingprocess.exit, so running this file alongside the rest of the suite cannot truncate it.Verification
bun test— 19 failures, byte-identical to the count on a cleanmaincheckout on this machine (allgstack-gbrain-*,check-careful, and a livecodexCLI smoke; they need tooling I don't have installed). Zero failures in anything this branch touches.bun run buildclean;bun run gen:skill-docs --host all --dry-runreports no drift.record start→ navigate → CSS transition →record stopproduces a 43KB WebM, 800×450, valid EBML, and the frame extracted mid-clip shows the transition captured in progress.Notes for the maintainer
NEW_IN_VERSION['record']is set to1.62.0.0so the unknown-command hint works the moment this lands. Adjust if you cut a different version..webmon disk without printing the path. Both are documented in the skill rather than guessed at; happy to add a cap if you want one.This is a fresh implementation of the idea in #1483, written against the current context lifecycle. That PR is conflicted and its review points (hidden flush failures, videos from closed pages, the forced test-process exit) are addressed above with tests covering each. Closes #1483 if you prefer this one; credit to @itstimwhite for the original idea and for identifying
recordVideoas the right primitive.