feat(card): a folder shows every bundle under it, as the server does

`okf card <folder>` prints `okf_list` and `okf_describe` with no bundle
named, joined by `mcp_server.overview`, and computes nothing of its own:
one source, two doors. Chosen over a separate `--root` flag because the
skill's first step must be the same command whether it was pointed at a
bundle or at a folder of them; the rule that decides is discovery's own
(a directory carrying an `index.md` is a bundle). A bundle path prints its
card as before.

v1.1 order F, part F1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-21 10:28:32 +02:00
commit df83c65e32
5 changed files with 212 additions and 4 deletions

View file

@ -512,6 +512,35 @@ def call_describe(surface: Surface, arguments: Mapping[str, Any]) -> dict[str, A
}
def is_bundle(path: Path) -> bool:
"""Whether `path` IS a bundle rather than a folder that may hold some.
The rule discovery already uses to stop descending: a directory carrying
an `index.md`. The command line's two doors ask it to decide which shape
they were pointed at, so a reader never has to say which one it holds.
"""
return (path / "index.md").is_file()
def overview(surface: Surface) -> dict[str, Any]:
"""Every bundle under the roots and each one's card, as the command line
prints it for a FOLDER (`okf card <folder>`).
It is `okf_list` and `okf_describe` with no bundle named, joined, and it
computes nothing of its own: one source, two doors. The listing carries
what the cards do not -- the directory each bundle sits in, and the
directories that look like a bundle and cannot be read as one.
"""
listing = call_list(surface, {})
described = call_describe(surface, {})
return {
"shape": listing["shape"],
"bundles": listing["bundles"],
"unreadable": listing["unreadable"],
"cards": described["cards"],
}
def _questions(arguments: Mapping[str, Any]) -> list[str]:
"""`question` (one string) or `questions` (a list), never both.