Phase 7: serve the vet sample from the template tools and docs
- build.py: _TEMPLATE_COMPONENTS rewritten around the vet sample (53 kinds —
per-resource slices, jobs, worked appointment_reminder family, tests);
seed tokens dropped from the manifest ('sample: vet' instead)
- registry.py: get_app_component(kind) no longer renames item/example seeds;
prompts and tool docs updated to 'copy a slice and adapt'
- templates/README.md, 01_build_recipe, 40_ui_admin, wiki/03 updated off the
old seed scheme; repo inventory/config now exclude vet (docs move under
standards; react/vet itself is deleted in a later phase)
- regenerated MCP bundle, vendored templates, and site output
This commit is contained in:
62
registry.py
62
registry.py
@@ -19,7 +19,7 @@ Tools:
|
||||
ping (from the base server)
|
||||
find_library (capability -> matching libraries + MCP endpoints)
|
||||
list_app_components (the template component kinds)
|
||||
get_app_component (kind -> exact template file, seed tokens renamed)
|
||||
get_app_component (kind -> exact template file)
|
||||
get_app_template (the whole app skeleton as a path -> content map)
|
||||
list_client_components (the client template component kinds)
|
||||
get_client_component (kind -> exact client template file)
|
||||
@@ -41,7 +41,6 @@ Prompts:
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
@@ -49,11 +48,6 @@ from config import MCPBundle
|
||||
from mcp_server import MCPServer
|
||||
|
||||
|
||||
def _pascal(name: str) -> str:
|
||||
"""Convert a snake/kebab name to PascalCase."""
|
||||
return "".join(part.capitalize() for part in re.split(r"[_\-\s]+", name) if part)
|
||||
|
||||
|
||||
_INTAKE_TEXT = (
|
||||
"# Start a new app — intake\n\n"
|
||||
"Gather the following, then call `build` (or `start_app`) with the values:\n\n"
|
||||
@@ -93,8 +87,9 @@ def _build_text(app_name: str, resources: str, pipelines: str, auth: str) -> str
|
||||
"3. Call `find_library(capability)` for db, di, routing, ingestion, "
|
||||
"and pipeline; never reimplement a Tier A library.\n"
|
||||
"4. Scaffold with `get_app_template()` (whole tree) or pull single "
|
||||
"files with `list_app_components()` and "
|
||||
"`get_app_component(kind, resource=..., family=...)`.\n"
|
||||
"files with `list_app_components()` and `get_app_component(kind)` — "
|
||||
"the template is the vet sample; copy a slice and adapt it to your "
|
||||
"domain.\n"
|
||||
"5. If a UI is needed, scaffold the client with `get_client_template()` "
|
||||
"(or pull files via `list_client_components()` / "
|
||||
"`get_client_component(kind)`) — the admin renders from your spec's x- "
|
||||
@@ -279,28 +274,17 @@ class StandardsMCPServer(MCPServer):
|
||||
files[rel] = path.read_text(encoding="utf-8")
|
||||
return files
|
||||
|
||||
def _read_component(
|
||||
self,
|
||||
entry: dict[str, Any],
|
||||
resource: str | None,
|
||||
family: str | None,
|
||||
) -> dict[str, Any]:
|
||||
"""Read a vendored template file, renaming seed tokens when asked."""
|
||||
def _read_component(self, entry: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Read a vendored template file as-is (no token rewriting)."""
|
||||
rel = entry["path"]
|
||||
path = Path(self.mcp_root) / "templates" / "app" / rel
|
||||
if not path.exists():
|
||||
return {"error": "not_found", "path": str(path)}
|
||||
text = path.read_text(encoding="utf-8")
|
||||
placeholder = entry.get("placeholder")
|
||||
if resource and placeholder == "resource":
|
||||
text = text.replace("Item", _pascal(resource)).replace("item", resource)
|
||||
if family and placeholder == "family":
|
||||
text = text.replace("Example", _pascal(family)).replace("example", family)
|
||||
return {
|
||||
"kind": entry["kind"],
|
||||
"path": rel,
|
||||
"placeholder": placeholder,
|
||||
"content": text,
|
||||
"placeholder": entry.get("placeholder"),
|
||||
"content": path.read_text(encoding="utf-8"),
|
||||
}
|
||||
|
||||
def _client(self) -> dict[str, Any]:
|
||||
@@ -454,22 +438,17 @@ class StandardsMCPServer(MCPServer):
|
||||
return self._components().get("components", [])
|
||||
|
||||
@self.app.tool()
|
||||
def get_app_component(
|
||||
kind: str,
|
||||
resource: str | None = None,
|
||||
family: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
def get_app_component(kind: str) -> dict[str, Any]:
|
||||
"""Return the exact template file for a component kind.
|
||||
|
||||
Use this to copy current, app-neutral skeleton code instead of
|
||||
inventing it. See :func:`list_app_components` for valid kinds.
|
||||
Use this to copy current sample code instead of inventing it. The
|
||||
template is the vet sample (parents/pets/treatments/vets/
|
||||
appointments + jobs + the appointment_reminder pipeline family);
|
||||
copy a slice and adapt it to your domain. See
|
||||
:func:`list_app_components` for valid kinds.
|
||||
|
||||
Args:
|
||||
kind (str): Component kind, e.g. "routes", "pipeline-impl".
|
||||
resource (str | None): Rename the resource seed ("item"/"Item")
|
||||
to this name (snake_case), for per-resource kinds.
|
||||
family (str | None): Rename the family seed ("example"/"Example")
|
||||
to this name (snake_case), for per-family kinds.
|
||||
kind (str): Component kind, e.g. "parent-routes", "pipeline-impl".
|
||||
|
||||
Returns:
|
||||
dict[str, Any]: ``{kind, path, placeholder, content}`` or an
|
||||
@@ -482,7 +461,7 @@ class StandardsMCPServer(MCPServer):
|
||||
"kind": kind,
|
||||
"available": [c["kind"] for c in self._components().get("components", [])],
|
||||
}
|
||||
return self._read_component(entry, resource, family)
|
||||
return self._read_component(entry)
|
||||
|
||||
@self.app.tool()
|
||||
def get_app_template(prefix: str = "") -> dict[str, Any]:
|
||||
@@ -490,8 +469,8 @@ class StandardsMCPServer(MCPServer):
|
||||
|
||||
Use this to scaffold in one shot instead of pulling components one
|
||||
by one; combine with :func:`list_app_components` for the kind and
|
||||
placeholder metadata. Seed tokens (``item`` / ``example``) are left
|
||||
as-is here — fetch a renamed file with :func:`get_app_component`.
|
||||
description metadata. The tree is the vet sample — replace the
|
||||
domain with your own, keeping the layer structure.
|
||||
|
||||
Args:
|
||||
prefix (str): Optional path prefix filter with POSIX
|
||||
@@ -655,14 +634,13 @@ class StandardsMCPServer(MCPServer):
|
||||
def list_repos(type: str | None = None) -> list[dict[str, Any]]:
|
||||
"""List the repositories covered by the CI and versioning standards.
|
||||
|
||||
Each entry has: ``name``, ``type`` ("package" | "service" | "app"),
|
||||
Each entry has: ``name``, ``type`` ("package" | "service"),
|
||||
``path`` (relative to the aetos/ workspace root), ``version_source``
|
||||
("pyproject.toml" | "package.json" | "VERSION"), ``drone`` (the
|
||||
template file), ``trigger`` ("tag"), ``docs`` kinds, and ``mcp``.
|
||||
|
||||
Args:
|
||||
type (str | None): Optional filter, e.g. "package", "service"
|
||||
or "app".
|
||||
type (str | None): Optional filter, e.g. "package" or "service".
|
||||
|
||||
Returns:
|
||||
list[dict[str, Any]]: Matching repository entries.
|
||||
|
||||
Reference in New Issue
Block a user