feat(v3.12.0): media pipeline, AI image generation, capability probe, companion v2.9.0
Some checks failed
Release / Test before release (push) Has been cancelled
Release / Publish to PyPI (push) Has been cancelled
Release / Publish to Docker Hub (push) Has been cancelled
Release / Create GitHub Release (push) Has been cancelled

Three-month batch sync from internal repo (~80 commits) covering Tracks F.5a, F.7e, F.8, F.17, F.18, F.X.

WordPress media pipeline
- Pillow-based optimization, AI image generation (OpenAI / Stability / Replicate / Google Nano Banana / OpenRouter), chunked + resumable uploads, bulk delete/reassign, idempotent retries.

Capability discovery (F.7e)
- Per-site credential probe + adapters for WordPress / WooCommerce / Gitea, tier-fit unions granted ∪ roles, capability badge UI with HTMX partial re-check, install hint in every companion-unreachable error.

Companion plugin overhaul
- Renamed wordpress-plugin/airano-mcp-seo-bridge → wordpress-plugin/airano-mcp-bridge.
- Eight new endpoints: /capabilities, /bulk-meta, /export, /cache-purge, /transient-flush, /site-health, /audit-hook, /upload-and-attach.
- wp.org Plugin Check pass: i18n, WP_Filesystem, scheme allowlist on audit-hook URL.

Other
- Gitea ergonomics (F.17): batch files, tree, search, compare, releases, fork.
- Opportunistic bcrypt upgrade for legacy SHA-256 admin keys (F.8).
- n8n refactor: structured errors, capability probe, missing tools backfilled.
- Idempotency-Key dedup for AI media upload retries; WP client fast-fails on unreachable sites.

Docs
- README + CLAUDE.md drop the fixed "633 tools" claim. The total grows with each release; per-plugin approximations + dashboard-surfaced counts replace it.
- Tools/Tests badges removed in favour of "Plugins: 10".

Deployment
- PyPI mirror chain, optional BUILD_HTTP_PROXY, Alpine→Yandex apk mirror, Debian-slim Plan-B Dockerfile, mirror.gcr.io variant.

CI
- Black + Ruff clean on Python 3.12; pytest tests/ green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-25 16:25:58 +02:00
parent 788439e377
commit f203ca88de
140 changed files with 23802 additions and 2253 deletions

View File

@@ -0,0 +1,109 @@
"""F.18.4 — Cache purge via companion plugin.
Wraps ``POST /airano-mcp/v1/cache-purge`` (companion plugin v2.4.0+).
Auto-detects active cache plugins (LiteSpeed, WP Rocket, W3 Total Cache,
WP Super Cache, WP Fastest Cache, SiteGround Optimizer) and invokes
their purge API. Always flushes the WP object cache. Replaces the
previous Docker-socket + WP-CLI path on managed hosts.
Tool: ``wordpress_cache_purge()``
"""
from __future__ import annotations
import json
import logging
from typing import Any
from plugins.wordpress.client import WordPressClient
from plugins.wordpress.handlers._companion_hint import (
companion_install_hint as _companion_install_hint,
)
logger = logging.getLogger("mcphub.wordpress.cache_purge")
def get_tool_specifications() -> list[dict[str, Any]]:
return [
{
"name": "cache_purge",
"method_name": "cache_purge",
"description": (
"Purge all caches on the WordPress site via the "
"airano-mcp-bridge companion plugin (v2.4.0+). Auto-detects "
"active cache plugins (LiteSpeed, WP Rocket, W3 Total Cache, "
"WP Super Cache, WP Fastest Cache, SiteGround Optimizer) and "
"calls each one's purge API. Always flushes the object cache. "
"Requires manage_options on the calling application password."
),
"schema": {"type": "object", "properties": {}},
"scope": "admin",
}
]
class CachePurgeHandler:
"""Cache purge via companion plugin."""
def __init__(self, client: WordPressClient) -> None:
self.client = client
async def cache_purge(self) -> str:
try:
payload = await self.client.post(
"airano-mcp/v1/cache-purge",
json_data={},
use_custom_namespace=True,
)
except Exception as exc: # noqa: BLE001
logger.error("cache_purge companion call failed: %s", exc)
return json.dumps(
{
"ok": False,
"error": "companion_unreachable",
"message": str(exc),
"hint": (
"Requires airano-mcp-bridge companion plugin v2.4.0+ "
"and manage_options capability. Run "
"wordpress_probe_capabilities to verify."
),
"install_hint": _companion_install_hint(
min_version="2.4.0",
required_capability="manage_options",
route="airano-mcp/v1/cache-purge",
),
"detected": [],
"purged": [],
"errors": [],
},
indent=2,
)
if not isinstance(payload, dict):
return json.dumps(
{
"ok": False,
"error": "invalid_response",
"message": "companion returned a non-object payload",
"detected": [],
"purged": [],
"errors": [],
},
indent=2,
)
# Pass through + normalise.
detected = list(payload.get("detected") or [])
purged = list(payload.get("purged") or [])
errors = list(payload.get("errors") or [])
ok = bool(payload.get("ok", not errors))
result = {
"ok": ok,
"detected": detected,
"purged": purged,
"skipped": list(payload.get("skipped") or []),
"errors": errors,
"plugin_version": payload.get("plugin_version"),
}
return json.dumps(result, indent=2)