Files
magpie/.github/ui-preview
yetone c91529f9aa ci: the UI preview scrolls to what a PR changes further down a page (owner: 录屏的时候,有时候需要录制的功能区需要滚动到下面才能看到,但是现在并不会滚动,导致录制的内容里完全没有 PR 所修改的功能) — the recorder reached an element with Playwright's scrollIntoViewIfNeeded, a scroll no reader asked for, which magpie puts back (scrollOnPurpose / backToReader in app.js), so the page stayed at its top; a shot's target was only a clip of the screen, never scrolled to, so a close-up of something below the fold showed the window's foot instead; and a scroll step turned the wheel wherever the mouse was. bringIntoView now wheels each view that hides the element, innermost first, in small notches with the drawn mouse over it, until it is in the middle (or at the top when taller): click, hover, type and a shot's target use it, and a scroll step takes "to" (a selector to bring into view). The planner's outlines mark elements past the fold of their view "(below the fold)" and its guide says a shot without a target shows only the screen. PLAN_FILE walks a given plan instead of asking DeepSeek. Tried against a sandbox magpie web with six providers and a fixed plan (a shot of Hermes Agent's models button, clicking it, scrolling to a Gateway row): the old recorder's close-up showed the list's foot without Hermes and its Gateway shot the page's top; the new one centres both, the menu opens at Hermes, and the video shows each scroll.
2026-10-03 15:18:01 +08:00
..
2026-10-03 15:18:01 +08:00

UI preview

.github/workflows/ui-preview.yml shows reviewers what a pull request does to the UI. When a PR touches internal/gui/assets/ or the GUI's Go code, or carries the ui-preview label, the workflow does this:

  1. publish.mjs detect decides whether the PR is a UI change. It puts a "recording…" note in a fixed block at the foot of the PR description, between <!-- magpie-ui-preview:begin --> and <!-- magpie-ui-preview:end -->.
  2. run.sh builds the PR's magpie (nogui) and runs magpie web in a fresh home, with DeepSeek added as a real provider. It sends a few requests through the gateway so Routing and Usage aren't empty, then runs:
  3. record.mjs, which:
    • gives DeepSeek the diff and outlines of the real pages;
    • has it plan scenes: what to click, hover, type and capture;
    • walks the plan in Chromium at 2x, with cursor.js drawing the pointer, its trail and each click. It always takes screenshots. When the change spans pages or needs interaction, it also records an mp4, never a GIF. If the key shows up on screen at any point, everything is thrown away.
  4. publish.mjs publish puts the files under pr-<n>/<sha>/ on the ui-previews branch, which GitHub Pages serves, and rewrites the block in the description:
    • the video's poster links to the player page, since GitHub won't embed a video it didn't host;
    • the screenshots are shown inline.

Security: the recording job runs the PR's code without asking anyone. Any PR's code can therefore read DEEPSEEK_API_KEY (environment ui-preview), so the key there should have a low spending limit. That job has no write access, and the job that writes never runs the PR's code.

To run it locally (run.sh builds and starts magpie itself):

cd .github/ui-preview && npm install && npx playwright install chromium
DEEPSEEK_API_KEY=… DIFF_FILE=pr.diff PR_TITLE=… ./run.sh ../.. /tmp/out

To re-run it for a PR, use gh workflow run ui-preview.yml -f pr=<n>.