feat: tools and limits settings tabs

Adds Einstellungen → LIT MCP → Tools (direct/indirect/disabled per
ability, only ExposurePolicy-allowed modes offered) and → Limits
(upload size, log retention, snapshot count), wired into Plugin.php.

Ruling Q11b (carried from task 6): overview.md notes that direct
visibility is configurable; hints in src/ that name a tool which is
direct by default but can be switched to indirect (content-get,
content-query, content-types, post-publish, media-search) now use the
neutral "lit/<name> (direkt: lit-<name>)" form so they stay correct
after an admin override. lit/guide (always direct) and the
media-preview/-download DIRECT_ONLY tools are unaffected.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
2026-09-26 03:47:40 +02:00
co-authored by Claude Opus 5.5
parent eee1840411
commit bca35f6166
14 changed files with 330 additions and 22 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ final class MediaGuard
if (! $attachment instanceof WP_Post || $attachment->post_type !== 'attachment') {
return Errors::notFound(
sprintf('Medium %d nicht gefunden.', $attachmentId),
'ID prüfen; Medien über lit-media-search suchen.'
'ID prüfen; Medien über lit/media-search (direkt: lit-media-search) suchen.'
);
}
@@ -34,8 +34,8 @@ final class MediaUpdateAbility implements Ability
private const REASON = 'WordPress hat die Metadaten eines Mediums nicht gespeichert.';
private const REV_HINT = 'Die genannten Medien neu lesen (lit/media-get oder lit-media-search) und mit dem '
. 'aktuellen modified erneut senden.';
private const REV_HINT = 'Die genannten Medien neu lesen (lit/media-get oder lit/media-search, direkt: '
. 'lit-media-search) und mit dem aktuellen modified erneut senden.';
public function __construct(private ChangeLog $log, private MediaMetaWriter $writer = new MediaMetaWriter())
{
@@ -284,8 +284,9 @@ final class MediaUpdateAbility implements Ability
$cause,
$detail,
rolledBackHint: 'Das Zurücksetzen hat modified der Medien geändert: vor einem neuen Versuch die Medien '
. 'neu lesen (lit/media-get oder lit-media-search) und den Stapel mit dem aktuellen modified '
. 'senden; tritt der Fehler wieder auf, den Administrator informieren (Details im PHP-Error-Log).'
. 'neu lesen (lit/media-get oder lit/media-search, direkt: lit-media-search) und den Stapel mit '
. 'dem aktuellen modified senden; tritt der Fehler wieder auf, den Administrator informieren '
. '(Details im PHP-Error-Log).'
);
}
@@ -399,8 +400,8 @@ final class MediaUpdateAbility implements Ability
return match (count($codes) === 1 ? $codes[0] : 'mixed') {
'forbidden' => Errors::make('forbidden', $message, 'Nur Medien ändern, die das verbundene Konto '
. 'bearbeiten darf; die übrigen Einträge erneut senden.', 403, ['failures' => $failures]),
'not_found' => Errors::make('not_found', $message, 'IDs prüfen (lit-media-search) und die Einträge '
. 'korrigiert erneut senden.', 404, ['failures' => $failures]),
'not_found' => Errors::make('not_found', $message, 'IDs prüfen (lit/media-search, direkt: '
. 'lit-media-search) und die Einträge korrigiert erneut senden.', 404, ['failures' => $failures]),
'rev_mismatch' => Errors::make('rev_mismatch', $message, self::REV_HINT, 409, ['failures' => $failures]),
default => Errors::make('validation_failed', $message, 'Die unter failures genannten Einträge '
. 'korrigieren und den ganzen Stapel erneut senden.', 400, ['failures' => $failures]),
+3 -3
View File
@@ -88,8 +88,8 @@ final class PostGuard
(int) $post->ID
),
[$field => 'geplanter Zeitpunkt verstrichen'],
'Beim Nutzer nachfragen: jetzt veröffentlichen (lit-post-publish) oder neu planen (lit/post-schedule '
. 'über mcp-adapter-execute-ability); danach die Änderung wiederholen.'
'Beim Nutzer nachfragen: jetzt veröffentlichen (lit/post-publish, direkt: lit-post-publish) oder neu '
. 'planen (lit/post-schedule über mcp-adapter-execute-ability); danach die Änderung wiederholen.'
);
}
@@ -107,7 +107,7 @@ final class PostGuard
if (! is_object($object)) {
return Errors::notFound(
sprintf('Inhaltstyp "%s" ist nicht verfügbar.', $name),
'Verfügbare Inhaltstypen über lit-content-types abrufen.'
'Verfügbare Inhaltstypen über lit/content-types (direkt: lit-content-types) abrufen.'
);
}
@@ -289,8 +289,8 @@ final class PostReplaceWithCopyAbility implements Ability
$revisionId === null ? '–' : (string) $revisionId,
$backupId
),
'Den Aufruf nicht einfach wiederholen. Zuerst den Stand mit lit-content-get prüfen; Titel, Inhalt '
. 'und Auszug lassen sich mit lit/revision-restore (revision_id, über '
'Den Aufruf nicht einfach wiederholen. Zuerst den Stand mit lit/content-get (direkt: lit-content-get) '
. 'prüfen; Titel, Inhalt und Auszug lassen sich mit lit/revision-restore (revision_id, über '
. 'mcp-adapter-execute-ability) zurückholen, Felder/Meta und Begriffe stehen in der Sicherung '
. 'backup_id (in WordPress aus dem Papierkorb holen). Dem Nutzer Bescheid geben.',
$details
@@ -103,7 +103,7 @@ final class PostScheduleAbility implements Ability
return Errors::invalidInput(
'Der Zeitpunkt muss in der Zukunft liegen.',
['date' => 'liegt nicht in der Zukunft'],
'Zum sofortigen Veröffentlichen lit-post-publish verwenden.'
'Zum sofortigen Veröffentlichen lit/post-publish (direkt: lit-post-publish) verwenden.'
);
}
@@ -41,8 +41,8 @@ final class StatusWrite
$e,
'',
sprintf('Status von Eintrag %d ist möglicherweise schon geändert worden.', $postId),
'Den Aufruf nicht einfach wiederholen. Zuerst mit lit-content-get Status und Inhalt prüfen und dem '
. 'Nutzer Bescheid geben.'
'Den Aufruf nicht einfach wiederholen. Zuerst mit lit/content-get (direkt: lit-content-get) Status '
. 'und Inhalt prüfen und dem Nutzer Bescheid geben.'
);
}
}