From 0e73f95d3d83291290df4ae1c5424fc10f7dfe41 Mon Sep 17 00:00:00 2001 From: bidi Date: Wed, 5 Aug 2026 17:44:53 +0300 Subject: [PATCH] added dotkernel.com packages Signed-off-by: bidi --- .../skills/dotkernel-package-status/SKILL.md | 70 +++++++++++++ .claude/skills/dotkernel-packages/SKILL.md | 98 +++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 .claude/skills/dotkernel-package-status/SKILL.md create mode 100644 .claude/skills/dotkernel-packages/SKILL.md diff --git a/.claude/skills/dotkernel-package-status/SKILL.md b/.claude/skills/dotkernel-package-status/SKILL.md new file mode 100644 index 0000000..834e552 --- /dev/null +++ b/.claude/skills/dotkernel-package-status/SKILL.md @@ -0,0 +1,70 @@ +--- +name: dotkernel-package-status +description: Use when asked whether a Dotkernel package is still maintained, what a package does, which PHP versions it supports, whether it is safe for a new project, or what the state of the Dotkernel open-source portfolio is. + Answer from the published listing rather than from memory. +--- + +# Dotkernel package status + +Dotkernel publishes the support status of its open-source packages as a machine-readable listing, rebuilt daily from the GitHub organization. +Prefer it over recollection: lifecycle states change, and a package that was active at training time may be security-only now. + +- Data: +- Human-readable page: +- Site that publishes both, and the code that generates them: + +The listing is a product of the dotkernel.com site rather than of any single package, so nothing needs to be installed to use it and it works from any repository. +Report a wrong or stale entry against `dotkernel/dotkernel.com`, and a wrong lifecycle value against the package's own repository, which is where the `OSSMETADATA` file that declares it lives. + +## Shape + +```json +{ + "generated_at": "2026-08-05T10:14:45+00:00", + "org": "dotkernel", + "packages": [ + { + "name": "dot-cache", + "url": "https://github.com/dotkernel/dot-cache", + "description": "Dotkernel cache component", + "lifecycle": "active", + "php": "~8.3.0 || ~8.4.0", + "archived": false + } + ] +} +``` + +- `name` - the bare repository name. The Composer package is `dotkernel/`. +- `description` - the GitHub repository description; `null` when the repository has none. +- `lifecycle` - see below. +Values outside the four listed are possible and mean the repository declared something unrecognized; report it as undeclared rather than guessing. +- `php` - the `require.php` constraint from the package's `composer.json`, or `null` when it declares none or the file could not be read. +A `null` is missing data, not "any PHP version." +- `archived` - GitHub's own archived flag, which is independent of `lifecycle`. +A repository can be archived on GitHub while still declaring an older lifecycle, and the page surfaces that as a separate "Archived on GitHub" note. + +## What each lifecycle means for a consumer + +| Value | What to tell someone | +|-----------------|----------------------------------------------------------------------------------------------------| +| `active` | Actively developed, new features and fixes. Safe for a new project. | +| `maintenance` | Still supported, receiving fixes but no new features. Safe to stay on; expect no new capabilities. | +| `security-only` | Only security fixes are released. Plan an upgrade or replacement now. | +| `archived` | No longer maintained. Do not use in new projects; migrate existing ones. | + +## Answering well + +- Cite `generated_at`. +The listing is a daily snapshot, so say what it was current as of. +- Absence is not non-existence. +A repository is only listed when it carries an `OSSMETADATA` file declaring its lifecycle, and the site excludes non-package repositories (documentation, skeleton apps, the site itself). +If a name is missing, say it is not in the published package listing and check - do not say it does not exist. +- For "is X maintained?", lead with the lifecycle sentence above, then the PHP constraint if the question is about upgrading. +- For "what should I use instead?", the listing gives no successor field. +Say the package is archived or security-only and point at the GitHub `url` and the lifecycle page rather than inventing a replacement. +- If the fetch fails, say so. +Do not fall back to remembered status, which is exactly what this listing exists to replace. + +The JSON is served from the document root of dotkernel.com, so its URL tracks the deployed file name. +If the request 404s, load the human-readable page above and read the "View as JSON" link from it, or check the `dataFile` setting in `config/autoload/packages.global.php` in . diff --git a/.claude/skills/dotkernel-packages/SKILL.md b/.claude/skills/dotkernel-packages/SKILL.md new file mode 100644 index 0000000..8cda836 --- /dev/null +++ b/.claude/skills/dotkernel-packages/SKILL.md @@ -0,0 +1,98 @@ +--- +name: dotkernel-packages +description: Use when working on the Dotkernel packages OSS lifecycle page published at dotkernel.com and built from the dotkernel/dotkernel.com repository - regenerating the listing, adding or removing a package, changing what a card shows, adjusting ignoreRepos, or explaining a bin/generate-packages warning. +--- + +# Dotkernel packages lifecycle page + +The page lists Dotkernel's open-source packages with their support status. +It renders a pre-generated JSON file - the request path never calls GitHub. + +## Where this lives + +- Published page: +- Data file: +- Source repository: + +Every path below is relative to the root of `dotkernel/dotkernel.com`. +If the current working directory is a different project, the change belongs in that repository, not here - clone it or switch to that checkout before editing. + +## The pieces + +| Concern | Path in `dotkernel/dotkernel.com` | +|---------------------|---------------------------------------------------------------------------| +| Route | `src/App/src/RoutesDelegator.php` | +| Handler (read-only) | `src/App/src/Handler/GetPackagesViewHandler.php` | +| Template | `src/Blog/templates/page/dotkernel-packages-oss-lifecycle.html.twig` | +| Card styles | `src/App/assets/scss/components/_custom.scss` (`Package lifecycle cards`) | +| Generator | `src/App/src/Service/PackageGenerator.php` | +| GitHub transport | `src/App/src/Service/GitHubClient.php` | +| Config | `config/autoload/packages.global.php` | +| CLI entry point | `bin/generate-packages` | +| Data file | `public/dotkernel-packages.json` (gitignored) | + +Two rules follow from this split, and breaking either is the usual cause of a confusing result: + +- The handler only reads. +A change to the generator shows up on the page only after the data file is rebuilt. +- The data file is gitignored, so it does not travel with a deploy. +Production depends on the cron run. + +## How a repository gets onto the page + +A repository is a published package when it contains an `OSSMETADATA` file with an `osslifecycle` value. +That is the whole opt-in - no allow-list to edit: + +```text +osslifecycle=active +``` + +Recognized values, which are also the display order (`LIFECYCLE_ORDER`): `active`, `maintenance`, `security-only`, `archived`. +Anything else is kept, sorted last, and rendered with the muted `package-card--unknown` treatment. +Equal lifecycles sort by name. + +To keep a repository off the page, add its bare name (case-insensitive) to `ignoreRepos` in `config/autoload/packages.global.php`. + +Each entry in the data file is built from three sources: + +- `name`, `url`, `description`, `archived` - the `/orgs/{org}/repos` listing, so they cost no extra request. +- `lifecycle` - the repository's `OSSMETADATA`. +- `php` - `require.php` in the repository's `composer.json`; `null` when absent or unreadable. + +`description` and `php` are `null` for anything unusable rather than an empty string, and the template omits the element instead of rendering a blank one. + +## Regenerating + +From the root of a `dotkernel/dotkernel.com` checkout: + +```bash +php bin/generate-packages +``` + +Credentials live in `config/autoload/local.php` under the `github` key (`authBearer`, `userAgent`, `org`) - see `local.php.dist`. +Requests fall back to unauthenticated when no token is set, which works but hits a much lower rate limit. + +The run is deliberately conservative: it writes to a `.tmp` sibling and renames, and it aborts with exit code 1 if more than 20% of per-repository requests fail (`FAILURE_THRESHOLD`), leaving the previous listing in place. +A non-zero exit means the page keeps serving yesterday's data, which is the intended outcome. + +## Reading the output + +- `Skipped by ignoreRepos: …` - informational, those repositories were excluded on purpose. +- `WARNING: ignoreRepos entries matched nothing (renamed or deleted?)` - stale `ignoreRepos` entries. +Prune them, or a renamed repository silently reappears on the site. +- `WARNING: : could not read OSSMETADATA (…)` - the request failed and counts toward the 20% threshold. +The repository is left off this run. +- `WARNING: : OSSMETADATA present but no osslifecycle value found, skipped` - the file exists but has no parsable `osslifecycle=`; fix it in that repository. +- `WARNING: : could not read composer.json (…)` - costs the PHP badge constraint, not the package. + +## After changing anything in the page + +- Changed the payload shape? Rerun `php bin/generate-packages`, since the local data file predates the change. +- Touched the SCSS? +Run `npm run build` - `public/css/app.css` is tracked, so the compiled file must be committed with the source. +- Run `vendor/bin/phpunit`, `vendor/bin/phpcs`, `vendor/bin/phpstan analyse`. +Coverage lives in `test/Unit/App/Service/PackageGeneratorTest.php`, `test/Unit/App/Factory/PackageGeneratorFactoryTest.php`, and `test/Unit/App/Handler/GetPackagesViewHandlerTest.php`. +- Renaming the data file means updating `packages.global.php`, `.gitignore`, the "View as JSON" link in the template, and the fallback default in `src/App/src/Factory/PackageGeneratorFactory.php`. + +Do not add `dotkernel-packages-oss-lifecycle` to `routes.page` in `local.php`. +It has a dedicated handler routed in `RoutesDelegator`, and listing it again registers the path twice.