## [0.9.8] - 2026-09-20

### Added
- Added PDF AES-256 password encryption via `--password`.
- Added cover page prepending capabilities for generating PDFs with title documents (`--cover-page`).
- Added hyperlink styling configurations (`--link-color`, `--no-link-underline`).
- Added `--stdin` batch parsing support for continuous pipeline integration.

### Fixed
- Fixed Vitest module loader deadlocks and concurrent Chromium Playwright crashing issues by rebuilding dynamic AST import pipelines.
- Fixed batch PDF merging memory leaks and recursive cover page rendering bugs.
- Fixed CLI formatting alignment and improved accuracy of OS-level error reporting.
- Restored precise ASCII CLI markers and fixed emoji stripping behaviors.
- Enforced strict temporary filesystem sandboxing directly under `~/.md2pdf/temp` for all processing logic.

### Performance
- Massively optimized boot speed by decoupling a 15MB Mermaid JS dependency and minifying the core engine bundle.

## [0.9.7] - 2026-09-14

### Security
- Fixed arbitrary code execution vulnerability by explicitly disabling all JavaScript and CoffeeScript engine aliases in the gray-matter frontmatter parser.
- Fixed path traversal vulnerabilities by restricting frontmatter `theme` declarations to built-in themes only.
- Fixed path traversal in cache extractions by strictly validating output paths before copying cached artifacts.
- Fixed Server-Side Request Forgery (SSRF) bypasses by blocking connections to cloud metadata endpoints, loopback addresses, and restricted ports.
- Fixed Local File Read vulnerabilities by sanitizing dangerous HTML nodes in Markdown and making the Obsidian embed containment symlink-aware.
- Fixed potential command injection by rigorously verifying custom Chromium executable paths.
- Hardened daemon security by implementing required token authentication, CSRF guards, and strict body payload limits.
- Enforced Chromium sandbox boundaries even when the DISPLAY environment variable is unset.
- Stopped configuration auto-discovery at project boundaries to prevent malicious configurations from being loaded from parent directories.
- Implemented offline mode and restricted external Playwright network resource loading.
- Removed destructive postuninstall script that manipulated filesystem permissions.

### Added
- Added `-r, --recursive` flag for processing directories recursively to discover and compile all Markdown files within nested folders.
- Added `--merge` flag to concatenate multiple converted Markdown files into a single unified output PDF.
- Added `--watch` flag for continuous conversion of Markdown files upon save events.
- Added `--split-by-heading <depth>` flag to automatically partition large Markdown documents into separate PDFs based on heading levels.
- Added `--watermark <text>` flag to overlay customizable watermark text across generated PDFs securely.

### Fixed
- Fixed CLI directory handling to return `ERR_NO_INPUT` on empty directories instead of throwing an invalid input exception.
- Fixed potential application crashes during `split-by-heading` by intercepting invalid inputs prior to AST parsing.
- Fixed stream interruption bugs occurring in the pre-publish hook.
- Fixed intermittent parser test failures by refining the internal `rehype-sanitize` configuration schema.

## [0.9.6] - 2026-09-12

### Security
- Fixed a path traversal vulnerability that could allow output PDFs to be written to restricted system directories.
- Hardened the output path validation to correctly resolve macOS symlinks (e.g. `/etc` resolves to `/private/etc`), preventing blocklist bypass on macOS.
- Fixed an over-broad path blocklist that incorrectly rejected valid output paths such as `/tmp`, custom user directories, and any directory outside `process.cwd()`. Only true OS-critical directories (`/etc`, `/usr`, `/bin`, `/sys`, `/proc`, `/dev`, `/boot`, `/lib`) are blocked.
- Fixed an arbitrary file read vulnerability in the Obsidian embed plugin where directory traversal sequences in embed paths could escape the vault boundary.
- Fixed a local file inclusion vulnerability where maliciously crafted markdown image paths could read internal system files by escaping the Playwright file URL sandbox.
- Eliminated a command injection vector when resolving custom browser executables via the `CHROME_PATH` environment variable.

### Added
- Implemented a persistent background Browser Daemon (`md2pdf daemon start`) that maintains a warm Playwright instance, eliminating the ~200ms browser startup cost for repeated conversions.
- Added `md2pdf daemon stop` and `md2pdf daemon status` subcommands.
- Added automated concurrency benchmark suite using `vitest bench` to validate batch processing throughput across worker configurations.

