refactor: ToolAvailability ersetzt die sechs Referenz-Closures in Plugin (Frage vor der Verdrahtung wirft statt still false); DiviIntegration bekommt den Tools-Tab-Zustand als Objekt; Plugin::integrations() mit Verdrahtungstest für Reihenfolge, einmaliges Booten und spätes Binden

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-18 21:56:36 +02:00
co-authored by Claude Opus 5.5
parent 6c59934caa
commit e6e0f914ba
6 changed files with 376 additions and 109 deletions
+63
View File
@@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace LIT\MCP\Abilities;
use LIT\MCP\Integrations\IntegrationRegistry;
use LogicException;
defined('ABSPATH') || exit;
/**
* The Tools-tab state for integrations that gate their own tools on another group or tool (rulings P9, E9, audit
* M2/L5). Integrations get this object before the registry and the policy exist – both need the integrations –
* and ask it only at call time; Plugin binds it right after building them. A question before bind() is a wiring
* error and throws, instead of quietly answering false.
*/
final class ToolAvailability
{
private ?IntegrationRegistry $registry = null;
private ?ExposurePolicy $policy = null;
/** Called once by Plugin after the registry and the policy are built. */
public function bind(IntegrationRegistry $registry, ExposurePolicy $policy): void
{
if ($this->policy !== null) {
throw new LogicException('ToolAvailability is already bound.');
}
$this->registry = $registry;
$this->policy = $policy;
}
/** Whether $group is switched on at all (ExposurePolicy::groupEnabled()). */
public function groupEnabled(string $group): bool
{
return $this->policy()->groupEnabled($group);
}
/** Whether abilities of $group may write (ExposurePolicy::groupWritable()). */
public function groupWritable(string $group): bool
{
return $this->policy()->groupWritable($group);
}
/** Whether the ability named $ability is registered and not disabled (ExposurePolicy::allows()). */
public function allows(string $ability): bool
{
$policy = $this->policy();
return $policy->allows($ability, $this->registry()->abilities());
}
private function policy(): ExposurePolicy
{
return $this->policy ?? throw new LogicException('ToolAvailability asked before Plugin bound it.');
}
private function registry(): IntegrationRegistry
{
return $this->registry ?? throw new LogicException('ToolAvailability asked before Plugin bound it.');
}
}