The CLI could audit and repair what already existed, but adding furniture
present at a source was still only possible from the admin UI item by item. The
repo already ships every piece of that pipeline, so wire them together as
further steps of the same run:
- `--import-new` imports furniture the compared source has and this hotel lacks.
It reuses `getClonableClassnames` for the diff and `cloneSingleFurni` per item,
which downloads the icon and the bundle (sources serve `.nitro`, stored as
`.hab`), appends the furnidata entry with `deferFurniData` and creates the
catalog page plus the offer itself. Deferred entries are written in one
`appendFurniEntriesBulk` call, so 26000 items cost one JSON write, not one per
item. `--only`, `--limit` and `--concurrency` narrow/tune it, failures are
isolated per item and never abort the run.
- `--reconcile`, `--fix-sprite-ids` and `--rebuild-offers` run the existing
`reconcileFurniDataWithItemsBase`, `verifyAndFixSpriteIds` and
`rebuildCatalogOfferIds` passes — the post-import consistency work.
- `--align-ids` and `--rename-bundles` delegate to the existing standalone
scripts; both only report until `--apply` is given, matching their own
contracts.
- The menu grows options 6-8 plus a dry run, each with its own confirmation.
`--everything` turns on every repair + import step but deliberately leaves the
destructive ones off. A live dry run against Wibbo listed 26593 items on the
source that this hotel does not have, and Habbo (COM) reported 2871.
Updating the catalog was only possible from the admin "Catalog audit" page,
which streams `runCatalogAudit` over SSE and always compares against every
enabled clone source. This adds the same engine to the terminal so it can be run
by hand or from cron:
- `scripts/catalog-sync.ts` — CLI driver around `runCatalogAudit`. Prints the
live progress, the per-source "on the source but not in this hotel" counts and
a summary block; generated catalog SQL is saved to
`storage/catalog-sync/*.sql` (gitignored). Supports `--list-sources`,
`--sources=<a,b>`, `--icons`, `--nitros`, `--furnidata`, `--structure`,
`--check-ids`, `--sql`, `--apply-sql`, `--organize-sql`, `--all`, `--json` and
`--fail-on-errors`.
- `scripts/catalog-sync.sh` — interactive menu (`pnpm catalog:sync`). Lists the
configured sources (so the menu always matches `clone_sources`), lets Habbo
(COM) be taken with Enter, and offers audit-only through full repair +
applying the catalog SQL, each with a distinct confirmation. With no arguments
it needs a terminal; with any flag it passes straight through to the CLI.
- `runCatalogAudit` gains `sourceIds` to restrict which sites are compared;
omitting it keeps the previous "compare against everything enabled" behaviour.
An audit writes nothing, and `--apply-sql` is the only flag that changes the
catalog. Verified against the live DB: 16370 items_base rows, 16479 catalog
items, 2871 Habbo (COM) entries missing from this hotel.
The deploy gate ran e2e specs that depend on live content and data, so a missing
upload (the /help article images) or a legacy malformed avatar figure could turn
a safe code deploy red. Split the suites by what they actually guarantee:
- Blocking gate (`pnpm test:e2e`, `playwright.config.ts`): only checks the CMS
can guarantee itself — anonymous redirects, register form fields, the captcha
DOM contract and the cache-control headers (deterministic origin-direct).
- Advisory suite (`pnpm test:e2e:quality`, `playwright.quality.config.ts`):
broken images, layout overflow and warm-page latency, which depend on live
content/upload state and the host. It runs as a `continue-on-error` CI job
against the public site so a real content problem stays visible without
blocking the pipeline.
Also add `scripts/sync-readme-versions.mjs` (+ tests, docs and a CI check) so
the pinned versions in README.md can never drift from package.json / .nvmrc.