### Fixed
- Fixed input file glob patterns resolving against the package install directory instead of the user's shell current working directory. Running `md2pdf fixtures/*.md` from any directory now works correctly.
- Fixed absolute input and output paths being re-resolved through `process.cwd()` inside the daemon, causing ENOENT errors when the daemon was started from a different directory than the user.
- Fixed the Playwright file URL sandbox using `process.cwd()` (the package dir) as the allowed base, blocking image assets in the user's actual document directory.
- Fixed `options.pageNumbers`, `options.outline`, `options.fontSize`, `options.lineHeight`, and related formatting flags being silently stripped by the Zod config schema validator.
- Fixed parser memory bloat on deeply nested blockquotes by replacing an unbounded `Math.max(...array)` spread with an iterative loop.
- Fixed incremental cache not invalidating when the installed md2pdf version or the custom theme CSS changed between runs.
- Fixed CLI numeric flag parsing (`--timeout`, `--workers`, etc.) to use `Number.isFinite` instead of `parseInt`, rejecting garbage input without silent truncation.
- Fixed `console.warn` and conversion success messages leaking output when `--quiet` flag was set.
- Fixed `--force` flag being ignored on the first file in batch mode when a daemon was active.

### Performance
- Overlapped Mermaid browser context initialization with AST parsing, reducing warm-path Mermaid conversion latency.
- Replaced the naive browser lifecycle with a reference-counted `globalBrowserManager` that holds Chromium alive across concurrent batch jobs and releases it only when all jobs are complete.
- Converted PDF output writing to a staged atomic pattern (`output.pdf.stage` then `fs.renameSync`) to prevent partial/corrupt files on crash or interrupt.
- Added version and theme-contents hashing to the cache key so upgrades and theme changes correctly invalidate cached PDFs.

### CI & Testing
- Fixed YAML syntax error in `.github/workflows/ci.yml` that prevented the Benchmark step from running.
- Added `tags: ['v*']` to the CI push trigger so GitHub Actions runs on tag pushes.
- Integrated benchmark suite into CI and `scripts/pre-publish.sh`.

## [0.9.5] - 2026-09-10

### Added
- **`--outline`**: Generates PDF bookmarks/outline from markdown headings (H1–H6), navigable in any PDF reader sidebar. Implemented using `pdf-lib` without relying on Playwright's native (broken) outline support.
- **`--add-date`**: Injects the current date/time into the PDF header (top-right). Does not require `--page-numbers` to be set.
- **`--add-filename`**: Injects the document title/filename into the PDF header (top-left).
- **`--document-meta`**: Super flag — enables `--page-numbers`, `--add-date`, and `--add-filename` all at once for a fully annotated PDF in a single flag.
- **`--page-numbers [position]`**: Now accepts an optional position argument: `bottom-center` (default), `bottom-right`, `top-center`, `top-right`. Previously only supported default bottom-center.
- Visual regression baseline test suite (`tests/visual/visual.test.ts`) using `pdf-lib` to validate page count and file size for all theme/option combinations.
- Contract tests for `--outline`, `--page-numbers`, `--line-height`, `--font-size`, and `--theme nord` in `tests/contract/options.test.ts`.

### Fixed
- Fixed the Chromium default header (date/time/filename) being injected unintentionally when `--page-numbers` was used — Chromium's `displayHeaderFooter` mode now only shows content that was explicitly requested.
- Fixed Mermaid block rendering crashes in batch mode (`TypeError: Cannot read properties of undefined (reading 'initialize')`).
- Fixed configuration and cache files polluting the home directory root (`~/.md2pdf.json`); moved to `~/.md2pdf/config.json`.
- Fixed `--outline` flag being silently dropped before reaching the conversion pipeline by adding `outline` to the explicit property map in `src/config/merge.ts`.
- Ensured stable dark-theme print CSS via `@media print` for `dracula`, `nord`, and `obsidian-dark` themes.

## [0.9.4] - 2026-09-10
### Fixed
- Stabilized the entire test infrastructure to ensure 115/115 tests consistently pass across all supported OS and Node environments.
- Fixed an issue where the batch JSON error response was losing the structured error `code` field.
- Fixed contract tests randomly failing in CI by building a shared helper to properly inject the resolved `CHROME_PATH` into child test processes.
- Fixed root user permission tests to gracefully skip via Vitest `.skipIf()` when running in environments where Unix file permissions are bypassed (such as Docker `root` or Windows).
- Decoupled batch file orchestration tests from the Chromium conversion layer by safely mocking PDF output, drastically reducing test overhead and complexity.

## [0.9.3] - 2026-09-06
### Added
- Added `--page-numbers` flag to inject minimalist page numbers into the footer
- Added `--font-size <px>` and `--line-height <ratio>` CLI flags to override base typography

