mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-08 22:35:36 +02:00
3af86348f6
Turn markdown into publication-quality PDFs. $P generate input.md out.pdf
produces a PDF with 1in margins, intelligent page breaks, page numbers,
running header, CONFIDENTIAL footer, and curly quotes/em dashes — all on
Helvetica so copy-paste extraction works ("S ai li ng" bug avoided).
Architecture (per Codex round 2):
markdown → render.ts (marked + sanitize + smartypants) → orchestrator
→ $B newtab --json → $B load-html --tab-id → $B js (poll Paged.js)
→ $B pdf --tab-id → $B closetab
browseClient.ts shells out to the compiled browse CLI rather than
duplicating Playwright. --tab-id isolation per render means parallel
$P generate calls don't race on the active tab. try/finally tab cleanup
survives Paged.js timeouts, browser crashes, and output-path failures.
Features in v1:
--cover left-aligned cover page (eyebrow + title + hairline rule)
--toc clickable static TOC (Paged.js page numbers deferred)
--watermark <text> diagonal DRAFT/CONFIDENTIAL layer
--no-chapter-breaks opt out of H1-starts-new-page
--page-numbers "N of M" footer (default on)
--tagged --outline accessible PDF + bookmark outline (default on)
--allow-network opt in to external image loading (default off for privacy)
--quiet --verbose stderr control
Design decisions locked from the /plan-design-review pass:
- Helvetica everywhere (Chromium emits single-word Tj operators for
system fonts; bundled webfonts emit per-glyph and break extraction).
- Left-aligned body, flush-left paragraphs, no text-indent, 12pt gap.
- Cover shares 1in margins with body pages; no flexbox-center, no
inset padding.
- The reference HTMLs at .context/designs/*.html are the implementation
source of truth for print-css.ts.
Tests (56 unit + 1 E2E combined-features gate):
- smartypants: code/URL-safe, verified against 10 fixtures
- sanitizer: strips <script>/<iframe>/on*/javascript: URLs
- render: HTML assembly, CJK fallback, cover/TOC/chapter wrap
- print-css: all @page rules, margin variants, watermark
- pdftotext: normalize()+copyPasteGate() cross-OS tolerance
- browseClient: binary resolution + typed error propagation
- combined-features gate (P0): 2-chapter fixture with smartypants +
hyphens + ligatures + bold/italic + inline code + lists + blockquote
passes through PDF → pdftotext → expected.txt diff
Deferred to Phase 4 (future PR): Paged.js vendored for accurate TOC page
numbers, highlight.js for syntax highlighting, drop caps, pull quotes,
two-column, CMYK, watermark visual-diff acceptance.
Plan: .context/ceo-plans/2026-04-19-perfect-pdf-generator.md
References: .context/designs/make-pdf-*.html
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
63 lines
1.8 KiB
TypeScript
63 lines
1.8 KiB
TypeScript
/**
|
|
* Command registry for make-pdf — single source of truth.
|
|
*
|
|
* Dependency graph:
|
|
* commands.ts ──▶ cli.ts (runtime dispatch)
|
|
* ──▶ gen-skill-docs.ts (generates usage table in SKILL.md)
|
|
* ──▶ tests (validation)
|
|
*
|
|
* Zero side effects. Safe to import from build scripts.
|
|
*/
|
|
|
|
export const COMMANDS = new Map<string, {
|
|
description: string;
|
|
usage: string;
|
|
flags?: string[];
|
|
category: "Primary" | "Setup";
|
|
}>([
|
|
["generate", {
|
|
description: "Render a markdown file to a publication-quality PDF",
|
|
usage: "generate <input.md> [output.pdf] [options]",
|
|
category: "Primary",
|
|
flags: [
|
|
// Page layout
|
|
"--margins", "--margin-top", "--margin-right", "--margin-bottom", "--margin-left",
|
|
"--page-size", "--format",
|
|
// Structure
|
|
"--cover", "--toc", "--no-chapter-breaks",
|
|
// Branding
|
|
"--watermark", "--header-template", "--footer-template", "--no-confidential",
|
|
// Output
|
|
"--page-numbers", "--no-page-numbers", "--tagged", "--no-tagged",
|
|
"--outline", "--no-outline", "--quiet", "--verbose",
|
|
// Network
|
|
"--allow-network",
|
|
// Metadata
|
|
"--title", "--author", "--date",
|
|
],
|
|
}],
|
|
["preview", {
|
|
description: "Render markdown to HTML and open it in the browser (fast iteration)",
|
|
usage: "preview <input.md> [options]",
|
|
category: "Primary",
|
|
flags: [
|
|
"--cover", "--toc", "--no-chapter-breaks", "--watermark",
|
|
"--no-confidential", "--allow-network",
|
|
"--title", "--author", "--date",
|
|
"--quiet", "--verbose",
|
|
],
|
|
}],
|
|
["setup", {
|
|
description: "Verify browse + Chromium + pdftotext, then run a smoke test",
|
|
usage: "setup",
|
|
category: "Setup",
|
|
flags: [],
|
|
}],
|
|
["version", {
|
|
description: "Print make-pdf version",
|
|
usage: "version",
|
|
category: "Setup",
|
|
flags: [],
|
|
}],
|
|
]);
|