mirror of
https://github.com/BillyOutlast/CLI-Anything-WEB.git
synced 2026-10-12 02:24:59 +00:00
Wire every cli-web-<app> CLI and a new cli-anything-web umbrella package into release-please + PyPI Trusted Publishing, so users can install each CLI individually (pip install cli-web-<app> / uvx cli-web-<app>) or the whole fleet at once (pip install cli-anything-web). - release-please-config.json / manifest: add the 20 CLIs + meta umbrella - meta/: new cli-anything-web metapackage (unpinned deps on all CLIs) - publish.yml: single generic resolver (tag -> dir) covers every package - docs.py + README + per-CLI docs + skills: show the published install - docs/PUBLISHING.md: one-time Trusted Publisher setup for all 22 projects
95 lines
3.6 KiB
Python
95 lines
3.6 KiB
Python
"""Generate fleet documentation from registry.json.
|
|
|
|
README.md's CLI table and install command are generated artifacts: the
|
|
content between ``<!-- fleet-table:start -->`` / ``<!-- fleet-table:end -->``
|
|
and ``<!-- fleet-install:start -->`` / ``<!-- fleet-install:end -->`` markers
|
|
is rewritten from the registry, so the docs can never drift from the fleet
|
|
again. ``--check`` mode (used in CI) fails if the README is stale.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
from .registry import Registry
|
|
|
|
_AUTH_DISPLAY = {
|
|
"none": "None",
|
|
"cookie": "Cookie",
|
|
"google_sso": "Google SSO",
|
|
"waf_cookies": "WAF cookies",
|
|
"browser (OpenAI SSO)": "Browser (OpenAI SSO)",
|
|
"optional (OAuth via token_v2)": "Optional (OAuth)",
|
|
"cookie (optional — required for write ops)": "Cookie (optional)",
|
|
}
|
|
|
|
TABLE_START = "<!-- fleet-table:start -->"
|
|
TABLE_END = "<!-- fleet-table:end -->"
|
|
INSTALL_START = "<!-- fleet-install:start -->"
|
|
INSTALL_END = "<!-- fleet-install:end -->"
|
|
|
|
|
|
def render_table(registry: Registry) -> str:
|
|
lines = [
|
|
f"{len(registry.clis)} real CLIs generated by the plugin — shipped as reference implementations:",
|
|
"",
|
|
"| CLI | Website | Protocol | Auth | Skill | Description |",
|
|
"|-----|---------|----------|------|-------|-------------|",
|
|
]
|
|
for e in registry.clis:
|
|
extra = e.extra
|
|
website = extra.get("display_website", e.website)
|
|
skill = extra.get("skill", "")
|
|
description = extra.get("description", "")
|
|
skill_cell = f"[📖 Skill]({skill})" if skill else "—"
|
|
auth = _AUTH_DISPLAY.get(e.auth, e.auth[0].upper() + e.auth[1:] if e.auth else e.auth)
|
|
lines.append(
|
|
f"| [`{e.name}`]({e.app_dir}/) | {website} | {e.protocol} | {auth} "
|
|
f"| {skill_cell} | {description} |"
|
|
)
|
|
return "\n".join(lines)
|
|
|
|
|
|
def render_install(registry: Registry) -> str:
|
|
# A no-auth CLI makes the best copy-paste example (runs with zero setup).
|
|
sample = next(
|
|
(e.name for e in registry.clis if e.auth == "none"),
|
|
registry.clis[0].name if registry.clis else "cli-web-gh-trending",
|
|
)
|
|
return (
|
|
"```bash\n"
|
|
"# Install the entire fleet (every CLI) in one command:\n"
|
|
"pip install cli-anything-web # or: uv tool install cli-anything-web\n"
|
|
"\n"
|
|
"# ...or install only the CLIs you want, by name (see the table above):\n"
|
|
f"pip install {sample}\n"
|
|
f"uvx {sample} --help # or run it once, no install, via uvx\n"
|
|
"```\n"
|
|
"\n"
|
|
"> Working from a clone instead? Install a CLI editable with "
|
|
"`pip install -e <app>/agent-harness` (see [QUICKSTART](QUICKSTART.md))."
|
|
)
|
|
|
|
|
|
def _replace_region(text: str, start: str, end: str, content: str) -> str:
|
|
pattern = re.compile(re.escape(start) + r".*?" + re.escape(end), re.S)
|
|
if not pattern.search(text):
|
|
raise ValueError(f"README markers not found: {start} ... {end}")
|
|
return pattern.sub(f"{start}\n{content}\n{end}", text)
|
|
|
|
|
|
def generate(root: Path, check: bool = False) -> bool:
|
|
"""Regenerate README regions. Returns True if the README was up to date."""
|
|
registry = Registry.load(root / "registry.json")
|
|
readme = root / "README.md"
|
|
original = readme.read_text(encoding="utf-8")
|
|
|
|
updated = _replace_region(original, TABLE_START, TABLE_END, render_table(registry))
|
|
updated = _replace_region(updated, INSTALL_START, INSTALL_END, render_install(registry))
|
|
|
|
fresh = updated == original
|
|
if not check and not fresh:
|
|
readme.write_text(updated, encoding="utf-8")
|
|
return fresh
|