### Fixed
- Fixed dark theme print CSS: `dracula`, `nord`, and `obsidian-dark` now render beautifully on screen while cleanly inverting to a white background with dark text during PDF generation (saves ink without breaking screen visuals)
- Fixed an issue where the browser missing error would overshadow correct errors (like invalid YAML or `publish: false`) by hoisting configuration and YAML validation to run before launching the browser.
- Fixed `md2pdf init` crashing on unexported `cli.js` by properly resolving the `playwright-core` package root.
- Fixed `md2pdf init` correctly auto-installing Linux system dependencies when the browser binary is present but system libraries (like `libatk`) are missing.
- Added strict `sudo`/`root` safeguards to `md2pdf init` to prevent crashes when automatically installing system dependencies in unprivileged Docker or CI environments.
- Added graceful fallback to the Playwright download prompt in `md2pdf init` if a system browser crashes during launch with an unknown error, allowing users to easily bypass corrupted system browsers.
- Fixed `md2pdf doctor` outputting overwhelming Playwright stack traces by intelligently truncating the GitHub issue template and providing exact install commands for missing dependencies.
- Added automatic detection of manually installed Playwright Chromium paths (`npx playwright install`) in the local cache, preventing `Browser Not Found` errors if the user manually installed a slightly different Playwright version.

## [0.9.2] - 2026-09-06
### Fixed
- Stabilized browser layer with full cross-platform discovery fallback logic
- Fixed Playwright version drift by injecting playwright-core version into the browser cache
- Fixed Mermaid initialization blocking the main thread during single/batch conversion rendering
- Added robust caching unit tests and browser discovery unit tests
- Fixed `md2pdf init` text indicating incorrect download size
- Fixed `md2pdf init` failing to install Linux system dependencies due to explicit sudo wrapper on NVM installs
- Fixed batch mode (`md2pdf *.md`) printing 30+ duplicate browser launch error messages instead of failing fast
- Fixed `pre-publish.sh` failing with Cannot find module package.json when executed from the scripts directory


## [0.9.1] - 2026-09-04

### Added
- `--stdin` flag: read markdown from stdin (pipe support).
  `echo "# Hello" | md2pdf --stdin -o out.pdf`
- Stdin is size-guarded at 30MB (same limit as files); excess is aborted
  without a hang.
- O(1) memory optimization for complexity depth validation: avoids call stack overflows and hangs when validating 30MB files by streaming string characters instead of splitting into massive arrays.

### Changed
- Maximum input file size raised from 5MB to 30MB. The old 5MB limit was
  too conservative for real-world technical documents and slide decks.
- UX icon system is now fully consistent across all commands:
  - `✔` success (conversion, cache hit, check passed)
  - `✖` error (file not found, conversion failed, permission denied)
  - `➖` skipped (publish: false, output already exists)
  - `⚠` warning (toc flags without --toc, output extension, SIGINT)
  - `ℹ` info (verbose pipeline steps, init header, doctor header)
  Previously batch.ts used `[ERR]` / `[INFO]` bracket-style prefixes
  and formatter.ts used `[ERR]` in the error box header.
- Dead code removed: `--stdout` and `--input` unsupported-option guards
  that were never reachable (those flags were never registered).

### Fixed
- Batch pre-validation failures now correctly increment `failedCount` and
  set `hasErrors = true`, so the exit code is 1 when any file fails.
  Previously the exit was 0 even when files were silently rejected.
- Duplicate validation-error loop in `batch.ts` (inserted by a previous
  patch) has been removed; each pre-validation failure is now counted once.
- `ERR_FILE_TOO_LARGE` with `--json-errors` now produces structured JSON
  output instead of 0 bytes on stdout with exit 0.
- Path traversal guard now fires even when the input file does not exist,
  closing a bypass vector (`md2pdf missing.md -o /etc/out.pdf`).
- `--quiet` flag suppresses spinner and success output as documented.
- Batch spinner is cleared before the summary line is printed.
- Pre-validation error lines are collected and printed after the spinner
  starts, so they appear inside the batch summary rather than before it.
- `doctor` browser cache mtime check now uses milliseconds (Date.now())
  not seconds, so the 24-hour cache skip works correctly.
- `init` non-interactive message changed from hyphen to period:
  "Non-interactive environment. Skipping config prompt."
- `-v` shorthand alias for `--version` removed to prevent future conflict
  with a planned `--verbose` shorthand.
- `--output <o>` placeholder in help text fixed to `--output <output>`.
- `--profile <n>` placeholder fixed to `--profile <name>`.
- Verbose debug prefixes `CORE-ERR` removed from error messages.

