This repository has been archived on 2026-07-29. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
kitchen-md/.claude/spec/cli-view.md
alexion 5841ae5de8 chore: add Biome and document design decisions from grill session
- Add @biomejs/biome 2.5.3 with 2-space indent, double quotes, trailing commas
- Add lint and format scripts to root package.json
- Update CONTEXT.md: resolve Structured Output shape, add Document AST, Block, Inline Node terms
- Add ADR 0002 (remark as internal Markdown parser)
- Add ADR 0003 (core defines own AST types)
- Add spec: core-parser (Parser implementation and Document AST)
- Add spec: cli-view (kitchen view <file> command)
2026-07-08 23:29:09 -04:00

97 lines
6.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Problem Statement
`@kitchen-md/bin` has an empty CLI entry point.
Users have no way to view a Recipe File in the terminal — they must open a text editor or Markdown viewer to read a recipe.
The `kitchen` binary exists in the scaffold but accepts no commands and produces no output.
## Solution
Implement the `kitchen view <file>` subcommand.
It reads a Recipe File from disk, passes the content to `@kitchen-md/core`'s `parse` function, and walks the resulting Document AST through a renderer that produces ANSI-styled terminal output.
Markdown structure is styled for readability; KitchenMD annotations are rendered as their raw source text for now.
## User Stories
1. As a CLI user, I want to run `kitchen view <file>` and see the recipe rendered in the terminal so that I can read it without opening a text editor.
2. As a CLI user, I want headings styled distinctly by level so that I can scan the recipe's structure at a glance.
3. As a CLI user, I want bold and italic text preserved in the terminal output so that emphasis in the recipe prose is visible.
4. As a CLI user, I want frontmatter shown as raw YAML before the recipe body so that I can see the recipe's metadata.
5. As a CLI user, I want wikilinks rendered distinctly from surrounding prose so that cross-references are visually identifiable.
6. As a CLI user, I want a clear error message when the file does not exist so that I am not left with a cryptic failure.
7. As a CLI user, I want the binary to exit with a non-zero code on error so that shell scripts can detect failure.
8. As a CLI user, I want ANSI styling suppressed automatically when output is piped so that downstream tools receive clean text.
## Implementation Decisions
- commander is used for argument parsing.
The `view` subcommand takes a single required positional argument: the path to a Recipe File.
No flags or options beyond the file path are implemented at this stage.
- The entry point reads the file from disk, passes the content string to `parse` from `@kitchen-md/core`, and passes the returned `DocumentAST` to the renderer.
File I/O is confined to the entry point.
- The renderer is a pure function `render(ast: DocumentAST): string`.
It walks the Document AST and returns an ANSI-styled string.
It has no filesystem access and no side effects.
The separation between the entry point (file I/O + commander) and the renderer (pure AST walk) allows the renderer to be tested without invoking a subprocess.
- **Rendering rules:**
- Frontmatter: serialised back to YAML and printed before the document body, followed by a visual separator.
- `HeadingBlock`: bold text; level 1 is the most visually prominent, with levels 26 progressively less so.
- `ParagraphBlock`: inline-rendered text followed by a blank line.
- `ListBlock`: each item on its own line, preceded by a bullet character (unordered) or sequential number (ordered).
- `CodeBlock`: literal text content, rendered as-is with no syntax highlighting.
- `ThematicBreakBlock`: a horizontal rule character string.
- `TextNode`: plain string output.
- `EmphasisNode` (italic): chalk italic.
- `StrongNode` (bold): chalk bold.
- `CodeSpanNode`: a visually distinct style (e.g. chalk dim or inverse).
- `LinkNode`: rendered as the inline content only; href is not shown.
- `WikilinkNode`: display text (or target if no display text), rendered with an underline or distinct colour.
- `TransclusionNode`: rendered as its raw source text (e.g. `![[file#section:1]]`).
- `IngredientNode`, `CookwareNode`, `TimerNode`: rendered as their raw annotation source text (e.g. `@flour{200 g}`, `$pan{}`, `~2-3 mins`).
Distinct annotation styling is out of scope for this spec.
- chalk is used for all ANSI styling.
chalk auto-detects whether stdout is a TTY and disables colour codes when output is piped, satisfying user story 8 without an explicit flag.
- **Error handling:**
- If the file path argument is missing, commander prints usage to stderr and exits with code 1.
- If the file does not exist or cannot be read, the entry point prints a human-readable error message to stderr and exits with code 1.
- No other error conditions are handled at this stage; parse errors from `@kitchen-md/core` are not expected (the parser is resilient to any valid Markdown string).
## Testing Decisions
- Two seams are tested:
**Renderer unit tests** — given a `DocumentAST` constructed inline in the test, assert the `render` function's output with ANSI codes stripped.
Tests cover every Block type, every Inline Node type, frontmatter output, and the visual separator between frontmatter and body.
No subprocess invocation; no filesystem access.
**Smoke tests** — invoke the `kitchen view` binary as a subprocess, capture stdout, strip ANSI codes, and assert the plain text content.
Smoke tests use `fixtures/basic.md` as input and assert that the output contains the expected rendered text for the fixture's headings, paragraphs, frontmatter, and wikilinks.
Smoke tests use Bun's subprocess API, consistent with the project scaffold's smoke test approach.
- ANSI colour and weight choices are visual decisions verified by inspection, not automated test assertions.
Assertions operate on stripped plain text only.
- Tests are co-located with source and follow the naming conventions established in the project scaffold.
## Out of Scope
- Distinct styling for KitchenMD annotation nodes (Ingredient, Cookware, Timer).
Annotations render as raw source text in this spec.
- Pager support.
- Multiple file arguments.
- `--no-color` flag (chalk auto-detects TTY).
- Syntax highlighting for code blocks.
- Formatted frontmatter display (title, servings, tags as a styled header).
- Any subcommand other than `view`.
## Further Notes
- Annotation raw source text (`@flour{200 g}`, `$pan{}`, `~2-3 mins`) reads naturally as plain text in the terminal.
This matches how Recipe Files render in Obsidian without a plugin — the format is designed to be readable without tooling.
- The renderer's purity is intentional.
Keeping file I/O in the entry point and rendering in a pure function is the minimum seam needed for deterministic unit tests without subprocess overhead.