diff --git a/.claude/skills/a11y-audit.md b/.claude/commands/a11y-audit.md similarity index 100% rename from .claude/skills/a11y-audit.md rename to .claude/commands/a11y-audit.md diff --git a/.claude/commands/add-solution.md b/.claude/commands/add-solution.md new file mode 100644 index 000000000..f0f669d9d --- /dev/null +++ b/.claude/commands/add-solution.md @@ -0,0 +1,216 @@ +--- +name: add-solution +description: > + Generate a structured TypeScript solution file for a challenge. + Accepts any input format: markdown, YAML, HTML, or plain text. + Downloads and converts images to WebP. Produces a file at + src/data/solutions//.ts that matches + the Solution type in src/data/solutions/types.ts. +--- + +# Add Solution Command + +Generate a structured TypeScript solution walkthrough for an OffOn challenge. + +## What this command does + +1. Gathers inputs, inferring what it can from the content before asking. +2. Parses the solution input (any format) into structured steps. +3. Downloads any referenced images and converts them to WebP using `cwebp`. +4. Writes `src/data/solutions//.ts` with the structured content. +5. Runs the generator to update `src/data/solutions/index.ts` and all region patches. +6. Runs the build to verify the output compiles. + +--- + +## Step 0: Gather inputs + +If the user already provided solution content (pasted HTML, markdown, plain text, or a file path), treat that as the content — do not ask for it again. + +For each remaining input, **first try to infer it from the content** before asking. If a value can be inferred with confidence, show it to the user for confirmation rather than asking a blank question. + +| Input | Required | How to infer | +| --- | --- | --- | +| Adventure ID | Yes | Look for the challenge or adventure name in the content (title, headings, kicker). Convert to kebab-case. | +| Level ID | Yes | Look for difficulty words in the content (`beginner`, `intermediate`, `expert`). | +| Contributor name | No | Look for an author credit in the content. If not found, ask: "Who wrote this walkthrough? (leave blank to omit)" | + +If adventure ID or level ID cannot be inferred confidently, ask for them directly. + +Confirm all inferred values with the user before proceeding. A single confirmation message is better than multiple rounds of questions. + +--- + +## Step 1: Locate the adventure + +Find the adventure in `src/data/adventures/index.ts` or the generated files to confirm the IDs are valid: + +```bash +grep -r "id: \"\"" src/data/adventures/ +``` + +Also confirm the level exists within that adventure. If either ID does not match, stop and report it. + +--- + +## Step 2: Parse the input into structured steps + +Read the input regardless of format (markdown, YAML, HTML, plain text). Extract: + +- **`title`** — solution title, e.g. "Intermediate Solution: Governing the Provinces". Never include difficulty emoji. No em dashes. +- **`contributor`** — `{ name: string }` if a contributor was provided. Omit the field entirely if unknown. +- **`spoilerWarning`** — one sentence. Plain text, no markdown. +- **`intro`** — one or two sentences. Plain text, no markdown. +- **`context`** (optional) — a setup section that explains the tooling or architecture the reader needs to understand before the steps. Title should reflect the specific challenge, not a generic phrase. Use "Understanding the Setup" only if nothing more specific fits. +- **`steps`** — one per numbered objective. Each step: + - `id` — kebab-case, no numbers (e.g. `census-scope`, `isolated-namespaces`) + - `title` — title case, no leading emoji + - `intro` — one to two sentences, plain text + - `body` — array of `SolutionBlock` (see below). Code patches go here as `code` blocks. + - `takeaways` — plain-text strings, sentence case. Preserve all takeaways from the source. Omit only if a step has no non-obvious insight to share. + - `furtherReading` — array of `{ title, url }`. These are aggregated into the sidebar across all steps; do not duplicate a URL across multiple steps. +- **`completeSolution`** (optional) — final corrected config or runbook shown as a summary at the end. +- **`outro`** — narrative closing. End with a sentence that follows the adventure's story world, then invite the reader to see how others solved it. Do not use "Got there by a different route?" or similar generic phrases. + +### SolutionBlock types + +```typescript +| { type: "text"; html: string } // HTML paragraph or list +| { type: "code"; language: string; title?: string; code: string } +| { type: "image"; src: string; alt: string; caption?: string } +| { type: "callout"; variant: "tip" | "warning" | "info"; html: string } +``` + +**Text blocks:** Write minimal HTML. Use `

`, `