markdown-to-html · diff
git:20260727.7ba66d5 to git:20260811.72b7e8c
42 added, 9 removed. Audit B to B.
---
name: markdown-to-html
description: Convert a Markdown file to a self-contained, styled HTML page (sticky header, sidebar nav, syntax-highlighted code, callout boxes, Mermaid diagrams, print-ready). Use when the user asks to render, convert, or export a `.md` file as a shareable HTML document -- not for slides, presentations, or pitch decks. Rendering is deterministic via `marked` + `highlight.js`; the agent only invokes the script.
metadata:
boundaries: [filesystem_write]
---
# Markdown to HTML
- A thin wrapper around `scripts/render.js`. The renderer parses Markdown
+ A thin wrapper around `<skill-dir>/scripts/render.js`. The renderer parses Markdown
deterministically with `marked` + `highlight.js`, post-processes for
callouts and table wraps, builds a sidebar nav and print TOC from
heading IDs, and stamps everything into `scripts/template.html`.
## Output rendering
Key–value / one record — For a single record's fields, use an aligned key: value list, not a two-row table.
+ ## Installed entry-point contract
+
+ Treat `<skill-dir>` as the installer-supplied directory containing this active
+ `SKILL.md`; never infer it from the current working directory, user input, an
+ environment variable, or a profile path. Replace `<skill-dir>` with that actual
+ validated directory before executing or relaying any command; never send the
+ placeholder to a runtime or user. Before every invocation of `render.js`:
+
+ 1. Canonicalize `<skill-dir>`, its `scripts/` child, and the expected entry
+ point, resolving symlinks. Require the entry point to be a regular file and
+ its resolved path to remain beneath the canonical `scripts/` directory.
+ 2. If the entry is missing, is not a regular file, encounters a symlink loop or
+ resolution error, or escapes that directory, stop before launching Node.
+ Report only `error: installed skill entry point is unavailable: <entry>`,
+ substituting the basename. Do not expose an absolute, home, profile,
+ environment, or protected path; do not relay raw runtime stderr; and do not
+ offer credential, SSO-capture, token, scope, or dependency remediation.
+ 3. Invoke with a discrete argument vector, for example
+ `["node", "<skill-dir>/scripts/render.js", "..."]`, so spaces, both quote characters, `$()`, backticks, and
+ variable-shaped text cannot be expanded by a shell. Keep the project root as
+ the working directory so user content paths retain their documented meaning.
+ 4. If only a shell string is available, use a single-quoted literal path on
+ POSIX or PowerShell and refuse paths containing a single quote. On cmd.exe,
+ use a double-quoted path and refuse paths containing `"`, `%`, or `!`.
+ If the adapter cannot represent the path safely, refuse instead of invoking.
+
+ Interpret exit codes only after this preflight succeeds and the entry point
+ actually runs.
+
## Instructions
You are not the renderer. The script is. Invoke it and report the path.
### Step 1 — Verify dependencies
The renderer needs Node.js and the `marked` + `highlight.js` packages
- (pinned in `package.json`). From the skill's own directory, check
- whether they're already installed:
+ (pinned in `package.json`). Use the actual `<skill-dir>` resolved during
+ preflight as npm's explicit prefix; do not substitute the current working
+ directory. Render that prefix with the same safe literal/refusal rules as the
+ entry point. The examples below show the POSIX/PowerShell single-quoted form;
+ refuse a path containing a single quote instead of relaying either command.
+ Check whether the packages are already installed:
```bash
- node -e "require.resolve('marked'); require.resolve('highlight.js')"
+ npm --prefix '<skill-dir>' ls --depth=0 --silent marked highlight.js
```
- Exit 0 → dependencies present; go to Step 2.
- Non-zero → not installed yet. Confirm `npm` is available
(`npm --version`); if it isn't, tell the user to install Node.js and
stop. If it is, **ask the user before installing**, then run the
one-time install and re-verify — don't assume it succeeded:
```bash
- npm install # installs the pinned marked + highlight.js
- node -e "require.resolve('marked'); require.resolve('highlight.js')"
+ npm --prefix '<skill-dir>' install
+ npm --prefix '<skill-dir>' ls --depth=0 --silent marked highlight.js
```
(The install is one-time; subsequent runs are cached in `node_modules/`.)
- > Note: if your installer drops this skill into a tracked directory, add the skill's `node_modules/` to your project's `.gitignore` to avoid committing the npm install artifacts.
+ > Note: if your installer drops this skill into a tracked directory, add the skill's `node_modules/` to your project's `.gitignore` to avoid committing installed dependency artifacts.
### Step 2 — Render
```bash
- node scripts/render.js <input.md> [--output OUT.html] [--title T] [--subtitle S] [--theme NAME] [--no-mermaid]
+ node '<skill-dir>/scripts/render.js' <input.md> [--output OUT.html] [--title T] [--subtitle S] [--theme NAME] [--no-mermaid]
```
| Flag | Meaning |
|---|---|
| `--output FILE` | Output path. Default: input with `.html` extension. |
| `--title TEXT` | Page title. Default: first H1, then filename. |
| `--subtitle TEXT` | Header subtitle (small grey text next to the title). |
| `--theme NAME` | `navy` (default), `green`, `teal`, `amber`, `rose`. |
| `--no-mermaid` | Skip the Mermaid CDN script (for sources with no diagrams). |
The script writes the HTML and prints three lines to stdout:
```
OUTPUT: /path/to/file.html
SECTIONS: <number of h2/h3 anchors built>
MERMAID: yes|no
```
Surface the output path to the user and the section/mermaid summary if
relevant.
### Step 3 — What the renderer handles automatically
- **Headings** get stable `id` attributes used by sidebar links and the
print TOC. Don't rewrite the markdown's headings.
- **Code blocks** are syntax-highlighted via `highlight.js`. Fenced
blocks tagged ` ```mermaid ` pass through as `<div class="mermaid">`
for the runtime CDN renderer.
- **Tables** are wrapped in `<div class="table-wrap">` for horizontal
scrolling on narrow viewports.
- **Callouts**: paragraphs that begin with `**Note:**`, `**Tip:**`,
`**Warning:**`, `**Important:**`, or `**Stop:**` are wrapped in a
styled callout box. Don't try to add HTML manually — the script
detects the bold lead-in.
- **Print**: every output includes an `@media print` block that hides
the sidebar, builds a single-page TOC, and preserves background
colors. `Ctrl+P → Save as PDF` works out of the box.
### Don't
- Don't write your own HTML. The script is the renderer; if the output
is wrong, fix the script (or the template).
- Don't pre-process the markdown by hand. The renderer expects raw
Markdown including any `**Note:**` lead-ins.
- Don't pass `--theme` unless the user asked for a specific accent
color. `navy` is the default for a reason.
- Don't suggest pasting the rendered HTML into chat. Open the output
file in a browser.
### Edge cases
- - **Missing dependencies**: `node scripts/render.js` exits 1 with an
+ - **Missing dependencies**: `node '<skill-dir>/scripts/render.js'` exits 1 with an
install hint. Follow Step 1 — install on consent, then re-verify;
don't install bare.
- **No headings**: sidebar shows `(no sections)`. Output still works,
the sidebar just stays empty.
- **Custom theme requested by name not in the list**: the script exits
with the list of valid choices. Ask the user which to use; don't
invent a sixth.
- **Source contains a Mermaid block but you want fully offline output**:
pass `--no-mermaid` and the diagram will fall back to a plain `<pre>`.
- **Trust model**: the renderer assumes the input markdown is the user's
own document. Marked's default behavior is to pass through raw HTML
embedded in markdown (e.g., a `<script>` tag in a `.md` file lands in
the output as-is). This is fine for documents you authored; do not
use this skill to render markdown from untrusted sources without a
separate sanitization step.