diff --git a/make-pdf/SKILL.md b/make-pdf/SKILL.md index 6883ea16a..90e10efdf 100644 --- a/make-pdf/SKILL.md +++ b/make-pdf/SKILL.md @@ -102,6 +102,42 @@ echo "CHECKPOINT_PUSH: $_CHECKPOINT_PUSH" [ -n "$OPENCLAW_SESSION" ] && echo "SPAWNED_SESSION: true" || true ``` +## MAKE-PDF SETUP (run this check BEFORE any make-pdf command) + +```bash +_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) +P="" +[ -n "$MAKE_PDF_BIN" ] && [ -x "$MAKE_PDF_BIN" ] && P="$MAKE_PDF_BIN" +[ -z "$P" ] && [ -n "$_ROOT" ] && [ -x "$_ROOT/.claude/skills/gstack/make-pdf/dist/pdf" ] && P="$_ROOT/.claude/skills/gstack/make-pdf/dist/pdf" +[ -z "$P" ] && P="$HOME/.claude/skills/gstack/make-pdf/dist/pdf" +if [ -x "$P" ]; then + echo "MAKE_PDF_READY: $P" + alias _p_="$P" # shellcheck alias helper (not exported) + export P # available as $P in subsequent blocks within the same skill invocation +else + echo "MAKE_PDF_NOT_AVAILABLE (run './setup' in the gstack repo to build it)" +fi +``` + +If `MAKE_PDF_NOT_AVAILABLE` is printed: tell the user the binary is not +built. Have them run `./setup` from the gstack repo, then retry. + +If `MAKE_PDF_READY` is printed: `$P` is the binary path for the rest of +the skill. Use `$P` (not an explicit path) so the skill body stays portable. + +Core commands: +- `$P generate [output.pdf]` — render markdown to PDF (80% use case) +- `$P generate --cover --toc essay.md out.pdf` — full publication layout +- `$P generate --watermark DRAFT memo.md draft.pdf` — diagonal DRAFT watermark +- `$P preview ` — render HTML and open in browser (fast iteration) +- `$P setup` — verify browse + Chromium + pdftotext and run a smoke test +- `$P --help` — full flag reference + +Output contract: +- `stdout`: ONLY the output path on success. One line. +- `stderr`: progress (`Rendering HTML... Generating PDF...`) unless `--quiet`. +- Exit 0 success / 1 bad args / 2 render error / 3 Paged.js timeout / 4 browse unavailable. + ## Plan Mode Safe Operations In plan mode, allowed because they inform the plan: `$B`, `$D`, `codex exec`/`codex review`, writes to `~/.gstack/`, writes to the plan file, and `open` for generated artifacts. @@ -489,42 +525,6 @@ On Linux, install `fonts-liberation` for correct rendering — Helvetica and Ari aren't present by default, and Liberation Sans is the standard metric-compatible fallback. CI and Docker builds install it automatically via Dockerfile.ci. -## MAKE-PDF SETUP (run this check BEFORE any make-pdf command) - -```bash -_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) -P="" -[ -n "$MAKE_PDF_BIN" ] && [ -x "$MAKE_PDF_BIN" ] && P="$MAKE_PDF_BIN" -[ -z "$P" ] && [ -n "$_ROOT" ] && [ -x "$_ROOT/.claude/skills/gstack/make-pdf/dist/pdf" ] && P="$_ROOT/.claude/skills/gstack/make-pdf/dist/pdf" -[ -z "$P" ] && P="$HOME/.claude/skills/gstack/make-pdf/dist/pdf" -if [ -x "$P" ]; then - echo "MAKE_PDF_READY: $P" - alias _p_="$P" # shellcheck alias helper (not exported) - export P # available as $P in subsequent blocks within the same skill invocation -else - echo "MAKE_PDF_NOT_AVAILABLE (run './setup' in the gstack repo to build it)" -fi -``` - -If `MAKE_PDF_NOT_AVAILABLE` is printed: tell the user the binary is not -built. Have them run `./setup` from the gstack repo, then retry. - -If `MAKE_PDF_READY` is printed: `$P` is the binary path for the rest of -the skill. Use `$P` (not an explicit path) so the skill body stays portable. - -Core commands: -- `$P generate [output.pdf]` — render markdown to PDF (80% use case) -- `$P generate --cover --toc essay.md out.pdf` — full publication layout -- `$P generate --watermark DRAFT memo.md draft.pdf` — diagonal DRAFT watermark -- `$P preview ` — render HTML and open in browser (fast iteration) -- `$P setup` — verify browse + Chromium + pdftotext and run a smoke test -- `$P --help` — full flag reference - -Output contract: -- `stdout`: ONLY the output path on success. One line. -- `stderr`: progress (`Rendering HTML... Generating PDF...`) unless `--quiet`. -- Exit 0 success / 1 bad args / 2 render error / 3 Paged.js timeout / 4 browse unavailable. - ## Core patterns ### 80% case — memo/letter diff --git a/make-pdf/SKILL.md.tmpl b/make-pdf/SKILL.md.tmpl index 0827492a8..d134ee62a 100644 --- a/make-pdf/SKILL.md.tmpl +++ b/make-pdf/SKILL.md.tmpl @@ -41,8 +41,6 @@ On Linux, install `fonts-liberation` for correct rendering — Helvetica and Ari aren't present by default, and Liberation Sans is the standard metric-compatible fallback. CI and Docker builds install it automatically via Dockerfile.ci. -{{MAKE_PDF_SETUP}} - ## Core patterns ### 80% case — memo/letter diff --git a/scripts/resolvers/preamble.ts b/scripts/resolvers/preamble.ts index b866e90b1..97698bfcf 100644 --- a/scripts/resolvers/preamble.ts +++ b/scripts/resolvers/preamble.ts @@ -58,6 +58,7 @@ import { generateContextHealth } from './preamble/generate-context-health'; // Tier 3+ repo mode + search import { generateRepoModeSection } from './preamble/generate-repo-mode-section'; import { generateSearchBeforeBuildingSection } from './preamble/generate-search-before-building'; +import { generateMakePdfSetup } from './make-pdf'; // Standalone export used directly by the resolver registry export { generateTestFailureTriage } from './preamble/generate-test-failure-triage'; @@ -81,7 +82,8 @@ export function generatePreamble(ctx: TemplateContext): string { } const sections = [ generatePreambleBash(ctx), - // Plan-mode-skill semantics at position 1: after bash (so _SESSION_ID / + ...(ctx.skillName === 'make-pdf' ? [generateMakePdfSetup(ctx)] : []), + // Plan-mode-skill semantics stays near the top: after bash (so _SESSION_ID / // _BRANCH / _TEL env vars are live) and before all onboarding gates so // models read the authoritative "AskUserQuestion satisfies plan mode's // end-of-turn" rule before any other instruction. Renders for all skills diff --git a/test/gen-skill-docs.test.ts b/test/gen-skill-docs.test.ts index 86cdac953..23a4965e7 100644 --- a/test/gen-skill-docs.test.ts +++ b/test/gen-skill-docs.test.ts @@ -1098,6 +1098,26 @@ describe('Plan status footer in preamble', () => { }); }); +// --- make-pdf setup ordering --- + +describe('make-pdf setup ordering', () => { + test('MAKE-PDF SETUP appears before generic preamble footer sections', () => { + const content = fs.readFileSync(path.join(ROOT, 'make-pdf', 'SKILL.md'), 'utf-8'); + const preambleIdx = content.indexOf('## Preamble (run first)'); + const setupIdx = content.indexOf('## MAKE-PDF SETUP'); + const planModeIdx = content.indexOf('## Plan Mode Safe Operations'); + const telemetryIdx = content.indexOf('## Telemetry (run last)'); + const workflowIdx = content.indexOf('# make-pdf: publication-quality PDFs from markdown'); + + expect(preambleIdx).toBeGreaterThanOrEqual(0); + expect(setupIdx).toBeGreaterThan(preambleIdx); + expect(setupIdx).toBeLessThan(planModeIdx); + expect(setupIdx).toBeLessThan(telemetryIdx); + expect(setupIdx).toBeLessThan(workflowIdx); + expect(content.match(/^## MAKE-PDF SETUP/gm)?.length ?? 0).toBe(1); + }); +}); + // --- Skill invocation during plan mode in preamble --- describe('Skill invocation during plan mode in preamble', () => {