"""Starlette application for the internal read-only web UI (#426).""" from __future__ import annotations from datetime import datetime, timezone from starlette.applications import Starlette from starlette.requests import Request from starlette.responses import HTMLResponse, JSONResponse, Response from starlette.routing import Route from webui.layout import render_page _READ_ONLY_METHODS = frozenset({"GET", "HEAD", "OPTIONS"}) def _stub_page(title: str, description: str) -> HTMLResponse: body = ( f"

{title}

" f'

{description}

' "

Implementation tracked in a child issue of #425.

" ) return HTMLResponse(render_page(title=title, body_html=body)) async def home(_request: Request) -> HTMLResponse: body = ( "

Operator console

" "

Local entry point for MCP Control Plane operational views.

" "" ) return HTMLResponse(render_page(title="Home", body_html=body)) async def health(_request: Request) -> JSONResponse: return JSONResponse({ "status": "ok", "service": "mcp-control-plane-webui", "mode": "read-only-mvp", "timestamp": datetime.now(timezone.utc).isoformat(), }) async def projects(_request: Request) -> HTMLResponse: return _stub_page( "Projects", "Project registry and onboarding model will list configured repos and profiles.", ) async def prompts(_request: Request) -> HTMLResponse: return _stub_page( "Prompts", "Prompt library will surface canonical workflows from skills/llm-project-workflow/.", ) async def runtime(_request: Request) -> HTMLResponse: return _stub_page( "Runtime", "Runtime health will report MCP profile, preflight, and stale-server signals.", ) async def audit(_request: Request) -> HTMLResponse: return _stub_page( "Audit", "Report audit will accept pasted final reports and run validator previews.", ) async def worktrees(_request: Request) -> HTMLResponse: return _stub_page( "Worktrees", "Worktree hygiene will summarize branches/ session folders and cleanup risk.", ) async def leases(_request: Request) -> HTMLResponse: return _stub_page( "Leases", "Lease visibility will show active issue and reviewer PR leases.", ) async def method_not_allowed(request: Request, _exc: Exception) -> Response: if request.method not in _READ_ONLY_METHODS: return JSONResponse( {"error": "read-only-mvp", "detail": f"{request.method} not permitted"}, status_code=405, ) return JSONResponse({"error": "not_found"}, status_code=404) def create_app() -> Starlette: """Build the read-only MVP Starlette app.""" return Starlette( debug=False, routes=[ Route("/", home, methods=["GET"]), Route("/health", health, methods=["GET"]), Route("/projects", projects, methods=["GET"]), Route("/prompts", prompts, methods=["GET"]), Route("/runtime", runtime, methods=["GET"]), Route("/audit", audit, methods=["GET"]), Route("/worktrees", worktrees, methods=["GET"]), Route("/leases", leases, methods=["GET"]), ], exception_handlers={405: method_not_allowed}, )