### Tests
- 16 new unit tests for `validation/input.ts` and `validation/output.ts`.
- `afterAll` cleanup hooks added to all contract test files.
- Empty `catch {}` blocks fixed (ESLint `no-empty` rule).
- Batch integration test timeout raised to 120 s to prevent flaky CI.

# Changelog

All notable changes to this project will be documented in this file.

## [0.9.0] - 2026-08-30

### Added
- Added `-q`, `--quiet` mode to suppress standard output for scripting environments.
- Added `--dry-run` flag to execute the conversion pipeline without writing to disk.
- Added `-v`, `--version` flag to CLI options.
- Added live progress percentages and ETAs to the batch conversion progress indicator.

### Fixed
- Fixed critical memory leak (timer leaks) in both the PluginRegistry and Mermaid Renderer when batch rendering large amounts of files.
- Fixed case-sensitive cache fragmentation on Windows/macOS.
- Enforced strict Plugin-aware processor cache hashing to prevent cross-plugin cache contamination.
- Neutralized the `EEXIST` crash when generating massive concurrent batches against missing directories.
- Ensured plugins are strictly sandboxed by trapping `Array.prototype.push` bypassing in deep readonly contexts.
- Hardened path traversal security to allow harmless prefix directories (like `/etc-backups/`) while still blocking traversal attacks against system roots like `/etc/`.
- Removed emojis and em-dashes from logging output to improve compatibility with strict terminal environments.
- Fixed process hang on non-TTY environments and edge cases throwing environment errors.
- Refactored `convert.ts` into modular single and batch handlers (`src/commands/handlers/`) to improve maintainability and CLI stability.
- Extracted core validation logic from CLI command into dedicated module (`src/validation/`).

## [0.8.10] - 2026-08-26
### Fixed
- Fixed CLI subcommand and flag consistency (`--list-themes` -> `list-themes`).
- Polished error formatting, standardizing on Title Case, boxed error messages, and catching raw Node.js stack traces.
- Fixed `doctor` to cache browser launch tests for 24h, check writability in `cwd`, and warn on `root` execution.
- Fixed `init` command prompt and spacing inconsistencies, and hardened filesystem write permissions in interactive mode.
- Intercepted early errors for `md2pdf help`, `--init`, and `--doctor` with better tips.
- Fixed JSON output error codes for batch operations.

## [0.8.9] - 2026-08-22

### Fixed
- File >5MB no longer hangs; the size check now correctly exits before the browser starts for single-file mode — missing continue caused the file to enter the pipeline after the check fired (BUG-1)
- Batch progress counter no longer overflows (e.g. 5/3); completedCount++ was called twice per file — once in the success path and again unconditionally at the bottom of the loop (BUG-6 regression)
- doc too complex now exits 2 without --json-errors; process.exit was being called inside a try/catch that silently swallowed it (BUG-8)
- Path traversal error is now rendered through the shared renderCliError formatter with correct box, error code, and run-with-verbose hint (BUG-NEW-3)
- Browser not found error is now rendered through renderCliError for consistent output (BUG-NEW-3)
- publish:false in single-file mode no longer shows - Converting... before the skip message; frontmatter is read before the spinner starts (BUG-NEW-4)
- Gray-matter ---js RCE block now shows the correct recommendation (Use YAML frontmatter) instead of the generic publish:true hint (BUG-NEW-7)
- md2pdf init now uses standard ℹ and ✔ symbols instead of home-grown [i] and [v] brackets (BUG-NEW-6)

## [0.8.8] - 2026-08-21

### Security
- Disabled gray-matter JavaScript frontmatter engine to prevent remote code execution via `---js` blocks in untrusted markdown files (VULN-1)
- Pinned mermaid to exact version 11.16.1 to guard against compromised upstream patch releases

### Fixed
- File larger than 5MB no longer hangs for 25 seconds before exiting; the size check now fires in the pre-flight loop before the browser starts (BUG-1)
- chmod 000 on a markdown file now shows the correct reason and recommendation instead of blaming the Playwright browser cache (BUG-3)
- bad yaml frontmatter now exits with code 1 (usage error) instead of code 2 (BUG-5)
- Batch progress counter no longer shows 0/N for the entire run; it increments correctly after each file completes (BUG-6)
- Duplicate spinner lines and duplicate skip messages for publish:false files are removed; exactly one message is emitted (BUG-4, BUG-7)
- doc too complex error now fires before cache lookup, so a previously cached complex document no longer exits 0 on warm cache (BUG-8)
- Batch --json-errors per-file code field is no longer the em-dash placeholder; errors carry the real error code (BUG-9)
- Verbose output prefix changed from [Verbose] bracket style to the standard info symbol to match the rest of the CLI (BUG-10)
- renderTimeMs in batch mode now measures wall-clock time from queue pickup to completion, including browser and Mermaid initialization (BUG-11)
- pre-publish.sh chmod 000 gate updated to expect exit code 2 to match the corrected behaviour


