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.

Datos de origen

Repositorio
Foundry376/Mailspring
Última actividad en el origen
7 de octubre de 2026 a las 19:01
Idioma detectado de SKILL.md
inglés
Estrellas
17.920
Forks
1055

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Explorador de archivos
5 archivos

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
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.
Ver en GitHub