Skip to content

Latest commit

 

History

History
352 lines (282 loc) · 19.9 KB

File metadata and controls

352 lines (282 loc) · 19.9 KB

Webentor Stack AI Guide

This file is for AI coding agents working in webentor-stack.

Purpose

webentor-stack is the source of truth for shared Webentor packages and docs. The monorepo exists to keep versioning and integration changes coordinated.

Repository Map

  • packages/webentor-core: shared PHP + JS runtime package.
  • packages/webentor-configs: shared ESLint/Stylelint/Prettier/static config package.
  • packages/webentor-setup: shared setup runtime + setup CLI.
  • packages/webentor-codemods: reusable ast-grep codemods for migrating consumer theme code across webentor-core updates (npm-published; run via pnpm dlx).
  • packages/webentor-starter: pure project skeleton (WordPress/theme only; no setup scaffolding).
  • docs: VitePress documentation project.
  • test-site/: spin-up Bedrock E2E harness mirroring the starter, with webentor-core symlinked (see Testing Suite (E2E)).
  • tests/: Playwright E2E specs + fixtures that run against the provisioned test-site.

Non-Negotiable Boundaries

  • webentor-demo is not part of this monorepo; it is a separate integration-gate repository.
  • packages/webentor-setup and packages/webentor-starter are mirrored to standalone repositories.
  • In consumer projects, scripts/setup-core/ is added via git subtree add from a tagged webentor-setup release.
  • All other scaffolding under scripts/ and .webikon/ is generated by webentor-setup init.
  • Project-specific setup customizations must live in:
    • scripts/.env.setup
    • scripts/hooks/
    • scripts/project-specific/

Dependency Direction

Allowed direction:

  • webentor-starter -> webentor-core, webentor-configs, webentor-setup (as runtime copy/subtree output)
  • webentor-demo (external) -> released outputs from monorepo packages

Avoid reverse dependencies from shared packages back into starter/demo.

Setup Runtime Contract

packages/webentor-setup defines setup contract. The init command generates all scaffolding (.env.setup, setup.sh, hooks, project-specific, optionally ts-up.sh, and .webikon/project.json). Without flags it prompts interactively; with flags the corresponding prompts are skipped (useful for CI/AI). The starter contains no setup files — it is a pure project skeleton.

.webikon/project.json (schema v2) declares four required fields — schema_version, slug, stack, theme_path — plus the optional setup_cli_version, and nothing else. It carries exactly one version, that one, and no feature toggles; every other such fact is read from the artifact that owns it. The maintenance reporter (≥ 2.5.0) derives what is visible from a deployed site: theme Composer/pnpm locks for webentor-core and webentor-configs, root composer.json version for the starter release, WP_CONTENT_DIR for layout. stack is a closed enum (webentor-v2, webentor-v2-hybrid, webentor-v1, sage, classic); layout is never encoded in it. init is merge-aware — a hand-set stack survives re-runs, --stack <value> overrides it — and it deletes the retired v1 file at .webentor/project.json.

setup_cli_version is the one declared rather than derived version, and it exists for one reason: its artifact is scripts/setup-core/composer.json, and scripts/ is deploy-excluded, so a production host cannot read it — the JSON carries the value across the deploy boundary. The inclusion test is not just "must not be derivable": derivable in the repo is not derivable from a deployed site, and the reporter only ever sees the latter. init writes the field by mirroring that composer.json and never substitutes the running CLI's own version, so a project with no scripts/setup-core/ — a hybrid, a plain Sage or classic project, and the starter package itself — gets no field. Being declared, it is also the one field that can rot: webentor-setup doctor compares it against the artifact and exits 1 on mismatch, and webikon:update-webentor-packages-in-project BLOCKs, because a git subtree pull of setup-core is a two-part change. Readers prefer the artifact when readable and fall back to the declaration otherwise — so fix the declaration to match the artifact, never the reverse.

The SETUP_* toggles are not in the file and were dropped from the reporter and dashboard entirely: they also live under scripts/, they were always all-false in production, and nothing acted on them. They stay a checkout-only fact read from scripts/.env.setup. Do not re-add them anywhere.

If setup runtime behavior changes, update all of these together:

  1. runtime scripts (common.sh, helpers, platform scripts)
  2. CLI behavior (src/webentor-setup.php) — including init scaffolding generators
  3. docs/README contract text
  4. upgrade manifests in upgrades/<version>/manifest.json if migration behavior changes

Setup-Core Consumption Rule