## [0.8.6] - 2026-08-15

### Fixed
- **Fixed Promise Hanging on Full Cache Hits:** Resolved an issue where background browser initialization promises would cause the CLI to hang indefinitely if the worker queue completed faster than the browser could launch.
- **Restored Obsidian Mermaid Compatibility:** Reintroduced AST preprocessing steps that cleanly handle unescaped quotes (`\"`) and empty parentheses (`()`) in Mermaid v11, fixing severe syntax errors on Obsidian-exported `mindmap` and `graph` markdown nodes.
- **Fixed Batch Execution Silent Failures:** Replaced standard `Promise.all` mapping in the worker queue with `Promise.allSettled` to elegantly catch unexpected application-level rejections (like filesystem panics) without swallowing the stack trace or crashing.
- **Repaired Error Exit Codes (Single & Batch Mode):** Batch failures correctly force `process.exitCode = 1` rather than succeeding if intermediate errors occurred. Single file fatal errors correctly bubble to the global error formatter instead of failing silently.
- **Fixed JSON Error Formatting:** Restructured the `renderCliError` logic to prevent `process.exit()` from bypassing browser cleanup protocols. Ensures filesystem errors (like `chmod 000`) correctly exit with code `2` instead of `0`.
- **Fixed Batch JSON Error Codes:** Added strict fallback mappings to individual file results within batch failures so that unhandled internal error objects never resolve to `code: undefined`.
- **NPM Audit Vulnerability Patch:** Upgraded nested high-severity dependencies (`brace-expansion`, `js-yaml`, `nanoid`, `postcss`, `esbuild`) resolving 5 major vulnerability vectors from upstream library chains.

## [0.8.5] - 2026-08-14

### Added
- **Universal Chromium Discovery:** The zero-config auto-discovery system has been massively expanded. It now natively scans default system installation paths across all major OS platforms (macOS, Windows, Linux) for 38 Chromium engines.
- **Intelligent Engine Enforcement:** Playwright's headless configuration can hang indefinitely when connecting to non-Chromium browsers via the CDP socket. md2pdf now features a fast runtime signature check that verifies the browser engine synchronously before attempting to launch it, failing gracefully instead of hanging.

### Fixed
- **Resilient Fallback Chains:** The browser fallback mechanism has been significantly fortified. Strict arbitrary timeouts have been removed to accommodate heavily loaded CI/CD runner environments that require more time to boot browsers. Invalid or stale browser cache paths are immediately evicted upon failed connections.
- **CLI Diagnostic Consistency:** The `md2pdf doctor` and `md2pdf init` commands fully inherit the new 38-browser matrix and engine enforcement rules, making debugging browser setups more transparent.
- **Playwright Launcher Fixes:** Fixed an issue where the `--browser` CLI flag wasn't properly mapping directly to the underlying Playwright launcher.
- **CI Pipeline Stabilizations:** Resolved CI pipeline timeouts affecting `windows-latest` and `ubuntu-latest` environments running `md2pdf` due to artificially constrained boot timeouts.

## [0.8.4] - 2026-08-13

### Fixed
- **JSON Output Formatting:** Refined `--json-errors` pipeline. All nested error objects now correctly format as `{ error: { message, code } }` instead of flattening, ensuring consistent schema compliance.
- **Log Routing Parity:** Messages indicating files skipped via `publish: false` frontmatter are now strictly routed to `stderr` (using `console.error`) rather than `stdout`, preserving pipe-safety for file contents.
- **Single-File Cache Optimization:** Substantially optimized the Incremental Rendering cache strategy for single-file conversions. The cache validation is now properly executed completely prior to any Playwright/Chromium instantiation, reducing "warm" cache response times to less than ~150ms.
- **Configuration Error Exit Codes:** Strengthened exit code enforcement. Malformed YAML frontmatter failures (`ERR_CONFIG_ERROR`) now accurately surface a standard exit code `1` (`EXIT.USAGE_ERROR`), correctly replacing an anomalous return value.

### Docs
- **Mermaid Documentation:** Expanded documentation explicitly detailing expected scaling, padding, and layout engine variations users might observe upgrading to Mermaid v11.
- **Documentation Overhaul:** Thoroughly reviewed and corrected language and formatting conventions across the entire documentation suite (`/docs` and `README.md`) to be more concise and professional.


## [0.8.3] - 2026-08-12

