From 35ea47d8328faa4796a3349400f02c982854f9c5 Mon Sep 17 00:00:00 2001 From: Jan-Niclas Loosen Date: Wed, 30 Sep 2026 03:19:31 +0200 Subject: [PATCH] chore: release 0.6.0 with Divi release gate, smoke test and acceptance notes Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/guides/overview.md | 8 ++ .../2026-09-30-divi-absicherung-abnahme.md | 15 +++ readme.txt | 13 +- src/Plugin.php | 2 +- tests/Integration/divi-release-smoke.sh | 114 ++++++++++++++++++ wp-lit-mcp.php | 2 +- 6 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 docs/superpowers/notes/2026-09-30-divi-absicherung-abnahme.md create mode 100755 tests/Integration/divi-release-smoke.sh diff --git a/docs/guides/overview.md b/docs/guides/overview.md index e974322..68e9b6f 100644 --- a/docs/guides/overview.md +++ b/docs/guides/overview.md @@ -62,3 +62,11 @@ Für den Einstieg liefert `lit-guide` mit dem Thema „all“ alle Themen in ein - Fehler: JSON mit `code` (z. B. `validation_failed`, `rev_mismatch`, `write_failed`, `partial_write`), `message`, `hint` (und ggf. `fields`). Dem `hint` folgen. - `confirm_required`: Nutzer fragen, dann mit `confirm: true` wiederholen. + +## Divi-Version nicht freigegeben + +Antwortet ein schreibendes Divi-Werkzeug mit `divi_untested`, ist die installierte Divi-Version für LIT MCP noch nicht +geprüft; bei `divi_incompatible` hat Divi Stellen geändert, die LIT MCP nutzt. In beiden Fällen wurde nichts +geändert. Lesende Divi-Werkzeuge funktionieren weiter und melden den Zustand in `warnings`; `lit-site-status` zeigt +ihn unter `components` → `divi` → `release`. Den Nutzer bitten, unter Einstellungen → LIT MCP → Divi die Prüfung +auszuführen und die Version freizugeben (`divi_untested`) bzw. LIT MCP zu aktualisieren (`divi_incompatible`). diff --git a/docs/superpowers/notes/2026-09-30-divi-absicherung-abnahme.md b/docs/superpowers/notes/2026-09-30-divi-absicherung-abnahme.md new file mode 100644 index 0000000..4a44158 --- /dev/null +++ b/docs/superpowers/notes/2026-09-30-divi-absicherung-abnahme.md @@ -0,0 +1,15 @@ +# Divi-Absicherung – manuelle Abnahme + +Stand 2026-09-30, Branch `divi-absicherung`, Version 0.6.0. + +1. Einstellungen → LIT MCP → Divi: Zustand „freigegeben – im Plugin als getestet hinterlegt“, Divi 5.2.1. +2. „Prüfung starten“: nach einigen Sekunden Hinweis „Divi-Prüfung abgeschlossen“, fünf ✓; unter Seiten keine + „[LIT MCP Prüfung]“-Seite, auch nicht im Papierkorb. +3. Ungetestete Version simulieren (nur lokal, nicht committen): in `src/Integrations/Divi/Release/DiviReleases.php` + `TESTED = []` setzen. Reiter zeigt „ungetestet“; ein MCP-Client bekommt beim Schreiben `divi_untested` mit dem + Hinweistext, beim Lesen den Hinweis in `warnings`. +4. „Prüfung starten“, dann „Divi 5.2.1 freigeben“: Zustand „freigegeben – auf dieser Website freigegeben am … von …“; + `lit-site-status` zeigt `release.source = database`; Protokoll zeigt den Eintrag `lit/divi-release`. +5. „Freigabe zurückziehen“: wieder „ungetestet“, Schreiben gesperrt, Protokoll-Eintrag. Danach `TESTED` zurücksetzen + (`git diff` leer). +6. Optional: eine vom Plugin geschriebene Seite im Visual Builder öffnen und speichern. diff --git a/readme.txt b/readme.txt index 3ad93a2..05f35ec 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: mcp, ai, divi, pods, oauth Requires at least: 6.9 Tested up to: 7.1 Requires PHP: 8.1 -Stable tag: 0.5.0 +Stable tag: 0.6.0 License: GPL-2.0-or-later License URI: https://www.gnu.org/licenses/gpl-2.0.html @@ -190,8 +190,19 @@ Die Änderung wirkt auf allen Seiten mit diesem Modul. LIT MCP speichert erst na betroffenen Seiten nennt, und einer ausdrücklichen Bestätigung (confirm); vorher entsteht eine Revision des Bibliothekseintrags. +== Divi-Freigabe == + +LIT MCP schreibt nur mit Divi-Versionen, die für diese Plugin-Version geprüft sind. Nach einem Divi-Update lesen die Divi-Werkzeuge weiter; schreibende Divi-Werkzeuge antworten mit „divi_untested“, bis ein Administrator unter Einstellungen → LIT MCP → Divi die Prüfung startet und die Version freigibt. Die Prüfung legt eine Entwurfsseite an, schreibt und rendert sie und löscht sie danach endgültig. Hat Divi Stellen geändert, die LIT MCP nachbildet, ist die Version „inkompatibel“ (divi_incompatible) – dann hilft nur ein Update von LIT MCP. Für Entwickler: `wp --user= lit-mcp divi-check [--diff] [--update-reference]`. + == Changelog == += 0.6.0 = +* Divi-Absicherung: Divi-Zugriffe gebündelt in Adaptern mit Manifest; Fingerabdrücke der nachgebildeten Divi-Funktionen. +* Ungetestete oder veränderte Divi-Versionen sperren alle schreibenden Divi-Wege (divi_untested / divi_incompatible); lesende Divi-Werkzeuge melden es in warnings. +* Neuer Reiter „Divi“: Prüfung mit Wegwerfseite, Freigabe nach grüner Prüfung, Freigabe zurückziehen. +* lit-site-status zeigt den Freigabe-Zustand (release). +* WP-CLI: wp lit-mcp divi-check mit --diff und --update-reference. + = 0.5.0 = * Divi Theme Builder: Vorlagen, Bedingungen und Layouts auflisten (lit/tb-list), Vorlagen mit Kopfzeile, Inhalt und Fußzeile anlegen – immer deaktiviert (lit/tb-create-template) –, Bedingungen setzen diff --git a/src/Plugin.php b/src/Plugin.php index be4c530..ffa69c9 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -51,7 +51,7 @@ defined('ABSPATH') || exit; */ final class Plugin { - public const VERSION = '0.5.0'; + public const VERSION = '0.6.0'; private static string $pluginFile = ''; private static ?SettingsPage $settingsPage = null; diff --git a/tests/Integration/divi-release-smoke.sh b/tests/Integration/divi-release-smoke.sh new file mode 100755 index 0000000..32baaf5 --- /dev/null +++ b/tests/Integration/divi-release-smoke.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash +# End-to-end checks of the Divi release gate (spec 2026-09-29-divi-absicherung). +# Runs INSIDE the DDEV web container (Divi 5.2.1 must be the active theme): +# cd /home/janniclas/Projekte/WordPress && timeout 900 ddev exec bash wp-content/plugins/WP-LIT-MCP/tests/Integration/divi-release-smoke.sh +# Leaves nothing behind: pages, the check report, the check lock, the state transient and the application password +# are removed again. +set -euo pipefail +cd /var/www/html +# shellcheck source=lib.sh +source wp-content/plugins/WP-LIT-MCP/tests/Integration/lib.sh + +ADMIN_LOGIN=$(wp user list --role=administrator --field=user_login | head -1) +CREATED_POSTS=() +BASE=http://localhost + +cleanup() { + for id in "${CREATED_POSTS[@]}"; do + wp post delete "$id" --force >/dev/null 2>&1 || true + done + wp option delete lit_mcp_divi_check_report lit_mcp_divi_check_lock >/dev/null 2>&1 || true + wp transient delete lit_mcp_divi_state >/dev/null 2>&1 || true + cleanup_app_passwords_for "$ADMIN_LOGIN" +} +trap 'rc=$?; cleanup; guard_exit "$rc" || exit $?' EXIT + +check_pages() { wp post list --post_type=page --post_status=any --meta_key=_lit_mcp_check_page --format=count; } + +[ "$(wp eval 'echo get_template();')" = "Divi" ] || fail "Divi must be the active theme" + +# 1. Code, registrations and fingerprints match Divi 5.2.1 +[ "$(wp eval 'echo wp_json_encode((new LIT\MCP\Integrations\Divi\DiviCompatibility())->problems());')" = "[]" ] \ + || fail "Divi compatibility problems under WP-CLI" +pass "manifests and fingerprints match the installed Divi" + +connect "$ADMIN_LOGIN" +STATUS=$(tool lit-site-status '{}') +echo "$STATUS" | jq -e '.components[] | select(.id == "divi") | .problems == [] and .release.state == "released" and .release.source == "code"' >/dev/null \ + || fail "site status must show Divi released from code: $STATUS" +pass "lit-site-status: Divi 5.2.1 released (code), no problems in an MCP request" + +# 2. Admin check through the REST route (application password instead of the cookie nonce). +# X-Forwarded-Proto: https is required here: without it the request to http://localhost with the +# site's own Host header never reaches the route (a 404 before any auth check even runs), the same +# header mcp-smoke.sh and tb-smoke.sh already send for their own curl calls against this DDEV site. +APP_PASSWORD=$(wp user application-password create "$ADMIN_LOGIN" lit-mcp-integration-test --porcelain) +HEADERS=$(curl -s -o /dev/null -D - -X POST -H "Host: $HOST" -H 'X-Forwarded-Proto: https' -u "$ADMIN_LOGIN:$APP_PASSWORD" "$BASE/wp-json/lit-mcp/v1/divi-check") +echo "$HEADERS" | grep -qi '^HTTP/[0-9.]* 303' || fail "check route must answer 303: $HEADERS" +echo "$HEADERS" | grep -qi '^location:.*tab=divi.*lit_mcp_notice=divi_checked' || fail "redirect to the tab: $HEADERS" +REPORT=$(wp option get lit_mcp_divi_check_report --format=json) +echo "$REPORT" | jq -e '[.steps[] | (.problems == [] and .skipped == false)] | all and length == 5' >/dev/null \ + || fail "every check step must be green: $REPORT" +[ "$(check_pages)" = "0" ] || fail "the throwaway page must be gone" +[ "$(wp option get lit_mcp_divi_check_lock 2>/dev/null || true)" = "" ] || fail "the check lock must be released" +pass "admin check (REST): five green steps, throwaway page deleted, lock released" + +UNAUTH=$(curl -s -o /dev/null -w '%{http_code}' -X POST -H "Host: $HOST" -H 'X-Forwarded-Proto: https' "$BASE/wp-json/lit-mcp/v1/divi-check") +[ "$UNAUTH" = "401" ] || [ "$UNAUTH" = "403" ] || fail "anonymous check must be refused, got $UNAUTH" +pass "check route refuses anonymous requests" + +# 3. Incompatible Divi (simulated: a failed fingerprint in the state cache) locks every write path +wp eval ' +$key = LIT\MCP\Integrations\Divi\Release\ReleaseResolver::stateKey((string) LIT\MCP\Integrations\Divi\Release\DiviEnvironment::version()); +set_transient(LIT\MCP\Integrations\Divi\Release\ReleaseResolver::CACHE, ["key" => $key, "problems" => ["Smoke: Nachbau geändert"]], 600);' + +PAGE_ID=$(wp --user="$ADMIN_LOGIN" post create --post_type=page --post_status=draft --post_title="LIT Freigabe Smoke" --porcelain) +CREATED_POSTS+=("$PAGE_ID") +wp post meta update "$PAGE_ID" _et_pb_use_builder on >/dev/null +wp post meta update "$PAGE_ID" _et_pb_use_divi_5 on >/dev/null +BEFORE=$(wp post get "$PAGE_ID" --field=post_content) + +OUTLINE=$(tool lit-divi-outline "{\"post_id\":$PAGE_ID}") +echo "$OUTLINE" | jq -e '.warnings | any(test("inkompatibel"))' >/dev/null || fail "read tool must carry the notice: $OUTLINE" +pass "reading Divi tool runs and warns" + +INSERT=$(tool lit-divi-insert "{\"post_id\":$PAGE_ID,\"tree_rev\":$(echo "$OUTLINE" | jq '.tree_rev'),\"nodes\":[{\"type\":\"section\",\"modules\":[{\"type\":\"text\",\"content\":\"

