fix(#404): remove stale --pdf-output-folder flag from md-to-pdf dispatch#405
Conversation
md-to-pdf removed --pdf-output-folder and --dest-name in a breaking API change; convert.sh still passed both flags, causing every npx md-to-pdf invocation to abort with: ArgError: unknown or unexpected option: --pdf-output-folder Fix: stage the source into a private temp dir under the desired output stem (e.g. WORK/out.pdf → WORK/out.md), invoke `npx -y md-to-pdf <tmp>.md`, then mv the resulting <tmp>.pdf to the requested TO_ABS. md-to-pdf writes <basename>.pdf next to the source by default, so this is compatible with every currently-released version. The same fix is applied to the md-to-pdf-html branch (HTML → PDF fallback), which had identical stale flags. Adds regression test at .claude/skills/pdf/tests/test_md_to_pdf_fallback.sh covering four cases: successful conversion, absence of the stale --pdf-output-folder flag, absence of --dest-name, and custom output path resolution. All four pass locally against the current npm latest. Refs #404 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
atlas-apex
left a comment
There was a problem hiding this comment.
Code Review: PR #405
Commit: 6e9e42eca66ae0b62c69ba91652065bcb9fc22ca
Summary
Removes stale --pdf-output-folder and --dest-name flags from both md-to-pdf dispatch branches in convert.sh (markdown and HTML inputs). Replaces with a stage-in-temp-dir strategy: copy source to $WORK/<out_stem>.{md,html}, invoke npx -y md-to-pdf <tmp_src>, then mv the resulting $WORK/<out_stem>.pdf to TO_ABS. Adds 4-case regression test at .claude/skills/pdf/tests/test_md_to_pdf_fallback.sh.
Checklist Results
- Architecture & Design: Pass
- Code Quality: Pass
- Testing: Pass
- Security: Pass (no new attack surface — same external-process invocation pattern, no new args derived from untrusted input)
- Performance: Pass (one extra
cpto temp dir, negligible) - PR Description & Glossary: Pass (Summary, Testing, Closes #404, Glossary all present)
- Summary Bullet Narrative: Pass (all 4 bullets are verb + >6 words + rationale)
- Technical Decisions (AgDR): N/A (no new dependency, no new pattern — bug fix that restores the documented contract)
- Adopter Handbooks: N/A (no handbooks in this repo affect
.claude/skills/pdf/)
Verification
-
Diff scope is correct — only
.claude/skills/pdf/convert.sh(+25 / -21) and the new.claude/skills/pdf/tests/test_md_to_pdf_fallback.sh(+168). No incidental edits to other skills, hooks, rules, agents, orsite/. -
The fix works — the new
md-to-pdfbranch (lines ~250-270 in head) computesout_stemfromTO_ABS, copies source to$WORK/<out_stem>.md, invokesnpx -y md-to-pdf "$tmp_src"with no removed flags. md-to-pdf's default behaviour (write<source-basename>.pdfnext to source) lands the result deterministically at$WORK/<out_stem>.pdf= the variabletmp_out, which is thenmv'd toTO_ABS. The old "some versions of md-to-pdf output as<basename>.pdf" double-check fallback is removed, which is correct now that the source basename and the expected output are aligned by construction (no longer two competing locations). Same fix applied symmetrically tomd-to-pdf-htmlbranch. -
Exit codes preserved — all exit points still use 0/1/2/3 per the SKILL.md contract. The temp-dir cleanup is handled by the existing
trap 'rm -rf "$WORK"' EXITat line ~218, so both success and failure paths clean up automatically. -
Graceful degrade unchanged —
choose_for_markdownstill prefers pandoc, falls through to md-to-pdf, exits 3 withprint_install_advisoryif neither is available. The fix only changes how the md-to-pdf branch invokes the binary, not the dispatch logic. -
Regression test is high quality — forces the md-to-pdf path via
--converter=md-to-pdf; gates oncommand -v npxat top (skips cleanly on Node-less hosts); per-test handling of exit 3 (md-to-pdf network/install failure) as a skip rather than a hard fail; trap cleans up$FIXTURE. Tests B and C explicitly grep stderr for the removed flag names — this is a strong assertion that catches regression even if md-to-pdf's CLI changes again in a way that happens to ignore unknown flags silently. Test D verifies output lands at exactly the requested--topath including a nested subdir.
Issues Found
None.
Suggestions
None blocking. One edge-case observation for the next person who touches this code: out_stem="$(basename "${TO_ABS%.*}")" derives the stem from the destination path; if a caller passes --to=/tmp/foo with no extension, ${TO_ABS%.*} returns the path unchanged and the temp file becomes $WORK/foo.md → $WORK/foo.pdf → mv to /tmp/foo. Works correctly, just worth knowing.
Verdict
APPROVED
Reviewed by Rex (Code Reviewer Agent)
Reviewed commit: 6e9e42eca66ae0b62c69ba91652065bcb9fc22ca
* fix(#404): remove stale --pdf-output-folder flag from md-to-pdf dispatch (#405) md-to-pdf removed --pdf-output-folder and --dest-name in a breaking API change; convert.sh still passed both flags, causing every npx md-to-pdf invocation to abort with: ArgError: unknown or unexpected option: --pdf-output-folder Fix: stage the source into a private temp dir under the desired output stem (e.g. WORK/out.pdf → WORK/out.md), invoke `npx -y md-to-pdf <tmp>.md`, then mv the resulting <tmp>.pdf to the requested TO_ABS. md-to-pdf writes <basename>.pdf next to the source by default, so this is compatible with every currently-released version. The same fix is applied to the md-to-pdf-html branch (HTML → PDF fallback), which had identical stale flags. Adds regression test at .claude/skills/pdf/tests/test_md_to_pdf_fallback.sh covering four cases: successful conversion, absence of the stale --pdf-output-folder flag, absence of --dest-name, and custom output path resolution. All four pass locally against the current npm latest. Refs #404 Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(#403): /release-sync — main→dev sync after each release (#406) * feat(#403): /release-sync skill — main→dev sync after each release Introduces the /release-sync skill to address squash-merge divergence that accumulated across releases and produced 99 conflicts on the v2.0.0 release PR. After each release, /release-sync vX.Y.Z opens a sync PR that merges upstream/main into upstream/dev with -X ours (dev wins on conflicts), making the squash commit an ancestor of dev so future release PRs only show genuinely-new commits. - .claude/skills/release-sync/SKILL.md — new skill spec with pre-flight checks, idempotent no-op, edge-case table, and PR body template - .claude/skills/release/SKILL.md — adds Step 9 (mandatory invoke of /release-sync) and updates Related section - docs/agdr/AgDR-0052-release-sync-skill.md — records the design choice (explicit skill vs auto-invoke vs switch-to-merge-commit) and the merge-strategy direction reasoning (-X ours on a dev-based branch) - .claude/hooks/tests/test_release_sync.sh — 11 sandbox-based smoke tests covering already-in-sync no-op, diverged detection, branch name shape, -X ours direction, idempotence, post-sync state, and version argument validation; all 11 pass Refs #403 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#403): refresh site skill-count (54→55) + 2 MD032 lint fixes Address red CI on Rex-approved release-sync PR: - site-counts drift: new /release-sync skill bumps total to 55. Update all 12 marketing-copy references across architecture.html, *.md.gen, llms.txt, llms-full.txt, skill.md (incl. 2 multiline / phrasing-variant references caught by the post-#377 cross-newline scanner). - markdownlint MD032: add blank lines around the bullet lists in release-sync SKILL.md (line 80) and AgDR-0052 (line 36). Refs #403 --------- Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(#408): CHANGELOG v2.1.0 + site version pill bump - Append [2.1.0] section above [2.0.2] - Bump site/index.html version pill v2.0.2 → v2.1.0 - Last cherry-pick release; /release-sync now live for v2.2.x+ Refs #408 --------- Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(me2resh#404): remove stale --pdf-output-folder flag from md-to-pdf dispatch (me2resh#405) md-to-pdf removed --pdf-output-folder and --dest-name in a breaking API change; convert.sh still passed both flags, causing every npx md-to-pdf invocation to abort with: ArgError: unknown or unexpected option: --pdf-output-folder Fix: stage the source into a private temp dir under the desired output stem (e.g. WORK/out.pdf → WORK/out.md), invoke `npx -y md-to-pdf <tmp>.md`, then mv the resulting <tmp>.pdf to the requested TO_ABS. md-to-pdf writes <basename>.pdf next to the source by default, so this is compatible with every currently-released version. The same fix is applied to the md-to-pdf-html branch (HTML → PDF fallback), which had identical stale flags. Adds regression test at .claude/skills/pdf/tests/test_md_to_pdf_fallback.sh covering four cases: successful conversion, absence of the stale --pdf-output-folder flag, absence of --dest-name, and custom output path resolution. All four pass locally against the current npm latest. Refs me2resh#404 Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(me2resh#403): /release-sync — main→dev sync after each release (me2resh#406) * feat(me2resh#403): /release-sync skill — main→dev sync after each release Introduces the /release-sync skill to address squash-merge divergence that accumulated across releases and produced 99 conflicts on the v2.0.0 release PR. After each release, /release-sync vX.Y.Z opens a sync PR that merges upstream/main into upstream/dev with -X ours (dev wins on conflicts), making the squash commit an ancestor of dev so future release PRs only show genuinely-new commits. - .claude/skills/release-sync/SKILL.md — new skill spec with pre-flight checks, idempotent no-op, edge-case table, and PR body template - .claude/skills/release/SKILL.md — adds Step 9 (mandatory invoke of /release-sync) and updates Related section - docs/agdr/AgDR-0052-release-sync-skill.md — records the design choice (explicit skill vs auto-invoke vs switch-to-merge-commit) and the merge-strategy direction reasoning (-X ours on a dev-based branch) - .claude/hooks/tests/test_release_sync.sh — 11 sandbox-based smoke tests covering already-in-sync no-op, diverged detection, branch name shape, -X ours direction, idempotence, post-sync state, and version argument validation; all 11 pass Refs me2resh#403 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(me2resh#403): refresh site skill-count (54→55) + 2 MD032 lint fixes Address red CI on Rex-approved release-sync PR: - site-counts drift: new /release-sync skill bumps total to 55. Update all 12 marketing-copy references across architecture.html, *.md.gen, llms.txt, llms-full.txt, skill.md (incl. 2 multiline / phrasing-variant references caught by the post-me2resh#377 cross-newline scanner). - markdownlint MD032: add blank lines around the bullet lists in release-sync SKILL.md (line 80) and AgDR-0052 (line 36). Refs me2resh#403 --------- Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(me2resh#408): CHANGELOG v2.1.0 + site version pill bump - Append [2.1.0] section above [2.0.2] - Bump site/index.html version pill v2.0.2 → v2.1.0 - Last cherry-pick release; /release-sync now live for v2.2.x+ Refs me2resh#408 --------- Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…tch (#405) md-to-pdf removed --pdf-output-folder and --dest-name in a breaking API change; convert.sh still passed both flags, causing every npx md-to-pdf invocation to abort with: ArgError: unknown or unexpected option: --pdf-output-folder Fix: stage the source into a private temp dir under the desired output stem (e.g. WORK/out.pdf → WORK/out.md), invoke `npx -y md-to-pdf <tmp>.md`, then mv the resulting <tmp>.pdf to the requested TO_ABS. md-to-pdf writes <basename>.pdf next to the source by default, so this is compatible with every currently-released version. The same fix is applied to the md-to-pdf-html branch (HTML → PDF fallback), which had identical stale flags. Adds regression test at .claude/skills/pdf/tests/test_md_to_pdf_fallback.sh covering four cases: successful conversion, absence of the stale --pdf-output-folder flag, absence of --dest-name, and custom output path resolution. All four pass locally against the current npm latest. Refs #404 Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(me2resh#404): remove stale --pdf-output-folder flag from md-to-pdf dispatch (me2resh#405) md-to-pdf removed --pdf-output-folder and --dest-name in a breaking API change; convert.sh still passed both flags, causing every npx md-to-pdf invocation to abort with: ArgError: unknown or unexpected option: --pdf-output-folder Fix: stage the source into a private temp dir under the desired output stem (e.g. WORK/out.pdf → WORK/out.md), invoke `npx -y md-to-pdf <tmp>.md`, then mv the resulting <tmp>.pdf to the requested TO_ABS. md-to-pdf writes <basename>.pdf next to the source by default, so this is compatible with every currently-released version. The same fix is applied to the md-to-pdf-html branch (HTML → PDF fallback), which had identical stale flags. Adds regression test at .claude/skills/pdf/tests/test_md_to_pdf_fallback.sh covering four cases: successful conversion, absence of the stale --pdf-output-folder flag, absence of --dest-name, and custom output path resolution. All four pass locally against the current npm latest. Refs me2resh#404 Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(me2resh#403): /release-sync — main→dev sync after each release (me2resh#406) * feat(me2resh#403): /release-sync skill — main→dev sync after each release Introduces the /release-sync skill to address squash-merge divergence that accumulated across releases and produced 99 conflicts on the v2.0.0 release PR. After each release, /release-sync vX.Y.Z opens a sync PR that merges upstream/main into upstream/dev with -X ours (dev wins on conflicts), making the squash commit an ancestor of dev so future release PRs only show genuinely-new commits. - .claude/skills/release-sync/SKILL.md — new skill spec with pre-flight checks, idempotent no-op, edge-case table, and PR body template - .claude/skills/release/SKILL.md — adds Step 9 (mandatory invoke of /release-sync) and updates Related section - docs/agdr/AgDR-0052-release-sync-skill.md — records the design choice (explicit skill vs auto-invoke vs switch-to-merge-commit) and the merge-strategy direction reasoning (-X ours on a dev-based branch) - .claude/hooks/tests/test_release_sync.sh — 11 sandbox-based smoke tests covering already-in-sync no-op, diverged detection, branch name shape, -X ours direction, idempotence, post-sync state, and version argument validation; all 11 pass Refs me2resh#403 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(me2resh#403): refresh site skill-count (54→55) + 2 MD032 lint fixes Address red CI on Rex-approved release-sync PR: - site-counts drift: new /release-sync skill bumps total to 55. Update all 12 marketing-copy references across architecture.html, *.md.gen, llms.txt, llms-full.txt, skill.md (incl. 2 multiline / phrasing-variant references caught by the post-me2resh#377 cross-newline scanner). - markdownlint MD032: add blank lines around the bullet lists in release-sync SKILL.md (line 80) and AgDR-0052 (line 36). Refs me2resh#403 --------- Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(me2resh#408): CHANGELOG v2.1.0 + site version pill bump - Append [2.1.0] section above [2.0.2] - Bump site/index.html version pill v2.0.2 → v2.1.0 - Last cherry-pick release; /release-sync now live for v2.2.x+ Refs me2resh#408 --------- Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
--pdf-output-folderand--dest-nameflags fromconvert.sh— md-to-pdf removed both flags in a breaking API change; every invocation of the md-to-pdf fallback path was aborting withArgError: unknown or unexpected option: --pdf-output-folder, meaning/pdfwas entirely broken for the majority of adopters who don't have pandoc installed (common on macOS where pandoc pulls in LaTeX dependencies)$WORKdir under the desired output stem,npx -y md-to-pdf <tmp>.mdis invoked there (md-to-pdf writes<stem>.pdfnext to the source by default), then the result ismv'd to the requestedTO_ABS; this is compatible with the current md-to-pdf API and avoids any cwd or output-name collisionsmd-to-pdf-htmlbranch — the HTML → PDF fallback path had identical stale flags and is fixed with the same staging pattern.claude/skills/pdf/tests/test_md_to_pdf_fallback.sh— covers 4 cases: successful conversion, absence of--pdf-output-folder, absence of--dest-name, and custom output path landing at exactly the requested--topath; all 4 pass locally against npmlatestTesting
Closes #404
Glossary
md-to-pdf/pdfas the no-pandoc fallback.--pdf-output-folderconvert.shwas still passing it, causing anArgErroron every invocation of the fallback path.--dest-name--pdf-output-folderto name the output file. Removed in the same fix.stage-in-temp-dir strategy$WORK/<desired-stem>.md, runnpx md-to-pdfthere, thenmv$WORK/<desired-stem>.pdfto the requested output path. Relies on md-to-pdf's default behaviour of writing<source-basename>.pdfnext to the source.graceful degrade/pdfuses: try each converter in order, fall through on missing-dep; only exit non-zero if NO converter is installed. The stale flags were causing the md-to-pdf branch to error (exit 1) instead of degrade (exit 3).