### Fixed
- **Browser Initialization**: Resolved Playwright `TypeError: Cannot read properties of undefined (reading 'newContext')` during Mermaid warmup in concurrent batch processes.
- **Cache Logging**: Corrected an issue where cache hits were not being reported in batch mode due to relative output path discrepancies. Cache hits now print cleanly in milliseconds.
- **Type Safety**: Cleaned up dangling variables and globally disabled the `any` ESLint warning.

## [0.8.2] - 2026-08-09

### Fixed
- **Cache Optimization**: Skipped Playwright browser startup when all files in a batch are already cached, completely eliminating overhead for 100% cache hits.
- **Browser Resolution**: Cached the fully resolved browser executable path to prevent Playwright from initiating a fallback waterfall search on every cold start when Chrome is missing.
- **CLI Ergonomics**: Running \`md2pdf\` without arguments now correctly prints the help menu and exits with code 1 instead of 0.
- **CLI Robustness**: Passing an existing directory to \`--output\` in single-file mode now correctly throws a fatal error instead of silently generating unexpected file paths.
- **Data Integrity**: JSON \`--json-errors\` output now correctly maps and increments the skipped count when \`publish: false\` is used.
- **Parser Resilience**: Added a strict depth limit (200) to pathological nested blockquotes to prevent AST call-stack overflow crashes (\`ERR_DOCUMENT_TOO_COMPLEX\`).
- **Asset Resolution**: Fixed an issue where Mermaid assets (\`mermaid.min.js\`) failed to resolve in distributed bundles due to improper pathing.
- **Unified Errors**: Unified the \`--json-errors\` output schema across all error code paths.

## [0.8.0] - 2026-08-08

### Added
- **Incremental Rendering Cache**: Implemented a robust content-hash based caching system (centralized in the OS temp directory) to significantly speed up batch conversions by automatically skipping unmodified files.
- **Cache Management CLI**: Added `--no-cache` flag to bypass the cache and force a complete re-render, and `--clear-cache` to wipe all stored cache records.

### Fixed
- **Parallel Diagram Rendering**: Re-architected Mermaid rendering for high-concurrency environments. Implemented a strict Mutex lock to serialize `page.evaluate` requests and utilized uniquely generated DOM IDs, entirely eliminating race conditions and visual layout corruption when processing multiple diagrams in parallel.
- **CLI Options Integrity**: Fixed an issue where the `--no-cache` flag would be dropped during configuration merging.
- **Automated Cache Cleanup**: The temporary cache directory is now cleanly purged upon running `npm uninstall -g @amitdevx/md2pdf`.

## [0.7.1] - 2026-08-03

### Fixed
- **Plugin Security (Sandboxing Escape)**: Plugins accessing the Playwright `Page` object in the `afterPageLoad` hook are now restricted via a Javascript Proxy. Destructive methods (`close`, `goto`, `pdf`) are aggressively blocked, throwing a `PluginSecurityError`.
- **Plugin Security (Context Mutability)**: Implemented a deep-readonly Proxy for `RenderContext`. Malicious or poorly designed plugins can no longer overwrite core engine options or configurations during runtime.
- **Resilience (Infinite Loops)**: All asynchronous plugin hooks are now aggressively wrapped in a 10,000ms `Promise.race` timeout to prevent single plugins from permanently hanging the batch processing CLI.
- **Resilience (Broken Initialization)**: Plugins that throw an error during the `setup()` initialization phase are now automatically evicted from the active registry and will not trigger cascading failures during the render pipeline.
- **Resilience (Type Integrity)**: Implemented strict runtime Zod-style type verification on hook return values. If `beforeRender` does not return a string, or `afterPdf` does not return a Buffer, the pipeline immediately aborts rather than feeding corrupted memory downstream to libraries like `pdf-lib`.
- **Resilience (Error Swallowing)**: Unhandled plugin hook errors now correctly propagate and abort the current file's generation, rather than silently failing and producing incomplete PDFs.

## [0.7.0] - 2026-07-31

### Added
- **Plugin Infrastructure**: A fully documented, stable plugin API exposing `MarkdownPlugin`, `HtmlPlugin`, `RenderPlugin`, `ThemePlugin`, and `ExportPlugin`. Hook into AST generation, inject custom HTML rendering logic, or modify the Playwright rendering lifecycle.
- **Plugin Registry**: Added internal registry and lifecycle hooks (`setup`, `beforeRender`, `afterPageLoad`, `afterPdf`, `teardown`).
- **Configuration Mapping**: Ensured `plugins` array correctly maps from Zod configuration to the internal `ConvertOptions`.

## [0.6.1] - 2026-07-20

### Added
- **Theming System**: Introduced 7 professionally crafted built-in themes (`default`, `github`, `obsidian-light`, `obsidian-dark`, `dracula`, `nord`, `academic`).
- **Dynamic Syntax Highlighting**: Shiki grammars are now dynamically detected and loaded on-the-fly, reducing compilation overhead.
- **Strict Obsidian Parity**: Flawless visual alignment with Obsidian's native exports, including Lucide SVG callout icons.
- **Improved Layout Engine**: Mermaid diagrams now naturally left-align, and large tables gracefully span across page breaks with repeating headers.

## [0.5.0] - 2026-07-12

### Added
- **Batch Processing**: Convert multiple Markdown files at once using globs (e.g., `md2pdf "docs/*.md" -o out_dir/`).
- **Browser Re-use**: Significantly optimized performance during batch processing by intelligently re-using a single headless Chromium instance.
- **Lazy-Loaded Mermaid Processing**: Completely eliminated Cold Start Lag by lazily instantiating the `sharedMermaidPage` only when Markdown files actually contain diagrams.
- **Persistent Configuration System**: Discovers and loads configuration automatically (`md2pdf.config.ts`, `.md2pdfrc.json`, `.md2pdfrc.yaml`, or `package.json`).
- **TypeScript Support**: Exposed `defineConfig` for typed programmatic config authoring.
- **Profiles**: Added `--profile <name>` CLI option to switch between configuration presets dynamically.

### Fixed
- Fixed an issue where the CLI would hang on `SIGINT` (Ctrl+C), leaving invisible Zombie Chromium processes running in RAM.
- Fixed a massive memory leak and garbage collection spike during batch processing by ensuring Playwright contexts are gracefully closed inside `finally` blocks.
- Fixed an issue where CLI options would mistakenly override file-level YAML frontmatter; frontmatter now correctly takes precedence.
- Fixed a bug causing large Mermaid diagrams to split across pages by ensuring `maxWidth` and `maxHeight` properties correctly propagate through the configuration merger.
- Fixed metadata injection crashing when `keywords` was provided as an array in a configuration file.
- Removed strict validation from `--mermaid-theme` CLI flag to properly support custom user CSS themes defined via `md2pdf.config.ts`.
- Ensured properties like KaTeX `numbering` and Obsidian `embedNotes` correctly map through the configuration merger.

## [0.4.2] - 2026-07-11

### Added
- Explicit handlers for unsupported flags (`--browser`, `--stdin`, `--stdout`, `--quiet`, `--input`) to output clear `InvalidArgumentError` messages rather than crashing.
- New `publish-gpr` GitHub Actions CI job to seamlessly publish the npm package to GitHub Packages in parallel.

### Fixed
- Rebuilt the `dist/` artifacts so that `md2pdf --version` accurately reports `0.4.2`.
- Added a 5MB size limit to Markdown inputs before unified/AST parsing to prevent severe V8 OOM aborts on exceptionally large files.

## [0.4.1] - 2026-07-10

### Added
- Native AST parsing support for Obsidian highlight syntax (`==highlight==`) translated to HTML `<mark>` tags.
- Root user sandboxing detection to auto-inject `--no-sandbox` if Playwright Chromium runs via `sudo` on Linux.

### Fixed
- Fixed CLI test assertions failing in GitHub CI because of updated Commander error string outputs.

## [0.4.0] - 2026-07-10

### Added
- Complete Obsidian Markdown interoperability layer (v0.4.0 & v0.4.1 phase plans).
- Transclusion and embedding of external markdown notes (`![[note.md]]`) and images.
- Full cycle detection and warning fallback for infinite circular embeds (`circular-1.md` -> `circular-2.md`).
- Clickable and natively styled internal Wiki links (`[[Link]]` and `[[Link|Alias]]`).
- 10 variations of Obsidian-styled blockquote callouts (`> [!WARNING]`).
- Inline and nested tags (`#tag`, `#nested/tag`) with dynamic styling (hiding supported via `--hide-tags`).
- Template variable injection in headers and footers (e.g. `{frontmatter.author}`).
- CLI flags for vault awareness: `--vault-root`, `--attachment-folder`, `--max-attachment-size`.