In consumer projects:

  • scripts/setup-core/ is not in the starter — it is added via git subtree add from a tagged webentor-setup release.
  • scripts/setup.sh and all other scaffolding under scripts/ are generated by webentor-setup init.
  • Do not place project business logic in setup-core.
  • Do not put generated scaffolding files back into packages/webentor-starter.

When packages/webentor-setup changes, keep consumer runtime in sync intentionally.

Testing Suite (E2E)

test-site/ is a Bedrock install used to test blocks/runtime against a real WordPress site. pnpm test:setup provisions it; pnpm test:e2e runs the Playwright specs in tests/; pnpm test:teardown removes it. The site serves at http://webentor-test.test (admin admin/admin).

Linkage (this is the key mental model):

  • webentor-core is symlinked into the test-site for BOTH PHP (Composer path repo) and JS (pnpm link:). Edits to packages/webentor-core are picked up directly.
  • The theme is a copy, not a symlink — test-env-setup.sh rsyncs it from packages/webentor-starter/web/app/themes/webentor-theme-v2. Edit the starter source and re-run setup to re-sync, or edit the test-site copy directly while iterating (it is the source of truth that matters for a committed change).

Reflecting webentor-core changes in the running site:

  • PHP (Providers, hooks, block render, Blade views): live via the symlink — run wp acorn optimize:clear from test-site/ to flush Acorn's cached views/config/services.
  • JS / CSS (webentor-core ships TS/CSS source, no dist — it's bundled by Vite). There are TWO separate bundles, and which one to rebuild depends on what changed:
    • Block editor JS (block edit components, inspector controls, block toolbars, block registration) is compiled into webentor-core's OWN bundle (public/build, enqueued as webentor-core-editor-js). Rebuild with pnpm build in packages/webentor-core — the theme build does NOT recompile this. (block.json changes like apiVersion/supports are read server-side at registration, so they apply via the symlink without any JS rebuild.)
    • Theme-side JS/CSS (theme editor.ts, app.ts, app styles, anything importing @webikon/webentor-core/* helpers) is bundled by the test-site theme's Vite — rebuild with pnpm build (or pnpm dev for HMR) in the test-site theme.
    • When in doubt after editing webentor-core, rebuild both.

Operational gotchas:

  • Run on a specific PHP version (e.g. 8.4 / 8.5): herd isolate <ver> --site webentor-test (the site is linked as webentor-test though the directory is test-site, so --site is required). CLI provisioning runs composer/wp, which resolve php from PATH — to provision on a non-global PHP, prepend a php→target-binary shim to PATH.
  • Database: set DB_HOST in test-site/.env to the server over TCP (127.0.0.1) when its socket differs from the client default (e.g. DBngin listens on /tmp/mysql_3306.sock).
  • WP core version bumps: setup runs wp core update-db; without it the editor (and every editor-dependent test) is stuck on the "Database Update Required" screen.
  • E2E auth requires wps-hide-login to be inactive (it 404s wp-login.php); setup/tests expect the standard login path.
  • WP 7.0 iframed editor: the editor canvas is in an iframe, so block-editor specs must use frameLocator('[name="editor-canvas"]') for canvas selectors — top-frame selectors like .block-editor-writing-flow time out.
  • ACF Pro key (needed for pnpm test:setup): 1Password item "ACF PRO licence", Clients vault, in the notesPlain field. Goes into test-site/.env as PLUGIN_ACF_KEY; never commit .env.

Block-console checker: node scripts/check-blocks-console.mjs logs into the test-site, inserts every top-level webentor/* block into a published page, and reports editor + frontend console messages (block validation errors, deprecation notices). Use it to catch block-editor regressions.

Release and Rollout Order

Default order for coordinated releases:

  1. webentor-core and/or webentor-configs
  2. webentor-setup (including any upgrade recipe)
  3. webentor-starter
  4. webentor-demo bump/validation (external repo)

Shared release is not complete until demo CI is green.

Versioning Policy

  • Use independent semver per package; do not force shared version numbers across the monorepo.
  • On every release request, update docs/src/compatibility-matrix.md with the tested-together version set.

Release Workflow (Manual versioning, automated rollout)

Maintainers choose version bumps and write changelog entries manually — the committed version and changelog files are the source of truth. Everything after the merge is automated: publishing, tagging, and mirror splits react to what is committed on main.

Release preparation

  1. Decide the semver bump for each affected package.
  2. Run pnpm release:prep <pkg>=<x.y.z> [...] (pkg: core, configs, setup, codemods, starter, theme). It stamps every mirrored version source (per-package manifests + CHANGELOG entries) and inserts the compatibility-matrix row. Bump packages that release together in ONE invocation so the matrix gains a single row. On a starter bump it also refreshes packages/webentor-starter/composer.lock — Composer hashes version into the lock's content-hash, so stamping the manifest alone leaves the lock stale and CI's composer validate exits 2. That step needs composer on PATH; without it the script warns and you must run composer update --lock --no-install in the starter yourself.
  3. Replace the scaffolded TODO changelog line(s) with curated entries.
  4. Run pnpm check:versions (CI enforces the same check on every PR/push).
  5. Commit and push the release preparation through the normal review flow.

A starter release MUST bump packages/webentor-starter/composer.json version in the release commit. That value is load-bearing, not cosmetic: consumer projects inherit the manifest, and the maintenance reporter derives a site's starter release from its root composer.json version. Ship a starter release without the bump and every project it lands on reports a stale release until someone notices by hand. A starter release needs no metadata-file update — the only version .webikon/project.json declares is setup_cli_version, which tracks scripts/setup-core/composer.json, not the starter release. (A webentor-setup release does move it, but only in consumer projects that pull the setup-core subtree; the starter package ships no scripts/setup-core, so its own file has no such field.)

What happens on merge to main

release.yml runs automatically:

  1. scripts/check-versions.mjs — aborts if any mirrored version source drifted.

  2. scripts/publish-npm.mjs — publishes any npm package (core, configs, codemods) whose committed version is not on the registry yet.

  3. scripts/release-tags.sh — for every released package (core, configs, codemods, setup, starter; the theme ships inside the starter and has no tag of its own) ensures three things exist for the committed version:

    • the namespaced tag (core-v*, configs-v*, codemods-v*, setup-v*, starter-v*) if it does not exist yet;
    • a GitHub Release on that tag, titled with the package's canonical manifest name (@webikon/webentor-core@0.15.7, webikon/webentor-setup@1.1.0) and carrying that version's CHANGELOG section as its notes;
    • a split-workflow dispatch, for mirrored packages only:
      • core-v* -> split-webentor-core.yml (also pings Packagist)
      • setup-v* -> split-webentor-setup.yml
      • starter-v* -> split-webentor-starter.yml

    The tag and Release checks are independent: a version whose tag exists but whose Release is missing gets the Release backfilled on the next run. Split dispatch only fires for a freshly created tag, so mirrors are never re-pushed. Run with DRY_RUN=true to preview.

The Release title deliberately reproduces the @webikon/webentor-*@* scheme the changesets action used before it was removed, so the Releases page reads continuously across the migration even though the underlying tags use <ns>-v<version>.

No manual tag pushes are needed for a normal release. To re-run a mirror split manually, dispatch the split workflow with the tag as input, or push the tag by hand (git tag core-v0.9.14 && git push origin core-v0.9.14).

AI agent release instructions

When asked to release a package:

  1. Identify the affected package(s) and choose the correct bump level.
  2. Run pnpm release:prep with all packages releasing together.
  3. Replace the scaffolded TODO changelog line(s) with curated entries.
  4. Verify with pnpm check:versions and pnpm test-release.
  5. Commit and push through the normal review flow. Publishing and tagging happen automatically after the merge to main.

Version Source Map

Reference map for locating version sources per package.

  • webentor-core (beta, 0.x):
  • packages/webentor-core/package.json -> "version" (manual)
  • packages/webentor-core/composer.json -> "version" (manual; keep in sync with package.json)
  • packages/webentor-core/CHANGELOG.md -> add new entry at top (manual)
  • npm publish via the existing release workflow; Composer/Packagist via split-mirror + Packagist API ping
  • webentor-configs (stable, 1.x):
  • packages/webentor-configs/package.json -> "version" (manual)
  • packages/webentor-configs/CHANGELOG.md -> add new entry at top (manual)
  • npm publish via the existing release workflow
  • webentor-setup (stable, 1.x):
    • packages/webentor-setup/CHANGELOG.md -> add new entry at top (manual)
    • Runtime is mirrored via split workflow (no npm publish)
    • packages/webentor-setup/composer.json -> "version" (manual)
  • webentor-codemods (beta, 0.x):
    • packages/webentor-codemods/package.json -> "version" (manual)
    • packages/webentor-codemods/CHANGELOG.md -> add new entry at top (manual)
    • npm publish via the existing release workflow (no Composer mirror)
  • webentor-starter (stable, 2.x):
    • packages/webentor-starter/composer.json -> "version" (manual; the reporter derives a consumer site's starter release from this value, so it must be bumped in the release commit)
    • packages/webentor-starter/CHANGELOG.md -> add new entry at top (manual)
    • Runtime is mirrored via split workflow (no npm publish)
  • webentor-theme-v2 (stable, 2.x, inside starter):
    • packages/webentor-starter/web/app/themes/webentor-theme-v2/package.json -> "version" (manual)
    • packages/webentor-starter/web/app/themes/webentor-theme-v2/composer.json -> "version" (manual)
    • packages/webentor-starter/web/app/themes/webentor-theme-v2/style.css -> Version: header (manual)
    • packages/webentor-starter/web/app/themes/webentor-theme-v2/CHANGELOG.md -> add new entry at top (manual)
    • Keep all theme version sources synchronized in the same bump

pnpm release:prep edits all of these in one command; pnpm check:versions (and the versions CI job) fails on any mismatch, including the compatibility-matrix top row. The same check guards the starter's .webikon/project.json shape (schema v2, the four required keys plus the optional setup_cli_version, no unknown keys, known stack, resolvable theme_path, and setup_cli_version rejected outright since the starter ships no scripts/setup-core) and the starter root composer.json name/version — the metadata file itself holds no version baseline this repo could compare against.

Mirror Policy

Mirror targets and workflows:

  • packages/webentor-core -> .github/workflows/split-webentor-core.yml / scripts/split-webentor-core.sh (tag: core-v*)
  • packages/webentor-setup -> .github/workflows/split-webentor-setup.yml / scripts/split-webentor-setup.sh (tag: setup-v*)
  • packages/webentor-starter -> .github/workflows/split-webentor-starter.yml / scripts/split-webentor-starter.sh (tag: starter-v*)

The split-webentor-core.yml workflow also pings Packagist after mirroring to update the Composer package. Secrets required: PACKAGIST_USERNAME, PACKAGIST_API_TOKEN.

Do not introduce additional split mirrors unless explicitly requested.

AI Editing Rules

  • This is a PUBLIC repository. Never reference client / consumer projects in anything published here. When a fix originates from a bug reported on a specific consumer site, do NOT name that project, its domains (*.sk, .test), or any of its data (post titles, people's names, cities, CPT contents) in commit messages, PR titles/bodies, changelogs, code comments, or docs. Describe the bug and its reproduction generically (e.g. "picking three posts in a scrambled order"). Consumer-specific reproduction and verification stay in the consumer project's own private repo/notes.
  • Prefer minimal, contract-preserving edits.
  • Preserve comments that explain operational intent, especially in setup scripts.
  • Do not silently remove troubleshooting paths (1Password, env fallback, platform-specific behavior).
  • Keep file paths and command examples consistent with scripts/setup-core naming.
  • Avoid editing unrelated files in large migrations.
  • Always check and update documentation
  • Throwaway scripts and captured output (diagnostics, screenshots, scratch *.mjs) go in .artifacts/ (gitignored) — never commit them. Only durable, reusable tooling belongs in scripts/ (e.g. scripts/check-blocks-console.mjs, scripts/build-demo-page.mjs).

Validation Checklist for AI Changes

Before handoff, run relevant checks:

  • Shell syntax for setup scripts:
    • find packages/webentor-setup -type f -name '*.sh' -print0 | xargs -0 -n1 bash -n
  • Shell syntax for split mirror and release scripts:
    • bash -n scripts/split-webentor-setup.sh
    • bash -n scripts/split-webentor-starter.sh
    • bash -n scripts/release-tags.sh
  • Version source consistency: pnpm check:versions
  • Setup CLI syntax:
    • php -l packages/webentor-setup/src/webentor-setup.php
  • JSON validity for changed package.json or manifest files.
  • If starter touched, verify it contains no setup scaffolding (no scripts/, no retired .webentor/). The one metadata file it does ship is .webikon/project.json, whose shape pnpm check:versions enforces.
  • If blocks or webentor-core/theme runtime changed, validate against the test-site: pnpm test:setup (first run) then pnpm test:e2e; for block-editor changes also run node scripts/check-blocks-console.mjs (see Testing Suite (E2E)).

Common Mistakes to Avoid

  • Breaking 1Password .env fetch flow (OP_VAULT_ID + OP_ITEM_ID + env-valet).
  • Mixing project-specific hooks into setup-core.
  • Releasing package changes without considering demo compatibility.
  • Putting generated scaffolding files (.env.setup, setup.sh, hooks, etc.) back into packages/webentor-starter — the starter is a pure project skeleton.

Decision Rule

If uncertain whether a change belongs in shared runtime or project customization:

  • Put reusable behavior in packages/webentor-setup.
  • Put project-specific behavior in hooks/env files outside setup-core.