Skip to main content

app-screenshots

Capture screenshots of the running Mailspring dev app for docs, PRs, or visual verification — launching with a CDP port, driving the UI, anonymizing or seeding data, and clipping to an element. Use whenever a task needs a picture of the app.

Quellinformationen

Repository
Foundry376/Mailspring
Letzte Quellaktivität
7. Oktober 2026 um 19:01
Erkannte Sprache von SKILL.md
Englisch
Sterne
17.902
Forks
1.051

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
5 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
app-screenshots
description
Capture screenshots of the running Mailspring dev app for docs, PRs, or visual verification — launching with a CDP port, driving the UI, anonymizing or seeding data, and clipping to an element. Use whenever a task needs a picture of the app.
# Screenshots of the running app `screencapture` is blocked in this environment (no Screen Recording permission), and the app has no test-id hooks. The reliable path is Chrome DevTools Protocol against a dev build launched with a remote-debugging port. Everything below runs from the repo root unless noted. Scripts live in `.claude/skills/app-screenshots/scripts/`. ## 1. Launch Only one instance can run at a time, so check first. If one is running that you didn't start, it is probably the user's: ask before closing it. ```bash pgrep -fl "[Ee]lectron ./app" # anything listed will be closed by the next line pkill -f "[Ee]lectron ./app"; pkill -f "app/mailsync --mode sync"; sleep 2 (./node_modules/.bin/electron ./app --enable-logging --dev --remote-debugging-port=9333 > /tmp/app.log 2>&1 &) sleep 18 # window + plugins + first sync curl -s localhost:9333/json | grep -c webSocketDebuggerUrl # >0 means ready ``` - Always kill orphaned `mailsync` processes too; they outlive the Electron process and hold the SQLite DB open (a later seed script will silently fail to commit). - `location.reload()` does nothing in the renderer. Pick up renderer changes with `AppEnv.commands.dispatch('window:reload')`; main-process changes (`app/src/browser`) need a full relaunch. Edited LESS can be hot-loaded with `AppEnv.themes.reloadCoreStyles()`. - For doc-sized captures, shrink the window first: `AppEnv.getCurrentWindow().setSize(1280, 800)`. ## 2. Drive the UI `scripts/eval.mjs` evaluates JS in the main window (picks the target whose `document.body.className` contains `window-type-default`) and optionally captures the whole window or dispatches a real mouse click: ```bash node --experimental-websocket scripts/eval.mjs "<js>" [out.png] [clickX clickY] ``` Useful snippets inside the JS: - Navigate to a sheet: `$m.Actions.focusMailboxPerspective(new (require('../internal_packages/activity/lib/activity-mailbox-perspective').default)($m.FocusedPerspectiveStore.sidebarAccountIds()))` - Pick from a `DropdownMenu`: click `.dropdown-menu > div`, wait 300ms, then find the item by text under `.menu div` and dispatch `mousedown` **and** `click` on it. - Drive a controlled `<input>`: set the value through `Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set` and dispatch `input`; plain `.value =` doesn't reach React. - Test real selection/hover behaviour with the click args (`Input.dispatchMouseEvent`), not synthetic `el.click()` — the two differ for caret placement and `:hover`. - Wait after every action; the Reports tab has a 2s minimum "thinking" cover. ## 3. Capture an element `scripts/shoot.mjs` runs setup JS, then captures one element by selector using `Page.captureScreenshot` with a `clip` in CSS px: ```bash node --experimental-websocket scripts/shoot.mjs "<setup-js>" "<selector>" out.png [pad] [maxHeight] ``` - `scale: 1` already yields device pixels (2x on retina). Don't pass `scale: 2` — that produces 4x images. - Clip by element rect; don't crop afterwards with `sips -c`, which crops from the centre and pads with black. Use `maxHeight` to trim tall columns instead. - Connecting a CDP session blurs the window (`body.is-blurred`, greyed traffic lights). The script strips the class before capturing. - **Popovers close on blur.** Open the popover inside the same `setup-js` that the capture runs in, never in a previous invocation, and never call `activeElement.blur()` to remove the focus ring — inject a `<style>` with `outline: none !important` instead. ## 4. Make the data presentable ### Anonymize what's on screen The dev mailbox contains real correspondents. Before any capture that leaves the machine, rewrite the rendered DOM: `scripts/anonymize.example.js` walks every text node and `title` attribute and applies a regex map. Copy it, edit the map for the current mailbox, and pass its contents as the `setup-js` (after the view has loaded). - React splits text into separate nodes, so match whole-node values (`/^ben$/`) rather than phrases (`/ben opened/`). - Replace links with `example.com` paths and your own accounts with `you@gmail.com` / `you@yourcompany.com`; sidebar account headers are text nodes too. - Re-run the anonymizer after any action that re-renders (tab switch, dropdown). ### Seed the database when there's nothing to show `scripts/seed-tracking-metadata.py` writes fake open/click metadata onto real sent messages. Pattern for any similar seeding: 1. Stop the app **and** mailsync; `cp edgehill.db edgehill.db.bak-<reason>`. 2. Write both places the UI reads from — the model's JSON blob (`Message.data`, `metadata` array) and the join table (`ModelPluginMetadata`) that queries filter on. 3. Keep timestamps relative to the message's own date so "N days after sending" and relative times look sane. 4. Tell the user where the backup is; the DB is ~1GB. ### Stage a specific layout For illustrative shots (e.g. every kanban column populated) it's fine to move or clone rendered nodes with DOM APIs in the setup JS — but React will throw on its next re-render because its tree no longer matches. So: **take staged captures last**, one per launch, and relaunch before doing anything interactive again. A blank/"loading" view right after staging is that crash, not a product bug. ## 5. Review before shipping Read every PNG back (the Read tool renders images). Things that slipped past otherwise: focus rings, blurred title bars, un-anonymized names in a second text node, a broken `<img>` from a guessed asset path (copy an existing icon's resolved `src` and swap the filename), and letterboxed crops.
Auf GitHub ansehen