## [0.3.0] - 2026-07-08

### Added
- Native support for Math blocks (KaTeX) using `remark-math` and `rehype-katex`.
- Support for mhchem plugin for chemical equations (`\ce{H2O}`).
- CLI option `--no-math` to disable Math rendering.

## [0.2.0] - 2026-07-03

### Added
- Mermaid diagram rendering using headless Playwright evaluation.
- SVG inlining for lossless, selectable Mermaid graphs in the PDF.
- Theme overrides for Mermaid diagrams via `--mermaid-theme`.

## [0.1.6] - 2026-06-29

### Added
- `--paper` strict runtime option validation (`A4`, `Letter`, `Legal`).
- `--margin` robust unit validation (CSS units `mm`, `cm`, `in`, `px`, `pt`, `em`, etc.).
- Explicit `stdin` (`-`) input validation and user-friendly error guidance.
- Output directory auto-creation warning and overwrite existing file warning.
- Success messages now print the fully resolved absolute path to the generated PDF.

### Fixed
- Fixed silent npm `postinstall` output by explicitly using `process.stderr.write` to announce Chromium checks and readiness.
- Fixed an issue where `.txt` and binary files incorrectly triggered a "same file" error by adding an explicit `.md` extension check.
- Fixed `EACCES` permission denied errors on input files to display actionable `chmod` guidance instead of raw stack traces.
- Fixed trailing slash output path issue where a hidden dotfile (`.pdf`) was created in directories like `/tmp/`.
- Fixed `YAMLException` multiline parsing escape from `\\n` to `\n` to cleanly show the first line of YAML syntax errors.
- Fixed TOC indentation compounding and `pruneEmpty` runtime crash by verifying element types and emitting a semantically nested `<ul>` tree.
- Changed `h1NewPage` default to `false` and exposed `--h1-new-page` CLI option to avoid unexpected breaking page breaks.

