"""Build the capability gallery: one screenshot per thing the harness can do. python showcase.py # every capability python showcase.py --list # list the ids without rendering python showcase.py --only decisions # render a subset by id substring The shared state - the catalogue, the renderers, the display - lives in :mod:`showcase_core`, and the capabilities themselves in :mod:`showcase_catalog`, so importing this file never makes a second copy of either. """ from __future__ import annotations import json import sys import showcase_catalog # noqa: F401 (importing it registers every shot) from showcase_core import ( CATALOG, GALLERY, ROOT, ensure_display, render_desktop, render_terminal, save, ) def main(argv: list[str] | None = None) -> int: args = list(argv if argv is not None else sys.argv[1:]) only = args[args.index("--only") + 1] if "--only" in args else None wanted = (args[args.index("--ids") + 1].split(",") if "--ids" in args else None) if "--card" in args: print("card section written:", write_card(_read_index()).name) return 0 display = ensure_display() picked = [s for s in CATALOG if (s.id in wanted if wanted else (not only or only.lower() in s.id.lower()))] print(f"display: {display} | {len(picked)}/{len(CATALOG)} capabilities") if "--list" in args: for s in picked: print(f" {s.id:36} {s.kind:8} {s.category}: {s.title}") return 0 GALLERY.mkdir(exist_ok=True) if "--reindex" in args or only: # an index built from the catalogue, not from what this run happened to draw _write_index() if "--reindex" in args: print(f"reindexed {len(_read_index())} pictures in {GALLERY}") return 0 tmp = ROOT / ".showcase-tmp" tmp.mkdir(exist_ok=True) made = [] for s in picked: try: image = render_desktop(s, tmp) if s.kind == "desktop" else render_terminal(s, tmp) path = save(image, s.id) made.append(s) print(f" ok {s.id:34} {path.name:34} {image.size[0]}x{image.size[1]}") except Exception as exc: print(f" FAIL {s.id:34} {type(exc).__name__}: {exc}") _write_index() print(f"wrote {len(made)} images to {GALLERY}") return 0 def _entry(s): return {"id": s.id, "category": s.category, "title": s.title, "shows": s.shows, "note": s.note, "kind": s.kind} def _write_index(): """Index every capability whose picture exists, in catalogue order.""" entries = [_entry(s) for s in CATALOG if (GALLERY / f"{s.id}.png").exists()] (GALLERY / "index.json").write_text(json.dumps(entries, indent=2)) return entries def _read_index(): return json.loads((GALLERY / "index.json").read_text()) def api_surface() -> tuple[list[str], list[str]]: """(callables, constants) - the public surface a picture has to cover. Introspected rather than hard-coded, so the gallery's promise is checked against the package instead of against a list someone forgot to update. """ import importlib import inspect names, constants = [], [] modules = ["actions", "act", "observe", "perception", "brain", "models", "loop", "safety", "desktop", "demo", "trace", "accessibility", "__main__", # 2.0: the operator layer. A picture that ignores it would let the gallery's # promise quietly mean "the pre-2.0 API", which is exactly the kind of claim # this repository is supposed to be too honest to make. "diff", "gates", "runner", "skills", "watchdog", "audit"] for module_name in modules: module = importlib.import_module(f"tiny_computer_agent.{module_name}") for name, obj in vars(module).items(): if name.startswith("_"): continue if inspect.isfunction(obj) or inspect.isclass(obj): if getattr(obj, "__module__", "") != module.__name__: continue # imported, not defined here names.append(name) if inspect.isclass(obj): for member, value in vars(obj).items(): if member.startswith("_"): continue if inspect.isfunction(value) or isinstance(value, property): names.append(f"{name}.{member}") elif name.isupper() and isinstance(obj, (str, int, float, tuple, frozenset)): constants.append(name) return names, constants def write_card(entries: list[dict]) -> Path: """Write the gallery page, and the section the model card embeds. Every entry carries the callables it demonstrates, so the card can promise - and a reader can check - that no part of the public API is left without a picture. """ areas: dict[str, list[dict]] = {} for entry in entries: areas.setdefault(entry["category"], []).append(entry) pictured = sorted({name for entry in entries for name in entry["shows"]}) callables, constants = api_surface() missing = sorted(set(callables) - set(pictured)) if missing: print(f" WARNING: {len(missing)} public callables are not pictured: {missing}") lines = [ "## Capability gallery", "", f"**{len(entries)} capabilities, one screenshot each - and " f"{len(set(callables) & set(pictured))} of the package's {len(callables)} public " f"callables (functions, methods, classes and protocols) appear in at least one of " f"them**, together with {len(set(constants) & set(pictured))} of its public " f"constants.", "", (f"_Not yet pictured: {len(missing)} callables added in 2.0 - the gate, skill, " f"runner, diff, watchdog and audit layers. They are covered by tests; the " f"roadmap tracks the pictures._" if missing else "_Every public callable in the package is pictured._"), "", "Nothing here is a mock-up. Each picture is produced by " "[`showcase.py`](showcase.py): a command or a call is run for real, and its actual " "output - or the real desktop it acted on - is what you see. The desktop shots are " "real screen captures on a real X server (Xvfb, 1280x800), including a real mouse " "click verified by the target application's own reaction.", "", "> **An honest note on the platform.** These were captured on Linux, because the " "sandbox that builds this card has no Windows: no KVM, no QEMU and no Windows image. " "The harness is OS-agnostic (pyautogui uses `SendInput` on Windows, and `GrabScreen` " "falls back to Pillow's `ImageGrab`), so these are the same code paths - but they are " "not Windows pixels. The Windows twins are generated by the same script in " "[`.github/workflows/live-desktop.yml`](.github/workflows/live-desktop.yml).", "", "Regenerate it with `python showcase.py` (`--list` to see the ids, `--only ` for a " "subset, `--card` to rewrite this section). It runs the calls for real, so a broken " "capability fails loudly instead of shipping a stale picture.", "", "| area | capabilities |", "|---|---:|", ] lines += [f"| {area} | {len(items)} |" for area, items in areas.items()] lines += ["", "---", ""] for area, items in areas.items(): lines += [f"### {area}", ""] for entry in items: lines += [f"**{entry['title']}**", ""] if entry["note"]: lines += [f"*{entry['note']}*", ""] lines += [f'', ""] lines += ["`shows:` " + ", ".join(f"`{name}`" for name in entry["shows"]), ""] text = "\n".join(lines) (GALLERY / "_card_section.md").write_text(text) (GALLERY / "README.md").write_text( "---\ntitle: Capability gallery\n---\n\n" + text + "\n") return GALLERY / "_card_section.md" if __name__ == "__main__": raise SystemExit(main())