LibrePortal/CLAUDE.md
librelad 60a2fc3b0b Add lp-task-names, a guard against unnamed task commands
Task titles come from one table whose final fallback returns the raw command
string, so a dispatched command with no matching row does not error — it just
renders as "libreportal instance remove bookstack_work" beside properly named
neighbours. That silence is why this kept being fixed and kept coming back.

The guard reads BOTH files as source — the command templates from
task-commands.js and the pattern table from tasks-format.js — so it fails on a
command added without a name rather than leaving it to be noticed in the UI.

Two checks, both from source rather than guessed from rendered text:

  1. Nothing falls through: a title equal to its command, or still starting with
     "libreportal ", means the raw fallback was reached.

  2. Every `libreportal app <verb>` verb has an actionMap entry. Without one the
     generic branch composes "<Verb> Application", which is how "Up Application"
     and "Down Application" shipped.

The second check reads the actionMap keys instead of pattern-matching the title,
which a first attempt did and which was wrong: "Reload Application" is both a
correct hand-written label and what the generic branch emits, so the rendered
text cannot distinguish them and the heuristic failed a title that was fine.

Verified by breaking it deliberately in both directions — adding a command with
no pattern, and deleting an actionMap verb. Each is caught, named, and pointed at
the file to edit; both files were restored byte-identical afterwards.

Lives in scripts/dev, which .gitattributes marks export-ignore, so it never ships
in a release tarball. Needs a node and borrows the running container's when the
host has none, the same constraint lp-shot works around for chromium.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 03:38:51 +01:00

2.7 KiB

LibrePortal — agent notes

Verify WebUI changes visually before marking them done

After changing anything user-visible in the WebUI (containers/libreportal/frontend/), confirm it actually renders correctly — syntax checks and type-correctness don't catch layout or visual regressions.

The maintainer's dev environment provides a headless screenshot helper, lp-shot, that captures a WebUI route (or a single element, via a trailing CSS selector) to a PNG for review:

lp-shot /admin/system                       # full route -> /tmp/webui-shot.png
lp-shot /admin/system /tmp/x.png 12 ".sys-strip"   # just one element, crisp

Use it (and read the PNG) to self-check UI work instead of assuming it looks right or asking the user to look. Skip it for purely backend/non-visual edits. If lp-shot isn't present, fall back to asking the user for a screenshot.

Every route except / is behind the WebUI login, and lp-shot handles that itself — it signs a one-hour session from the jwtSecret the backend stores in frontend/.auth.json, the same token /api/auth/login would issue. No password is involved (the stored one is a bcrypt hash). So no setup: just run it. Override with LP_SHOT_TOKEN, or LP_SHOT_USER+LP_SHOT_PASS, when shooting a remote instance. lp-shot --help lists the rest (LP_SHOT_URL, LP_SHOT_VIEWPORT, LP_SHOT_SCALE, …).

If a shot comes back as the boot splash, the page wasn't ready — lp-shot waits for #libreportal-loading-screen to leave the DOM, so a splash in the PNG means boot genuinely stalled. Read the page error: lines it prints to stderr.

Testing against the live WebUI means updating the running install, not just the repo: /libreportal-containers/libreportal/frontend/ is bind-mounted into the container, so copying changed files there (owned dockerinstall:dockerinstall) takes effect on the next browser load — no rebuild or restart. Diff before you copy; the live tree can hold changes the repo doesn't.

Check task names after adding a dispatched command

Task titles all come from one table in components/tasks/js/tasks-format.js, whose final fallback returns the raw command string. A command added to core/tasks/js/task-commands.js without a matching row does not error — it just renders as libreportal instance remove bookstack_work next to properly named neighbours like Bookstack - Create Backup. That silence is why bad titles kept coming back.

lp-task-names reads both files and fails if any dispatched command has no proper name:

scripts/dev/lp-task-names            # table of every command and its title
scripts/dev/lp-task-names --quiet    # failures only

Run it after touching either file. It needs a node and borrows the running container's if the host has none.