feat(compat): Profile, Gates und Pods über den Kompatibilitätskern

Neu: Tier, Profile, Compatibility, CapabilityLocked, CapabilityGate, CompatibilityComponent, ProvidesCompatibility, DiviProfile sowie PodsFeature, PodsCompatibility und PodsIntegration. Das CapabilityGate sperrt gesperrte und unbekannte Fähigkeits-IDs (übernimmt die Sperre unbekannter IDs vom DiviFeatureGate) und delegiert nur Divi ausdrücklich. Pods-Schema, -Lesen, -Schreiben und -Feldrechte laufen über usable(PodsFeature::…); Schreiben verlangt FieldRead und FieldWrite, damit ein Rollback keine Werte verliert. lit-site-status meldet Pods über die CompatibilityComponent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-11-06 12:26:54 +01:00
co-authored by Claude Opus 5.5
parent b511ef6348
commit c85131603b
38 changed files with 2259 additions and 135 deletions
+33 -1
View File
@@ -5,6 +5,10 @@ declare(strict_types=1);
namespace LIT\MCP\Integrations;
use LIT\MCP\Abilities\Ability;
use LIT\MCP\Compatibility\Compatibility;
use LIT\MCP\Compatibility\Profile;
use LIT\MCP\Compatibility\ProvidesCompatibility;
use LogicException;
defined('ABSPATH') || exit;
@@ -17,6 +21,7 @@ final class IntegrationRegistry
private ?array $loaded = null;
private bool $booted = false;
private ?Compatibility $compatibility = null;
public function __construct(Integration ...$integrations)
{
@@ -63,7 +68,8 @@ final class IntegrationRegistry
}
/**
* Abilities of the available integrations, grouped by integration id (registry order).
* Abilities of the available integrations, grouped by integration id (registry order). An integration without
* abilities (Pods) is no group.
*
* @return array<string, list<Ability>>
*/
@@ -71,6 +77,9 @@ final class IntegrationRegistry
{
$groups = [];
foreach ($this->loaded() as [$integration, $own]) {
if ($own === []) {
continue;
}
$groups[$integration->id()] = array_merge($groups[$integration->id()] ?? [], $own);
}
@@ -101,6 +110,29 @@ final class IntegrationRegistry
return $labels;
}
/** @return list<Profile> Profiles of every registered integration that provides some, available or not. */
public function compatibilities(): array
{
$profiles = [];
foreach ($this->integrations as $integration) {
if ($integration instanceof ProvidesCompatibility) {
array_push($profiles, ...$integration->compatibilities());
}
}
return $profiles;
}
/**
* The compatibility state of all profiles, one shared instance (its matrices are memoised per request).
*
* @throws LogicException When two profiles or capabilities share an ID (a programming error, PluginTest).
*/
public function compatibility(): Compatibility
{
return $this->compatibility ??= new Compatibility($this->compatibilities());
}
/** @return list<string> Ids of all known integrations, available or not. */
public function ids(): array
{