Files
admin 6eeb8b9087 feat: add wordvibe_build_page (Word Page Builder over MCP)
Wraps the site tool wpb_build_page: build or update a Word Page from {kind, html} sections. The page lands as a native Word Page (payload in post meta, builder-rendered), so it stays editable and undoable in the builder. Also documents the builder tools in the bundled skill and README.
2026-09-22 01:59:54 +03:00

83 lines
3.1 KiB
Python

"""wordvibe-hermes — registration.
Connects Hermes to WordPress sites running the WordVibe plugin (which ships an
MCP server at /wp-json/wp-ide/v1/mcp) and exposes a lean set of tools for
driving those sites from any Hermes surface — CLI, Telegram, cron, subagents.
"""
import logging
from . import schemas, tools
logger = logging.getLogger(__name__)
TOOLSET = "wordvibe"
def _split_commands(raw: str) -> list:
return [c for c in (raw or "").split() if c]
def _handle_command(ctx, raw_args: str) -> str:
"""`/wordvibe [sites|info|tools|call <tool> <json>]` — quick access without a model turn."""
parts = _split_commands(raw_args)
sub = (parts[0].lower() if parts else "sites")
if sub in ("sites", "list"):
return tools.sites({"probe": True}, ctx=ctx)
if sub in ("info", "status"):
return tools.site_info({"site": parts[1] if len(parts) > 1 else ""}, ctx=ctx)
if sub in ("tools", "listtools"):
return tools.tools({"site": parts[1] if len(parts) > 1 else ""}, ctx=ctx)
if sub in ("call", "run") and len(parts) >= 2:
import json as _json
tool_name = parts[1]
raw_json = raw_args.split(tool_name, 1)[1].strip() if tool_name in raw_args else ""
try:
arguments = _json.loads(raw_json) if raw_json else {}
except Exception as exc: # noqa: BLE001
return tools._err(f"arguments must be JSON: {exc}")
return tools.call({"tool": tool_name, "arguments": arguments}, ctx=ctx)
return tools._ok(
{
"usage": "/wordvibe sites | info [site] | tools [site] | call <tool> '{json}'",
"example": "/wordvibe call post_list '{\"post_type\":\"post\",\"limit\":5}'",
}
)
def _on_post_tool_call(tool_name, args, result, task_id, **kwargs):
"""Log wordvibe_* traffic at debug level (visibility without noise)."""
if str(tool_name).startswith("wordvibe_"):
logger.debug("wordvibe tool %s (session %s)", tool_name, task_id)
def register(ctx):
"""Wire the wordvibe tools into the Hermes tool registry."""
registry = [
("wordvibe_sites", schemas.SITES, tools.sites),
("wordvibe_site_info", schemas.SITE_INFO, tools.site_info),
("wordvibe_tools", schemas.TOOLS, tools.tools),
("wordvibe_call", schemas.CALL, tools.call),
("wordvibe_read_file", schemas.READ_FILE, tools.read_file),
("wordvibe_write_file", schemas.WRITE_FILE, tools.write_file),
("wordvibe_edit_file", schemas.EDIT_FILE, tools.edit_file),
("wordvibe_search", schemas.SEARCH, tools.search),
("wordvibe_build_page", schemas.BUILD_PAGE, tools.build_page),
]
for name, schema, handler in registry:
ctx.register_tool(name=name, toolset=TOOLSET, schema=schema, handler=handler)
ctx.register_command(
"wordvibe",
lambda raw: _handle_command(ctx, raw),
description="WordVibe sites: `sites`, `info [site]`, `tools [site]`, `call <tool> '{json}'`",
)
ctx.register_hook("post_tool_call", _on_post_tool_call)
logger.info("wordvibe-hermes registered %d tools", len(registry))