diff --git a/.claude/skills/README.md b/.claude/skills/README.md index 5cfcb822..d146bea6 100644 --- a/.claude/skills/README.md +++ b/.claude/skills/README.md @@ -17,4 +17,4 @@ These skills are opinionated about safety and never: run a package manager or `n Dependency installation and `npm run init` require consent. The init skill uses the declared dependencies; Composer's install hook already runs npm. Sibling dependency checkouts are maintainer work. After file changes, refresh the local graph with `graphify update .`. -Cleanup removes the Copilot-specific files under `.github` (`copilot-instructions.md`, `prompts/`, `instructions/`); issue templates, the PR template, `dependabot.yml`, `release.yml`, and workflows stay. `sync-ai` restores only generated framework instructions. The Claude skills remain. Review these removals before personalizing a clone. +Cleanup removes the Copilot-specific files under `.github` (`copilot-instructions.md`, `prompts/`, `instructions/`) and the starter's own repository files (`.gitattributes`, `CODEOWNERS`, the bug and feature issue forms and their `config.yml`, `labels.yml`, `SECURITY.md`); the `task` and `epic` issue templates, the PR template, `dependabot.yml`, and workflows stay. `sync-ai` restores only generated framework instructions. The Claude skills remain. Review these removals before personalizing a clone. diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..7d7c4599 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,15 @@ +# Starter-only files: theme-elementary's own repository settings, which must +# not reach a theme created from the starter. `composer create-project` +# installs the Packagist dist archive, and export-ignore leaves these out of +# it. For a git clone, `npm run init` removes the same files (cleanup.targets +# in bin/scaffold.config.js); keep the two lists in step. +/.gitattributes export-ignore +/.github/CODEOWNERS export-ignore +/.github/ISSUE_TEMPLATE/bug.yml export-ignore +/.github/ISSUE_TEMPLATE/config.yml export-ignore +/.github/ISSUE_TEMPLATE/feature.yml export-ignore +/.github/labels.yml export-ignore +/SECURITY.md export-ignore +/.github/release-starter export-ignore +/.github/workflows/release-starter.yml export-ignore +/tests/js/starter-files.test.js export-ignore diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..6a7b89b9 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @aryanjasala @AnuragVasanwala @Adi-ty diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md deleted file mode 100644 index 4bc8afb5..00000000 --- a/.github/ISSUE_TEMPLATE/bug.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -name: Bug Report -about: There is a bug in functionality that needs to be fixed. -title: '' -labels: '' -assignees: '' - ---- - -## Description - - - -## Steps to Reproduce - - - -## Screenshots - - - -## Additional Information - - diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 00000000..c257dbd0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,128 @@ +name: Bug report +description: Something in the theme-elementary starter is broken or behaves unexpectedly. +type: Bug +labels: + - "Type: Bug" +body: + - type: markdown + attributes: + value: >- + Thanks for reporting a bug. Please search + [existing issues](https://github.com/rtCamp/theme-elementary/issues?q=is%3Aissue) + first. Bugs in the framework belong in + [wp-primitives](https://github.com/rtCamp/wp-primitives/issues), and + bugs in `npm run init` or `npx wp-tooling` in + [wp-tooling](https://github.com/rtCamp/wp-tooling/issues). + - type: markdown + attributes: + value: >- + **Found a security issue?** Do not open a public issue. Report it + privately through + [GitHub's vulnerability reporting](https://github.com/rtCamp/theme-elementary/security/advisories/new), + as [SECURITY.md](https://github.com/rtCamp/theme-elementary/blob/main/SECURITY.md) + describes. + - type: input + id: starter-version + attributes: + label: Starter version or commit + description: >- + The release you started from (`composer create-project` prints it) or, + if you cloned `main`, the commit SHA. + placeholder: 2.0.0, or a1b2c3d + validations: + required: true + - type: dropdown + id: where + attributes: + label: Where does it happen? + options: + - In the starter itself, before `npm run init` + - In a theme created from the starter, after `npm run init` + - During `composer create-project` or `npm run init` + validations: + required: true + - type: dropdown + id: area + attributes: + label: Area + options: + - "Init and setup (npm run init, bin/scaffold.config.js)" + - "Templates, parts, patterns and theme.json" + - "Assets and build (src/, blocks, webpack, HMR, Tailwind)" + - "PHP (inc/ and its wp-primitives wiring)" + - "Tests and lint (PHPUnit, Jest, PHPCS, PHPStan, ESLint, Stylelint)" + - "CI workflows" + - Documentation + - Not sure + validations: + required: false + - type: input + id: wp-version + attributes: + label: WordPress version + placeholder: "6.8" + validations: + required: true + - type: input + id: php-version + attributes: + label: PHP version + placeholder: "8.3" + validations: + required: true + - type: input + id: node-version + attributes: + label: Node version + description: The output of `node --version`. The starter expects the version in `.nvmrc`. + placeholder: v22.22.2 + validations: + required: true + - type: input + id: environment + attributes: + label: Local environment + description: Where WordPress runs, if relevant. + placeholder: wp-env, VIP dev-env, Local, a remote host + validations: + required: false + - type: textarea + id: what-happened + attributes: + label: What happened? + description: The error or behaviour you saw. Screenshots help for front-end and editor bugs. + validations: + required: true + - type: textarea + id: expected + attributes: + label: What did you expect to happen? + validations: + required: true + - type: textarea + id: reproduce + attributes: + label: Steps to reproduce + placeholder: | + 1. composer create-project rtcamp/theme-elementary demo + 2. cd demo && npm run init -- --name="Demo" --yes + 3. ... + validations: + required: true + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Terminal output, PHP errors or browser console errors. Rendered as code, so no backticks are needed. + render: shell + validations: + required: false + - type: checkboxes + id: checks + attributes: + label: Before you submit + options: + - label: I searched the existing issues and this is not a duplicate. + required: true + - label: I removed secrets, keys and private URLs from everything above. + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..198943b9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Report a security vulnerability + url: https://github.com/rtCamp/theme-elementary/security/advisories/new + about: Report security issues privately, never in a public issue. See SECURITY.md. diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml new file mode 100644 index 00000000..ad340aec --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.yml @@ -0,0 +1,69 @@ +name: Feature request +description: Suggest something the theme-elementary starter should include or do. +type: Feature +labels: + - "Type: Feature" +body: + - type: markdown + attributes: + value: >- + Thanks for the suggestion. Please search + [existing issues](https://github.com/rtCamp/theme-elementary/issues?q=is%3Aissue) + first. + - type: markdown + attributes: + value: >- + Every theme created from this starter copies it, so additions should be + general enough for most projects. Framework behaviour belongs in + [wp-primitives](https://github.com/rtCamp/wp-primitives), the init and + scaffold engine in [wp-tooling](https://github.com/rtCamp/wp-tooling), + and CI jobs in + [wp-shared-workflows](https://github.com/rtCamp/wp-shared-workflows). + [CONTRIBUTING.md](https://github.com/rtCamp/theme-elementary/blob/main/CONTRIBUTING.md) + explains how to build it yourself. + - type: dropdown + id: area + attributes: + label: Area + options: + - "Init and setup (npm run init, bin/scaffold.config.js)" + - "Templates, parts, patterns and theme.json" + - "Assets and build (src/, blocks, webpack, HMR, Tailwind)" + - "PHP (inc/ and its wp-primitives wiring)" + - "Tests and lint (PHPUnit, Jest, PHPCS, PHPStan, ESLint, Stylelint)" + - "CI workflows" + - "AI tooling (AGENTS.md, Claude skills, Copilot prompts)" + - Documentation + - Not sure + validations: + required: true + - type: textarea + id: problem + attributes: + label: What problem does this solve? + description: What you are building on the starter, and what stops you today. + validations: + required: true + - type: textarea + id: proposal + attributes: + label: Proposed change + description: >- + What the starter should ship, and whether it should be always on, an + example set that init can remove, or an optional feature. + validations: + required: true + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + description: Workarounds you use now, or other designs you ruled out. + validations: + required: false + - type: checkboxes + id: checks + attributes: + label: Before you submit + options: + - label: I searched the existing issues and this is not a duplicate. + required: true diff --git a/.github/labels.yml b/.github/labels.yml new file mode 100644 index 00000000..d038a2cc --- /dev/null +++ b/.github/labels.yml @@ -0,0 +1,282 @@ +# Labels for rtCamp/theme-elementary. +# +# Labels are repository settings, not files, so adding an entry here does not +# create the label. A maintainer applies this list by running +# `gh label create --color --description --force` +# for each entry: missing labels are created and existing ones updated. That +# never deletes a label, so removing an entry here does not remove it on GitHub. +# +# The "Shared" sections are the same in all five rtCamp framework repositories +# (wp-shared-workflows, wp-primitives, wp-tooling, theme-elementary and +# plugin-elementary), apart from the wording of the BC descriptions; change them +# in all five together. The sections after them belong to this repository. +# release-please writes the release notes from pull request titles, so these +# labels are for triage only. + +# --- Shared: type ------------------------------------------------------------ +- name: "Type: Bug" + color: "D93F0B" + description: "Something is broken or behaves unexpectedly" +- name: "Type: Feature" + color: "A2EEEF" + description: "New capability or an improvement to an existing one" +- name: "Type: Task" + color: "0E8A16" + description: "Self-contained unit of work for a milestone" +- name: "Type: Chore" + color: "C5DEF5" + description: "Maintenance, tooling, docs, housekeeping" +- name: "Type: Epic" + color: "5319E7" + description: "Large initiative spanning multiple issues" +- name: "Type: Story" + color: "1D76DB" + description: "Group of related tasks within an epic" +- name: "Type: Docs" + color: "BFD4F2" + description: "Documentation-only change" + +# --- Shared: priority -------------------------------------------------------- +- name: "Priority: P0" + color: "B60205" + description: "Critical: blocks milestone" +- name: "Priority: P1" + color: "D93F0B" + description: "High: sprint commitment" +- name: "Priority: P2" + color: "FBCA04" + description: "Medium: nice to have this sprint" +- name: "Priority: P3" + color: "C2E0C6" + description: "Low: can slip" + +# --- Shared: status ---------------------------------------------------------- +- name: "Status: Blocked" + color: "E99695" + description: "Waiting on another issue or external dependency" +- name: "Status: Needs Review" + color: "FEF2C0" + description: "Human review requested" +- name: "Status: Rotating" + color: "D4C5F9" + description: "Engineer rotated out: awaiting pickup (see Handoff log)" +- name: "Status: Needs BC Check" + color: "F9D0C4" + description: "Run /check-bc before merge" + +# --- Shared: backward compatibility ------------------------------------------ +- name: "BC: Breaking" + color: "B60205" + description: "Breaking change: targets release/vNext" +- name: "BC: Additive" + color: "0E8A16" + description: "Additive only: safe for current major" +- name: "BC: Deprecation" + color: "FBCA04" + description: "Adds or removes a @deprecated symbol" + +# --- Shared: dependencies and outside contributors --------------------------- +- name: "dependencies" + color: "0366d6" + description: "Pull requests that update a dependency file" +- name: "good first issue" + color: "7057ff" + description: "Good for newcomers" +- name: "help wanted" + color: "008672" + description: "Extra attention is needed" + +# --- This repository: scope (proposed) --------------------------------------- +- name: "Scope: Init" + color: "0075CA" + description: "npm run init, bin/scaffold.config.js and starter cleanup" +- name: "Scope: Templates" + color: "0075CA" + description: "theme.json, templates/, parts/, patterns/ and styles/" +- name: "Scope: Assets" + color: "0075CA" + description: "src/ sources, blocks, webpack build, HMR and Tailwind" +- name: "Scope: PHP" + color: "0075CA" + description: "inc/ classes and their rtcamp/wp-primitives wiring" +- name: "Scope: CI" + color: "0075CA" + description: "Caller workflows for rtCamp/wp-shared-workflows" +- name: "Scope: AI Tooling" + color: "0075CA" + description: "AGENTS.md, Claude skills, Copilot prompts and graphify" +- name: "Scope: Docs" + color: "FEF2C0" + description: "Documentation" +- name: "Scope: Tests" + color: "BFDADC" + description: "PHPUnit and Jest suites" + +# --- This repository: legacy ------------------------------------------------- +# Legacy, keep until relabelled. These predate the shared set and are still +# on open and closed issues and pull requests; Dependabot also applies +# `GHA`, `NPM` and `Composer` (see .github/dependabot.yml). Remove an entry +# only after relabelling what carries it, and delete the label on GitHub by +# hand. The live `Dependencies` label is the same label as the shared +# `dependencies` above (GitHub label names are case-insensitive), so it is +# not listed twice: applying this file recolours it and keeps its name. +- name: "[Priority] High" + color: "F9D0C4" + description: "" +- name: "[Priority] Low" + color: "F9D0C4" + description: "" +- name: "[Priority] Medium" + color: "F9D0C4" + description: "" +- name: "[Status] Blocked" + color: "138562" + description: "" +- name: "[Status] On Hold" + color: "138562" + description: "" +- name: "[Type] Bug" + color: "D93F0B" + description: "It's a bug, needs a fix." +- name: "[Type] Enhancement" + color: "40667D" + description: "Enhancement done or needs to be done for an existing feature" +- name: "[Type] Epic" + color: "40667D" + description: "" +- name: "[Type] Feature" + color: "40667D" + description: "" +- name: "accessibility" + color: "c5def5" + description: "" +- name: "architecture" + color: "5319e7" + description: "" +- name: "Block-Patterns" + color: "7A3955" + description: "" +- name: "Build:Passing" + color: "ededed" + description: "" +- name: "ci" + color: "d93f0b" + description: "" +- name: "cli" + color: "fbca04" + description: "" +- name: "component-library" + color: "5319e7" + description: "" +- name: "components" + color: "0e8a16" + description: "" +- name: "Composer" + color: "FBCA04" + description: "" +- name: "css" + color: "5319e7" + description: "" +- name: "Documentation" + color: "C5DEF5" + description: "" +- name: "dx" + color: "e99695" + description: "" +- name: "eslint" + color: "5319e7" + description: "" +- name: "feature" + color: "84b6eb" + description: "" +- name: "fix" + color: "ee0701" + description: "" +- name: "frontend" + color: "0075ca" + description: "" +- name: "GHA" + color: "0052CC" + description: "" +- name: "github-actions" + color: "d93f0b" + description: "" +- name: "gutenberg" + color: "5319e7" + description: "" +- name: "initialization" + color: "C5DEF5" + description: "Project initialization and configuration" +- name: "internal" + color: "C5DEF5" + description: "Internal development and pilot procedures" +- name: "library" + color: "1d76db" + description: "" +- name: "local-development" + color: "C5DEF5" + description: "Local environment and daily development workflows" +- name: "maintainer" + color: "C5DEF5" + description: "Repository maintenance and release procedures" +- name: "NPM" + color: "D93F0B" + description: "" +- name: "onboarding" + color: "C5DEF5" + description: "Getting started and first-use workflows" +- name: "php" + color: "b60205" + description: "" +- name: "phpcs" + color: "5319e7" + description: "" +- name: "psr-4" + color: "b60205" + description: "" +- name: "quality" + color: "5319e7" + description: "" +- name: "refactor" + color: "bfd4f2" + description: "" +- name: "research" + color: "fbca04" + description: "" +- name: "scaffold" + color: "0e8a16" + description: "" +- name: "shared-package" + color: "f9d0c4" + description: "" +- name: "static-analysis" + color: "fef2c0" + description: "" +- name: "stylelint" + color: "5319e7" + description: "" +- name: "tailwind" + color: "0075ca" + description: "" +- name: "theme-elementary-v2" + color: "006b75" + description: "" +- name: "tooling" + color: "e4e669" + description: "" +- name: "vite" + color: "5319e7" + description: "" +- name: "webpack" + color: "5319e7" + description: "" + +# release-please adds "autorelease: pending" to its release pull request and +# finds the merged one to tag by it, then swaps it for "autorelease: tagged". +# Never delete these two, or a merged release may not get tagged. +- name: "autorelease: pending" + color: "ededed" + description: "release-please release PR, not tagged yet" +- name: "autorelease: tagged" + color: "ededed" + description: "release-please release PR, tagged" diff --git a/.github/release.yml b/.github/release.yml deleted file mode 100644 index 390bdc2b..00000000 --- a/.github/release.yml +++ /dev/null @@ -1,5 +0,0 @@ -changelog: - exclude: - authors: - - dependabot - - dependabot-preview diff --git a/README.md b/README.md index 8bcbd882..711caf0f 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ This theme ships AI-assisted setup and feature scaffolding, kept in step across - **Claude Code:** retained skills in [`.claude/skills/`](.claude/skills/) — `/init`, `/scaffold`, and `/setup`. - **GitHub Copilot:** `/init` and `/scaffold` prompts are available while setting up this source repository. - - Initialization removes the Copilot-specific files under `.github` (`copilot-instructions.md`, `prompts/`, `instructions/`); issue templates, the PR template, and workflows stay. + - Initialization removes the Copilot-specific files under `.github` (`copilot-instructions.md`, `prompts/`, `instructions/`) and the starter's own repository files, such as `CODEOWNERS`, the issue forms and `SECURITY.md`; the `task` and `epic` issue templates, the PR template, and workflows stay. - A committed knowledge graph in [`graphify-out/`](graphify-out/) lets AI assistants query the codebase's structure instead of reading it all; see [docs/internal/knowledge-graph.md](docs/internal/knowledge-graph.md) for how it's built and kept current. Shared conventions for all assistants live in [AGENTS.md](AGENTS.md). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..1846d485 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,32 @@ +# Security policy + +## Supported versions + +| Version | Supported | +|---|---| +| Latest 2.x release and `main` | Yes | +| 1.x | No further releases; start new themes from 2.x | + +Theme Elementary is a starter: a theme created from it is a copy, and it does +not update itself. A fix lands in the starter's next release, and the advisory +names the affected files so existing themes can apply it by hand. Code a +project adds after creating its theme belongs to that project's maintainers, +and issues in `rtcamp/wp-primitives` or `@rtcamp/wp-tooling` belong in those +repositories. + +## Reporting a vulnerability + +Please do not report security issues in public issues, pull requests or +discussions. + +Report them privately through GitHub instead: open the repository's +**Security** tab and choose **Report a vulnerability**, or go straight to +. The +report stays visible only to you and the maintainers, and the fix, the release +and the advisory are coordinated in that same thread. + +Include what you can of: + +- the affected file or feature, and the starter release or commit; +- the impact, and the conditions an attacker needs; +- steps or a minimal proof of concept that reproduce it. diff --git a/bin/scaffold.config.js b/bin/scaffold.config.js index 467dff24..85f8ddd2 100644 --- a/bin/scaffold.config.js +++ b/bin/scaffold.config.js @@ -12,6 +12,29 @@ const tailwindEntry = () => 'functions.php'; const tailwindConst = (api) => `${api.identity.constantPrefix}_ENABLE_TAILWIND`; +const fs = require('fs'); +const path = require('path'); + +// theme-elementary's own repository files, kept out of new projects. Cleanup also runs on +// --reinit, "Re-run full setup" and --clean, and a project's own CODEOWNERS, +// SECURITY.md, .gitattributes or issue forms live at these same paths, so they +// are removed on first setup only: before init writes .wp-scaffold.json. +// .gitattributes export-ignores the same paths; tests/js/starter-files.test.js +// keeps the two lists in step. +const STARTER_REPO_FILES = [ + 'tests/js/starter-files.test.js', + '.gitattributes', + '.github/CODEOWNERS', + '.github/ISSUE_TEMPLATE/bug.yml', + '.github/ISSUE_TEMPLATE/config.yml', + '.github/ISSUE_TEMPLATE/feature.yml', + '.github/labels.yml', + 'SECURITY.md', +]; +const firstSetup = !fs.existsSync( + path.join(__dirname, '..', '.wp-scaffold.json') +); + module.exports = { kind: 'theme', vendor: 'rtcamp', @@ -160,12 +183,17 @@ module.exports = { ], }, + // Starter-only files removed after setup. The repository files from + // `.gitattributes` down are theme-elementary's own; `.gitattributes` + // export-ignores them, so a `composer create-project` copy never has them + // and this only matters for a git clone. Keep both lists in step. cleanup: { targets: [ '.github/copilot-instructions.md', '.github/prompts', '.github/instructions', 'languages', + ...(firstSetup ? STARTER_REPO_FILES : []), // The starter's own release workflow, config and manifest. Cleanup also runs // on re-init and --clean, so both paths are named for the starter: a // project's own release-please files never live there. diff --git a/docs/initialization.md b/docs/initialization.md index e3f360e1..d2c637ae 100644 --- a/docs/initialization.md +++ b/docs/initialization.md @@ -60,7 +60,7 @@ npm run init -- --name="Acme Blog" --version=1.0.0 --yes --remove-examples | Optional features | HMR updates `.env.local`; Tailwind adds its entry/config and declarations. | | State | `.wp-scaffold.json` records identity and feature choices; do not hand-edit it. | | Autoload | Setup regenerates Composer's autoloader. | -| Cleanup | Before the wrapper's final sync, the Copilot-specific `.github` files (`copilot-instructions.md`, `prompts/`, `instructions/`) and `languages` (including the starter POT file) are removed, along with the starter's own release workflow, config and manifest (`.github/workflows/release-starter.yml`, `.github/release-starter/`). The other workflows, issue templates, the PR template, `dependabot.yml`, and `.github/release.yml` stay untouched. | +| Cleanup | Before the wrapper's final sync, the Copilot-specific `.github` files (`copilot-instructions.md`, `prompts/`, `instructions/`) and `languages` (including the starter POT file) are removed, with the starter's own repository files: `.gitattributes`, `.github/CODEOWNERS`, the bug and feature issue forms and their `config.yml`, `.github/labels.yml`, `SECURITY.md`, and its release workflow, config and manifest (`.github/workflows/release-starter.yml`, `.github/release-starter/`). A `composer create-project` copy never contains those repository files. The other workflows, the `task` and `epic` issue templates, the PR template, and `dependabot.yml` stay untouched. | | AI instructions | After a successful change, the wrapper runs `sync-ai`; in a standalone project with the framework installed, it refreshes the generated framework PHP instructions. It does not restore the removed prompts or theme-specific rules. | | Retained files | Theme source, `bin/`, Claude skills, documentation, and test infrastructure remain; files belonging to removed example sets do not. | diff --git a/docs/internal/maintenance.md b/docs/internal/maintenance.md index 079a16c8..f187759d 100644 --- a/docs/internal/maintenance.md +++ b/docs/internal/maintenance.md @@ -18,7 +18,7 @@ If an installation route or feature cannot be exercised, report the missing prer ### Cleanup checks -Check that the Copilot-specific `.github` files (`copilot-instructions.md`, `prompts/`, `instructions/`) and `languages` are removed, along with the starter's release workflow, config and manifest (`.github/workflows/release-starter.yml`, `.github/release-starter/`), while the other workflows, issue templates, and the PR template stay untouched. Also confirm the init wrapper script is not removed by cleanup, and that `sync-ai` (see [initialization.md](../initialization.md#what-changes)) restores only generated framework instructions. Claude skills and documentation remain; Copilot prompts and theme-specific GitHub rules do not. Run POT generation separately to verify the language output can be recreated. +Check that the Copilot-specific `.github` files (`copilot-instructions.md`, `prompts/`, `instructions/`) and `languages` are removed, along with the starter's own repository files (`.gitattributes`, `.github/CODEOWNERS`, the bug and feature issue forms and their `config.yml`, `.github/labels.yml`, `SECURITY.md`) and its release workflow, config and manifest (`.github/workflows/release-starter.yml`, `.github/release-starter/`), while the other workflows, the `task` and `epic` issue templates, and the PR template stay untouched. In a `composer create-project` copy, confirm those repository files were never there: `.gitattributes` export-ignores them, and its list must match `cleanup.targets` in `bin/scaffold.config.js`. Also confirm the init wrapper script is not removed by cleanup, and that `sync-ai` (see [initialization.md](../initialization.md#what-changes)) restores only generated framework instructions. Claude skills and documentation remain; Copilot prompts and theme-specific GitHub rules do not. Run POT generation separately to verify the language output can be recreated. Check references in retained documentation and AI instructions. Use upstream source links for optional examples or starter-only files that cleanup may remove. Do not silently change the cleanup contract as part of a documentation correction. diff --git a/tests/js/starter-files.test.js b/tests/js/starter-files.test.js new file mode 100644 index 00000000..591fe08e --- /dev/null +++ b/tests/js/starter-files.test.js @@ -0,0 +1,23 @@ +/** Keep the starter-only files out of every install route. */ +const fs = require('fs'); +const path = require('path'); + +const root = path.resolve(__dirname, '../..'); +// A theme made from the starter has run init, which removes .gitattributes and +// this test; skip there in case it was kept. +const inStarter = !fs.existsSync(path.join(root, '.wp-scaffold.json')); + +(inStarter ? describe : describe.skip)('starter-only files', () => { + test('every export-ignore path is also an init cleanup target', () => { + const ignored = fs + .readFileSync(path.join(root, '.gitattributes'), 'utf8') + .split('\n') + .map((line) => line.trim()) + .filter((line) => /\sexport-ignore$/.test(line)) + .map((line) => line.split(/\s+/)[0].replace(/^\//, '')); + const { cleanup } = require('../../bin/scaffold.config.js'); + + expect(ignored.length).toBeGreaterThan(0); + expect(cleanup.targets).toEqual(expect.arrayContaining(ignored)); + }); +});