Zupulse Web Debug
All paths below are relative to the repository root unless absolute.
Host facts (demo:dev, locale, IndexedDB, file import, viewports): apps/web-demo/AGENTS.md.
Locators and deterministic journeys: apps/web-demo/e2e/library.spec.ts.
Product behavior: docs/features/contracts/ (not this skill).
Desktop Electron: zupulse-desktop-debug — do not merge the two skills.
When not to use
- Desktop shell, native dialogs, SQLite, recognition engines, or PDF OMR (Browser has no
#/pdf-omr).
- Unit tests or
pnpm demo:test:e2e journeys that already assert the same outcome.
- Reading code or Feature Contracts without driving the running app.
If a playbook's steps become stable assertions, add them to e2e/library.spec.ts and leave a one-line pointer here.
Driving modes
- Playwright driver (default for repro / screenshots / IndexedDB). Same JSON
cmd.mjs pattern as desktop-debug; Chromium profile under the workdir.
- In-app browser tools (light walkthrough). When the environment already exposes a browser against
http://127.0.0.1:5173, reuse pnpm demo:dev and exercise the journey there. Still follow apps/web-demo/AGENTS.md for locale, clean session, and viewports. Prefer the driver when you need clearSiteData, chooseFiles, dropFiles, downloadClick, or durable shots/ under tmp-run/.
Launch (driver)
- Ensure the demo is up: prefer an existing
pnpm demo:dev. If nothing answers on 5173, start it in the background and leave it running for reuse (do not kill a shared demo on cleanup).
- Choose a workdir under
tmp-run/<slug>/ (e.g. tmp-run/web-sample-import/). Put browser-profile/, shots/, downloads/, and cmd/res there. Do not use tasks/. tmp-run/ is gitignored.
- Start the driver (requires the demo already reachable):
W="$(pwd)/tmp-run/<slug>"
mkdir -p "$W"
# optional: WEB_DEBUG_LOCALE=zh-CN DEMO_URL=http://127.0.0.1:5173
nohup node .agents/skills/zupulse-web-debug/scripts/driver.mjs "$W" > "$W/driver.log" 2>&1 &
for i in $(seq 1 40); do [ -f "$W/driver.ready" ] && break; sleep 1; done
[ -f "$W/driver.ready" ] || { echo "driver failed to start"; cat "$W/driver.log"; exit 1; }
- Send commands:
node .agents/skills/zupulse-web-debug/scripts/cmd.mjs "$W" '{"action":"nav","hash":"/library"}'
- Cleanup (always):
kill "$(cat "$W/driver.pid")". Do not stop demo:dev unless this session started a dedicated server and the user wants it stopped.
driver.mjs <workdir> [baseURL] — baseURL defaults to DEMO_URL or http://127.0.0.1:5173. Chromium locale defaults to WEB_DEBUG_LOCALE or zh-CN (matches e2e copy). Ready signal is $W/driver.ready. Profile persists under $W/browser-profile/ across driver restarts.
Commands
JSON actions via cmd.mjs. Optional __timeout ms on any command (default 240s). Click/fill/select/chooseFiles/dropFiles/downloadClick fail when the locator matches 0 or 2+ nodes. Failed commands write shots/fail-<id>.png when the page is still open.
| Action |
Fields |
Notes |
shot / shotFull |
name |
PNG under $W/shots/ |
nav |
hash (/library or #/library) |
Waits until location.hash matches |
goto |
path or url |
Full navigation |
reload |
|
|
viewport |
width, height |
e.g. 390×844 or 1280×720 |
clickRole |
role, name, exact? |
Unique match required |
clickTestId |
testId |
Unique match required |
clickText |
text, exact? |
Unique match required |
selectOption |
combobox, value |
Unique combobox |
fill |
value, plus testId or role+name, exact? |
Unique match required |
press |
key, optional role+name, exact? |
Page-level if no role |
chooseFiles |
path or paths, plus testId or role+name |
Clicks control, sets filechooser files |
dropFiles |
files: [{path, name?}], plus testId or role+name |
DataTransfer drop (Browser-only) |
downloadClick |
saveAs?, plus testId or role+name, timeoutMs? |
Click + save under $W/downloads/ |
seedLocale |
locale (zh-CN | en-US | system) |
Writes zupulse-locale, then reloads |
seedTheme |
theme (light | dark) |
Writes zupulse-theme |
clearSiteData |
|
Clears storage + deletes zupulse-library |
bodyText |
|
First 6000 chars |
waitText / waitGone |
text, exact?, timeoutMs? |
At least one match |
wait |
ms |
Last resort |
eval |
js |
Page JS |
hash |
|
Full page.url() |
Playbook JSON is literal except <repo> (repository root) and <workdir> (the driver workdir). Default UI copy is zh-CN.
Playbooks
| When |
File |
| Clean empty Library; no PDF OMR entry |
references/playbooks/empty-library.md |
| Bundled sample import / export / delete |
references/playbooks/sample-import-export.md |
1---2name: zupulse-web-debug3description: Start or reuse the Zupulse Browser demo (apps/web-demo on http://127.0.0.1:5173) and drive it for manual UI verification, bug reproduction, and UX audits. Use when a task requires opening the local web demo, exercising Library/Viewer/Studio in Chromium, checking IndexedDB persistence or refresh recovery, taking screenshots at desktop or narrow viewports, or Browser-only import/drag-drop behavior. Do not use for Desktop Electron, PDF OMR, unit tests, or journeys already covered by pnpm demo:test:e2e unless investigating a failure those tests do not cover.4---56# Zupulse Web Debug78All paths below are relative to the repository root unless absolute.910Host facts (demo:dev, locale, IndexedDB, file import, viewports): `apps/web-demo/AGENTS.md`.11Locators and deterministic journeys: `apps/web-demo/e2e/library.spec.ts`.12Product behavior: `docs/features/contracts/` (not this skill).13Desktop Electron: `zupulse-desktop-debug` — do not merge the two skills.1415## When not to use1617- Desktop shell, native dialogs, SQLite, recognition engines, or PDF OMR (Browser has no `#/pdf-omr`).18- Unit tests or `pnpm demo:test:e2e` journeys that already assert the same outcome.19- Reading code or Feature Contracts without driving the running app.2021If a playbook's steps become stable assertions, add them to `e2e/library.spec.ts` and leave a one-line pointer here.2223## Driving modes24251. **Playwright driver (default for repro / screenshots / IndexedDB).** Same JSON `cmd.mjs` pattern as desktop-debug; Chromium profile under the workdir.262. **In-app browser tools (light walkthrough).** When the environment already exposes a browser against `http://127.0.0.1:5173`, reuse `pnpm demo:dev` and exercise the journey there. Still follow `apps/web-demo/AGENTS.md` for locale, clean session, and viewports. Prefer the driver when you need `clearSiteData`, `chooseFiles`, `dropFiles`, `downloadClick`, or durable `shots/` under `tmp-run/`.2728## Launch (driver)29301. Ensure the demo is up: prefer an existing `pnpm demo:dev`. If nothing answers on 5173, start it in the background and leave it running for reuse (do not kill a shared demo on cleanup).312. Choose a workdir under `tmp-run/<slug>/` (e.g. `tmp-run/web-sample-import/`). Put `browser-profile/`, `shots/`, `downloads/`, and cmd/res there. Do **not** use `tasks/`. `tmp-run/` is gitignored.323. Start the driver (requires the demo already reachable):3334```bash35W="$(pwd)/tmp-run/<slug>"36mkdir -p "$W"37# optional: WEB_DEBUG_LOCALE=zh-CN DEMO_URL=http://127.0.0.1:517338nohup node .agents/skills/zupulse-web-debug/scripts/driver.mjs "$W" > "$W/driver.log" 2>&1 &39for i in $(seq 1 40); do [ -f "$W/driver.ready" ] && break; sleep 1; done40[ -f "$W/driver.ready" ] || { echo "driver failed to start"; cat "$W/driver.log"; exit 1; }41```42434. Send commands:4445```bash46node .agents/skills/zupulse-web-debug/scripts/cmd.mjs "$W" '{"action":"nav","hash":"/library"}'47```48495. Cleanup (always): `kill "$(cat "$W/driver.pid")"`. Do **not** stop `demo:dev` unless this session started a dedicated server and the user wants it stopped.5051`driver.mjs <workdir> [baseURL]` — baseURL defaults to `DEMO_URL` or `http://127.0.0.1:5173`. Chromium locale defaults to `WEB_DEBUG_LOCALE` or `zh-CN` (matches e2e copy). Ready signal is `$W/driver.ready`. Profile persists under `$W/browser-profile/` across driver restarts.5253## Commands5455JSON actions via `cmd.mjs`. Optional `__timeout` ms on any command (default 240s). Click/fill/select/`chooseFiles`/`dropFiles`/`downloadClick` fail when the locator matches 0 or 2+ nodes. Failed commands write `shots/fail-<id>.png` when the page is still open.5657| Action | Fields | Notes |58| ----------------------- | ------------------------------------------------------------ | ------------------------------------------ |59| `shot` / `shotFull` | `name` | PNG under `$W/shots/` |60| `nav` | `hash` (`/library` or `#/library`) | Waits until `location.hash` matches |61| `goto` | `path` or `url` | Full navigation |62| `reload` | | |63| `viewport` | `width`, `height` | e.g. 390×844 or 1280×720 |64| `clickRole` | `role`, `name`, `exact?` | Unique match required |65| `clickTestId` | `testId` | Unique match required |66| `clickText` | `text`, `exact?` | Unique match required |67| `selectOption` | `combobox`, `value` | Unique combobox |68| `fill` | `value`, plus `testId` **or** `role`+`name`, `exact?` | Unique match required |69| `press` | `key`, optional `role`+`name`, `exact?` | Page-level if no role |70| `chooseFiles` | `path` or `paths`, plus `testId` **or** `role`+`name` | Clicks control, sets filechooser files |71| `dropFiles` | `files: [{path, name?}]`, plus `testId` **or** `role`+`name` | DataTransfer drop (Browser-only) |72| `downloadClick` | `saveAs?`, plus `testId` **or** `role`+`name`, `timeoutMs?` | Click + save under `$W/downloads/` |73| `seedLocale` | `locale` (`zh-CN` \| `en-US` \| `system`) | Writes `zupulse-locale`, then reloads |74| `seedTheme` | `theme` (`light` \| `dark`) | Writes `zupulse-theme` |75| `clearSiteData` | | Clears storage + deletes `zupulse-library` |76| `bodyText` | | First 6000 chars |77| `waitText` / `waitGone` | `text`, `exact?`, `timeoutMs?` | At least one match |78| `wait` | `ms` | Last resort |79| `eval` | `js` | Page JS |80| `hash` | | Full `page.url()` |8182Playbook JSON is literal except `<repo>` (repository root) and `<workdir>` (the driver workdir). Default UI copy is **zh-CN**.8384## Playbooks8586| When | File |87| --------------------------------------- | ---------------------------------------------- |88| Clean empty Library; no PDF OMR entry | `references/playbooks/empty-library.md` |89| Bundled sample import / export / delete | `references/playbooks/sample-import-export.md` |