## [0.1.5] - 2026-06-29

### Fixed
- Fixed an issue where the `postinstall` script skipped downloading Chromium because the `npm_config_global` check silently evaluated to false on some systems. The guard has been removed, relying on Playwright's native cache to avoid redundant downloads.

## [0.1.4] - 2026-06-29

### Fixed
- Fixed an issue where Playwright Chromium binaries were not automatically downloaded during a global `npm install -g`, causing a failure on first run.
- Added a `postinstall` script to seamlessly download the required Chromium dependencies.
- Added a fallback guard so local project installations do not forcefully download Chromium.
- Improved CLI error handling to gracefully detect missing browsers and provide actionable installation commands instead of raw stack traces.

## [0.1.3] - 2026-06-28

### Added
- Running Headers and Footers support (`--header`, `--footer`).
- Manual Page Breaks via `<!-- pagebreak -->`.
- Automatic Page Breaks before `h1` and optionally `hr`.
- Robust HTML escaping for metadata titles.
- Dynamic version inference for PDF creator metadata.

### Fixed
- Fixed bug where PDF metadata merge overwrote earlier fields.
- Fixed `__dirname` resolution in ESM tests.

## [0.1.1] - 2026-06-28

### Added
- Table of Contents generation via `--toc`, `--toc-depth`, and `--toc-title`.
- Native GFM Footnotes support with bidirectional backlinks.
- YAML frontmatter parsing via `gray-matter`.
- PDF metadata injection using `pdf-lib` (Title, Author, Subject, Keywords).
- Heading stable IDs generated automatically via `rehype-slug`.

## [0.1.0] - 2026-06-27

### Added
- Shiki-based syntax highlighting for 20+ languages (`github-light` and `one-dark-pro` fallbacks).
- Visual golden document testing suite (`tests/fixtures/`).
- Safely encodes URI paths for local images containing spaces.
- Print CSS improvements for preserving code blocks across pagination boundaries.
- Task list specific styling to prevent double-bullets.

## [0.0.1] - 2026-06-26

### Added
- Core Markdown to PDF rendering engine using Playwright.
- Programmatic API `convert(options)`.
- CLI via `md2pdf <file>` command.
- AST-based parsing pipeline using `unified`, `remark`, and `rehype`.
- Default professional print typography and theme.
- Support for GitHub Flavored Markdown (tables, strikethrough).
- Resolution of local relative image paths.
- Comprehensive configuration for `tsup`, `vitest`, `eslint`, and `prettier`.
- GitHub Actions CI workflow for linting, building, and testing.

## [0.9.0] - 2026-08-30
### Refactor
- Orchestration logic extracted from monolithic `src/commands/convert.ts`.
- Validation fully extracted into dedicated modules `src/validation/input.ts`, `src/validation/output.ts`, `src/validation/flags.ts`, and `src/validation/index.ts`.
- Cache module relocated from `src/core/cache.ts` to `src/cache/index.ts`.

### Testing
- Built a comprehensive Contract Testing suite in `tests/contract/`.
- 27 matrix tests added for exit-codes covering all error paths and combinations.
- 20 matrix tests added for json-errors covering structured error propagation.

### Fixes
- Addressed hang on missing permissions and 5MB payload limit by hoisting validation before playwright browser launch.
- Assured 100% adherence to established exit code contract.
