Every file under src/ exits outside WordPress (defined('ABSPATH') ||
exit; after the use block, so a direct request no longer prints a fatal
error with the server path); divi-convert-fixture.php gets the WP_CLI
guard the other integration scripts have. A unit test keeps both true;
PSR1 side-effects warning excluded for the guard.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
80 lines
3.0 KiB
PHP
80 lines
3.0 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace LIT\MCP\Guides;
|
||
|
||
use LIT\MCP\Abilities\ExposurePolicy;
|
||
use LIT\MCP\Integrations\Integration;
|
||
use LIT\MCP\Integrations\IntegrationRegistry;
|
||
|
||
defined('ABSPATH') || exit;
|
||
|
||
/**
|
||
* Builds the short server instructions every MCP client loads on connect.
|
||
* Keep this text short: it occupies context in every conversation.
|
||
*/
|
||
final class InstructionsBuilder
|
||
{
|
||
/** @var (callable(): list<string>)|null */
|
||
private $postTypeNames;
|
||
|
||
private ExposurePolicy $policy;
|
||
|
||
public function __construct(
|
||
private IntegrationRegistry $registry,
|
||
?callable $postTypeNames = null,
|
||
?ExposurePolicy $policy = null
|
||
) {
|
||
$this->postTypeNames = $postTypeNames;
|
||
$this->policy = $policy ?? new ExposurePolicy();
|
||
}
|
||
|
||
public function build(): string
|
||
{
|
||
$active = implode(', ', array_map(
|
||
static fn (Integration $integration): string => $integration->id(),
|
||
$this->registry->available()
|
||
));
|
||
|
||
$directNames = array_map(
|
||
static fn (string $name): string => 'lit-' . substr($name, strlen('lit/')),
|
||
$this->policy->directNames($this->registry->abilities())
|
||
);
|
||
|
||
$lines = [
|
||
'LIT MCP pflegt diese WordPress-Website (Inhalte, Medien, Divi 5, Pods).',
|
||
'Aktive Integrationen: ' . $active . '.',
|
||
'Direkt aufrufbare Tools: ' . implode(', ', $directNames) . '.',
|
||
'Weitere Fähigkeiten über mcp-adapter-execute-ability (Ability-Name lit/<name>).',
|
||
];
|
||
|
||
if ($this->postTypeNames !== null) {
|
||
$lines[] = 'Inhaltstypen: ' . implode(', ', ($this->postTypeNames)())
|
||
. ' (Felder und Taxonomien: lit/content-types, direkt: lit-content-types).';
|
||
}
|
||
|
||
$divi = str_contains(', ' . $active . ',', ', divi,')
|
||
? [
|
||
'- Divi-Seiten: vor Änderungen lit-divi-outline und lit-divi-design-system lesen; Aufbau: lit-guide '
|
||
. 'topic "divi-structure".',
|
||
'- Divi-Änderungen verlangen die tree_rev aus lit-divi-outline bzw. der letzten Divi-Antwort '
|
||
. '(nicht rev).',
|
||
]
|
||
: [];
|
||
|
||
return implode("\n", array_merge($lines, [
|
||
'Regeln:',
|
||
'- Vor dem ersten Arbeitsschritt lit-guide (ohne Topic) aufrufen; Details je Thema über lit-guide '
|
||
. 'mit topic.',
|
||
'- Änderungen erzeugen native Divi-Module; Variablen und Presets vor festen Werten; Code-Modul nur, '
|
||
. 'wenn kein natives Modul passt.',
|
||
'- Den Status (Entwurf/veröffentlicht) nie ändern, außer der Nutzer verlangt es ausdrücklich; '
|
||
. 'neue Inhalte entstehen als Entwurf.',
|
||
'- Beim Bearbeiten immer den rev-Wert aus dem letzten Lesevorgang mitgeben (Pflicht).',
|
||
'- Löschen und Ersetzen erst nach Rückfrage beim Nutzer (confirm: true).',
|
||
'- Fehler enthalten einen hint – ihm folgen, statt blind zu wiederholen.',
|
||
], $divi));
|
||
}
|
||
}
|