x

\"}]}]}") +echo "$INSERT" | jq -e '.__error | fromjson | .code == "divi_incompatible"' >/dev/null || fail "write must be refused: $INSERT" +[ "$(wp post get "$PAGE_ID" --field=post_content)" = "$BEFORE" ] || fail "nothing may be written" +pass "writing Divi tool refused with divi_incompatible, page unchanged" + +CREATE=$(tool lit-content-create '{"post_type":"page","title":"LIT Freigabe Smoke Neu","divi":[{"type":"section","modules":[{"type":"text","content":"

x

"}]}]}') +echo "$CREATE" | jq -e '.__error | fromjson | .code == "divi_incompatible"' >/dev/null || fail "content-create with divi must be refused: $CREATE" +[ "$(wp post list --post_type=page --post_status=any --title='LIT Freigabe Smoke Neu' --format=count)" = "0" ] \ + || fail "no draft may remain" +pass "lit-content-create with divi refused before a draft exists" + +STATUS=$(tool lit-site-status '{}') +echo "$STATUS" | jq -e '.components[] | select(.id == "divi") | .release.state == "incompatible"' >/dev/null \ + || fail "site status must show incompatible: $STATUS" +# wp db query --skip-column-names misreports this as a write query (it treats "insert" anywhere in the SQL, +# even inside a quoted value like 'lit/divi-insert', as an INSERT and prints "Rows affected" instead of the +# result) - wp eval with $wpdb->get_var() runs the same COUNT() reliably. +REFUSED_LOGGED=$(wp eval ' +global $wpdb; +echo (int) $wpdb->get_var($wpdb->prepare( + "SELECT COUNT(*) FROM {$wpdb->prefix}lit_mcp_log WHERE result = %s AND ability = %s", + "refused", + "lit/divi-insert" +));') +[ "$REFUSED_LOGGED" -ge 1 ] || fail "the refusal must be in the change log" +pass "site status incompatible, refusal logged" + +# 4. Back to released: writes work again +wp transient delete lit_mcp_divi_state >/dev/null +OUTLINE=$(tool lit-divi-outline "{\"post_id\":$PAGE_ID}") +INSERT=$(tool lit-divi-insert "{\"post_id\":$PAGE_ID,\"tree_rev\":$(echo "$OUTLINE" | jq '.tree_rev'),\"nodes\":[{\"type\":\"section\",\"modules\":[{\"type\":\"text\",\"content\":\"

x

\"}]}]}") +echo "$INSERT" | jq -e '.ok == true' >/dev/null || fail "write must work when released: $INSERT" +pass "released again: writing works" + +# 5. WP-CLI +wp --user="$ADMIN_LOGIN" lit-mcp divi-check >/dev/null || fail "wp lit-mcp divi-check must succeed" +[ "$(check_pages)" = "0" ] || fail "the CLI check must delete its page" +pass "wp lit-mcp divi-check is green and leaves no page" + +finish diff --git a/wp-lit-mcp.php b/wp-lit-mcp.php index ef21670..3d206d7 100644 --- a/wp-lit-mcp.php +++ b/wp-lit-mcp.php @@ -3,7 +3,7 @@ /** * Plugin Name: WP-LIT-MCP * Description: MCP-Server für WordPress, Divi 5 und Pods – mit OAuth für KI-Assistenten. - * Version: 0.5.0 + * Version: 0.6.0 * Requires at least: 6.9 * Requires PHP: 8.1 * Tested up to: 7.1