paperlint 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/dependabot.yml +72 -0
- package/.github/workflows/ci.yml +297 -0
- package/.github/workflows/dependabot-automerge.yml +70 -0
- package/.github/workflows/pr-title.yml +59 -0
- package/.github/workflows/release.yml +54 -0
- package/CLAUDE.md +598 -0
- package/CONTRIBUTING.md +159 -0
- package/LICENSE +21 -0
- package/README.md +240 -0
- package/action.harness.mjs +287 -0
- package/action.mutations.mjs +162 -0
- package/action.yml +138 -0
- package/bin/rpp.mjs +43 -0
- package/dist/action-ref.d.ts +12 -0
- package/dist/action-ref.d.ts.map +1 -0
- package/dist/action-ref.js +16 -0
- package/dist/action-ref.js.map +1 -0
- package/dist/adapters/banal/failure.d.ts +73 -0
- package/dist/adapters/banal/failure.d.ts.map +1 -0
- package/dist/adapters/banal/failure.js +58 -0
- package/dist/adapters/banal/failure.js.map +1 -0
- package/dist/adapters/banal/index.d.ts +17 -0
- package/dist/adapters/banal/index.d.ts.map +1 -0
- package/dist/adapters/banal/index.js +56 -0
- package/dist/adapters/banal/index.js.map +1 -0
- package/dist/adapters/banal/install.d.ts +26 -0
- package/dist/adapters/banal/install.d.ts.map +1 -0
- package/dist/adapters/banal/install.js +15 -0
- package/dist/adapters/banal/install.js.map +1 -0
- package/dist/adapters/banal/invocation.d.ts +48 -0
- package/dist/adapters/banal/invocation.d.ts.map +1 -0
- package/dist/adapters/banal/invocation.js +43 -0
- package/dist/adapters/banal/invocation.js.map +1 -0
- package/dist/adapters/banal/locate.d.ts +50 -0
- package/dist/adapters/banal/locate.d.ts.map +1 -0
- package/dist/adapters/banal/locate.js +34 -0
- package/dist/adapters/banal/locate.js.map +1 -0
- package/dist/adapters/banal/output.d.ts +27 -0
- package/dist/adapters/banal/output.d.ts.map +1 -0
- package/dist/adapters/banal/output.js +112 -0
- package/dist/adapters/banal/output.js.map +1 -0
- package/dist/adapters/banal/pin.d.ts +19 -0
- package/dist/adapters/banal/pin.d.ts.map +1 -0
- package/dist/adapters/banal/pin.js +15 -0
- package/dist/adapters/banal/pin.js.map +1 -0
- package/dist/adapters/banal/probe.d.ts +12 -0
- package/dist/adapters/banal/probe.d.ts.map +1 -0
- package/dist/adapters/banal/probe.js +27 -0
- package/dist/adapters/banal/probe.js.map +1 -0
- package/dist/adapters/banal/run.d.ts +89 -0
- package/dist/adapters/banal/run.d.ts.map +1 -0
- package/dist/adapters/banal/run.js +104 -0
- package/dist/adapters/banal/run.js.map +1 -0
- package/dist/adapters/banal/settings.d.ts +18 -0
- package/dist/adapters/banal/settings.d.ts.map +1 -0
- package/dist/adapters/banal/settings.js +29 -0
- package/dist/adapters/banal/settings.js.map +1 -0
- package/dist/adapters/banal/xml.d.ts +48 -0
- package/dist/adapters/banal/xml.d.ts.map +1 -0
- package/dist/adapters/banal/xml.js +67 -0
- package/dist/adapters/banal/xml.js.map +1 -0
- package/dist/adapters/curl/download.io.d.ts +14 -0
- package/dist/adapters/curl/download.io.d.ts.map +1 -0
- package/dist/adapters/curl/download.io.js +69 -0
- package/dist/adapters/curl/download.io.js.map +1 -0
- package/dist/adapters/curl/index.d.ts +6 -0
- package/dist/adapters/curl/index.d.ts.map +1 -0
- package/dist/adapters/curl/index.js +6 -0
- package/dist/adapters/curl/index.js.map +1 -0
- package/dist/adapters/memory/index.d.ts +43 -0
- package/dist/adapters/memory/index.d.ts.map +1 -0
- package/dist/adapters/memory/index.js +79 -0
- package/dist/adapters/memory/index.js.map +1 -0
- package/dist/adapters/node/files.io.d.ts +3 -0
- package/dist/adapters/node/files.io.d.ts.map +1 -0
- package/dist/adapters/node/files.io.js +31 -0
- package/dist/adapters/node/files.io.js.map +1 -0
- package/dist/adapters/node/host.io.d.ts +3 -0
- package/dist/adapters/node/host.io.d.ts.map +1 -0
- package/dist/adapters/node/host.io.js +14 -0
- package/dist/adapters/node/host.io.js.map +1 -0
- package/dist/adapters/node/index.d.ts +25 -0
- package/dist/adapters/node/index.d.ts.map +1 -0
- package/dist/adapters/node/index.js +14 -0
- package/dist/adapters/node/index.js.map +1 -0
- package/dist/adapters/node/process.io.d.ts +14 -0
- package/dist/adapters/node/process.io.d.ts.map +1 -0
- package/dist/adapters/node/process.io.js +41 -0
- package/dist/adapters/node/process.io.js.map +1 -0
- package/dist/adapters/node/workspace.io.d.ts +4 -0
- package/dist/adapters/node/workspace.io.d.ts.map +1 -0
- package/dist/adapters/node/workspace.io.js +33 -0
- package/dist/adapters/node/workspace.io.js.map +1 -0
- package/dist/adapters/pdfjs/fill.d.ts +42 -0
- package/dist/adapters/pdfjs/fill.d.ts.map +1 -0
- package/dist/adapters/pdfjs/fill.js +91 -0
- package/dist/adapters/pdfjs/fill.js.map +1 -0
- package/dist/build-engine.d.ts +48 -0
- package/dist/build-engine.d.ts.map +1 -0
- package/dist/build-engine.js +148 -0
- package/dist/build-engine.js.map +1 -0
- package/dist/build.d.ts +163 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +575 -0
- package/dist/build.js.map +1 -0
- package/dist/cli.d.ts +151 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +951 -0
- package/dist/cli.js.map +1 -0
- package/dist/doctor.d.ts +42 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +280 -0
- package/dist/doctor.js.map +1 -0
- package/dist/domain/geometry.d.ts +71 -0
- package/dist/domain/geometry.d.ts.map +1 -0
- package/dist/domain/geometry.js +35 -0
- package/dist/domain/geometry.js.map +1 -0
- package/dist/domain/host.d.ts +16 -0
- package/dist/domain/host.d.ts.map +1 -0
- package/dist/domain/host.js +8 -0
- package/dist/domain/host.js.map +1 -0
- package/dist/domain/page-layout.d.ts +34 -0
- package/dist/domain/page-layout.d.ts.map +1 -0
- package/dist/domain/page-layout.js +8 -0
- package/dist/domain/page-layout.js.map +1 -0
- package/dist/domain/paths.d.ts +5 -0
- package/dist/domain/paths.d.ts.map +1 -0
- package/dist/domain/paths.js +2 -0
- package/dist/domain/paths.js.map +1 -0
- package/dist/domain/result.d.ts +23 -0
- package/dist/domain/result.d.ts.map +1 -0
- package/dist/domain/result.js +10 -0
- package/dist/domain/result.js.map +1 -0
- package/dist/domain/sha256.d.ts +7 -0
- package/dist/domain/sha256.d.ts.map +1 -0
- package/dist/domain/sha256.js +14 -0
- package/dist/domain/sha256.js.map +1 -0
- package/dist/domain/text.d.ts +6 -0
- package/dist/domain/text.d.ts.map +1 -0
- package/dist/domain/text.js +7 -0
- package/dist/domain/text.js.map +1 -0
- package/dist/engine.d.ts +93 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +119 -0
- package/dist/engine.js.map +1 -0
- package/dist/exit-code.d.ts +22 -0
- package/dist/exit-code.d.ts.map +1 -0
- package/dist/exit-code.js +10 -0
- package/dist/exit-code.js.map +1 -0
- package/dist/facts-file.d.ts +96 -0
- package/dist/facts-file.d.ts.map +1 -0
- package/dist/facts-file.js +134 -0
- package/dist/facts-file.js.map +1 -0
- package/dist/hooks-settings.d.ts +141 -0
- package/dist/hooks-settings.d.ts.map +1 -0
- package/dist/hooks-settings.js +306 -0
- package/dist/hooks-settings.js.map +1 -0
- package/dist/init.d.ts +201 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +579 -0
- package/dist/init.js.map +1 -0
- package/dist/latex-log.d.ts +80 -0
- package/dist/latex-log.d.ts.map +1 -0
- package/dist/latex-log.js +187 -0
- package/dist/latex-log.js.map +1 -0
- package/dist/latex-loop.d.ts +129 -0
- package/dist/latex-loop.d.ts.map +1 -0
- package/dist/latex-loop.js +113 -0
- package/dist/latex-loop.js.map +1 -0
- package/dist/link-skills.d.ts +51 -0
- package/dist/link-skills.d.ts.map +1 -0
- package/dist/link-skills.js +199 -0
- package/dist/link-skills.js.map +1 -0
- package/dist/new-paper.d.ts +48 -0
- package/dist/new-paper.d.ts.map +1 -0
- package/dist/new-paper.js +110 -0
- package/dist/new-paper.js.map +1 -0
- package/dist/pdf-facts.d.ts +44 -0
- package/dist/pdf-facts.d.ts.map +1 -0
- package/dist/pdf-facts.js +239 -0
- package/dist/pdf-facts.js.map +1 -0
- package/dist/pdf-geometry.d.ts +170 -0
- package/dist/pdf-geometry.d.ts.map +1 -0
- package/dist/pdf-geometry.js +158 -0
- package/dist/pdf-geometry.js.map +1 -0
- package/dist/ports/download.d.ts +9 -0
- package/dist/ports/download.d.ts.map +1 -0
- package/dist/ports/download.js +2 -0
- package/dist/ports/download.js.map +1 -0
- package/dist/ports/files.d.ts +11 -0
- package/dist/ports/files.d.ts.map +1 -0
- package/dist/ports/files.js +2 -0
- package/dist/ports/files.js.map +1 -0
- package/dist/ports/measure-geometry.d.ts +8 -0
- package/dist/ports/measure-geometry.d.ts.map +1 -0
- package/dist/ports/measure-geometry.js +2 -0
- package/dist/ports/measure-geometry.js.map +1 -0
- package/dist/ports/process.d.ts +45 -0
- package/dist/ports/process.d.ts.map +1 -0
- package/dist/ports/process.js +2 -0
- package/dist/ports/process.js.map +1 -0
- package/dist/ports/tool-installer.d.ts +29 -0
- package/dist/ports/tool-installer.d.ts.map +1 -0
- package/dist/ports/tool-installer.js +2 -0
- package/dist/ports/tool-installer.js.map +1 -0
- package/dist/ports/workspace.d.ts +18 -0
- package/dist/ports/workspace.d.ts.map +1 -0
- package/dist/ports/workspace.js +2 -0
- package/dist/ports/workspace.js.map +1 -0
- package/dist/rules-config.d.ts +34 -0
- package/dist/rules-config.d.ts.map +1 -0
- package/dist/rules-config.js +132 -0
- package/dist/rules-config.js.map +1 -0
- package/dist/structure.d.ts +34 -0
- package/dist/structure.d.ts.map +1 -0
- package/dist/structure.js +149 -0
- package/dist/structure.js.map +1 -0
- package/dist/tex-requirements.d.ts +43 -0
- package/dist/tex-requirements.d.ts.map +1 -0
- package/dist/tex-requirements.js +127 -0
- package/dist/tex-requirements.js.map +1 -0
- package/dist/toolchain.d.ts +159 -0
- package/dist/toolchain.d.ts.map +1 -0
- package/dist/toolchain.js +542 -0
- package/dist/toolchain.js.map +1 -0
- package/dist/types.d.ts +110 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/docs/configuration.md +235 -0
- package/docs/e2e.md +152 -0
- package/docs/incidents.md +59 -0
- package/docs/install.md +170 -0
- package/docs/optional-rules.md +107 -0
- package/docs/package-shape-options.md +262 -0
- package/docs/prior-art/README.md +76 -0
- package/docs/prior-art/blocking-vs-advisory.md +83 -0
- package/docs/prior-art/content-delivery.md +124 -0
- package/docs/prior-art/multi-mode-tools.md +106 -0
- package/docs/prior-art/nondeterministic-checks.md +99 -0
- package/docs/prior-art/package-location.md +422 -0
- package/docs/prior-art/paper-folder-scaffolding.md +538 -0
- package/docs/prior-art/readme-structure.md +69 -0
- package/docs/prior-art/repro/README.md +92 -0
- package/docs/prior-art/repro/claim1-allowedtools.mjs +66 -0
- package/docs/prior-art/repro/claim1-at2.mjs +40 -0
- package/docs/prior-art/repro/claim1-crosschannel.mjs +54 -0
- package/docs/prior-art/repro/claim1-frontmatter.mjs +76 -0
- package/docs/prior-art/repro/claim1-hook-payload-reporter.mjs +10 -0
- package/docs/prior-art/repro/claim1-plugin-frontmatter.mjs +27 -0
- package/docs/prior-art/repro/claim1-plugin-skill.mjs +52 -0
- package/docs/prior-art/repro/claim1-project-skill.mjs +81 -0
- package/docs/prior-art/repro/claim2-marketplace-flat-asclaimed.json +1 -0
- package/docs/prior-art/repro/claim2-marketplace-negative-control.json +1 -0
- package/docs/prior-art/repro/claim2-marketplace-nested-exact.json +9 -0
- package/docs/prior-art/repro/claim2-marketplace-nested-noversion.json +9 -0
- package/docs/prior-art/repro/claim2-marketplace-nested-range.json +1 -0
- package/docs/prior-art/repro/claim3-imports.mjs +50 -0
- package/docs/prior-art/repro/claim4-find-package-json.mjs +8 -0
- package/docs/prior-art/repro/claim4-package-dir.mjs +39 -0
- package/docs/prior-art/repro/claim4-parent-arg.mjs +17 -0
- package/docs/prior-art/repro/claim4-resolve-apis.mjs +21 -0
- package/docs/prior-art/repro/claim4-setup-consumers.mjs +45 -0
- package/docs/prior-art/repro/claim4-yarn-pnp.mjs +70 -0
- package/docs/prior-art/repro/claim5-bin-launch.mjs +39 -0
- package/docs/prior-art/repro/claim5-exports-mutation.mjs +57 -0
- package/docs/prior-art/repro/claim5-resolved-location-and-bin.mjs +33 -0
- package/docs/prior-art/repro/claim6-candidate-ambiguity.mjs +17 -0
- package/docs/prior-art/repro/claim6-doc-path-candidates.mjs +27 -0
- package/docs/prior-art/test-tooling.md +131 -0
- package/docs/rules.md +58 -0
- package/docs/texlive-install-decision.md +230 -0
- package/docs/toolchain.md +152 -0
- package/eslint-rules/doc-fields.harness.mjs +336 -0
- package/eslint-rules/doc-fields.mjs +186 -0
- package/eslint-rules/doc-fields.mutations.mjs +96 -0
- package/eslint-rules/install-path-literals.harness.mjs +121 -0
- package/eslint-rules/install-path-literals.mjs +108 -0
- package/eslint-rules/install-path-literals.mutations.mjs +62 -0
- package/eslint-rules/latex-language.harness.mjs +599 -0
- package/eslint-rules/latex-language.mjs +591 -0
- package/eslint-rules/latex-language.mutations.mjs +196 -0
- package/eslint-rules/paper-research-question.harness.mjs +146 -0
- package/eslint-rules/paper-research-question.mjs +180 -0
- package/eslint-rules/paper-research-question.mutations.mjs +127 -0
- package/eslint-rules/paper-stages.harness.mjs +356 -0
- package/eslint-rules/paper-stages.mjs +455 -0
- package/eslint-rules/paper-stages.mutations.mjs +157 -0
- package/eslint-rules/paper-typography.harness.mjs +291 -0
- package/eslint-rules/paper-typography.mjs +313 -0
- package/eslint-rules/paper-typography.mutations.mjs +131 -0
- package/eslint-rules/papers.harness.mjs +259 -0
- package/eslint-rules/papers.mjs +166 -0
- package/eslint-rules/papers.mutations.mjs +186 -0
- package/eslint-rules/pdf-last-page-balance.harness.mjs +206 -0
- package/eslint-rules/pdf-last-page-balance.mjs +208 -0
- package/eslint-rules/review-findings-cause.harness.mjs +228 -0
- package/eslint-rules/review-findings-cause.mjs +135 -0
- package/eslint-rules/review-findings-cause.mutations.mjs +72 -0
- package/eslint-rules/temp-root-realpath.harness.mjs +176 -0
- package/eslint-rules/temp-root-realpath.mjs +129 -0
- package/eslint-rules/temp-root-realpath.mutations.mjs +99 -0
- package/eslint-rules/tex-build.harness.mjs +753 -0
- package/eslint-rules/tex-build.mjs +322 -0
- package/eslint-rules/tex-build.mutations.mjs +258 -0
- package/eslint.config.mjs +521 -0
- package/fixtures/build-e2e/acmart/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/acmart/paper.tex +11 -0
- package/fixtures/build-e2e/acmart/venue.json +1 -0
- package/fixtures/build-e2e/broken/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/broken/paper.tex +7 -0
- package/fixtures/build-e2e/cite/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/cite/build.sh +5 -0
- package/fixtures/build-e2e/cite/paper.tex +10 -0
- package/fixtures/build-e2e/cite/refs.bib +9 -0
- package/fixtures/build-e2e/empty/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/empty/paper.tex +6 -0
- package/fixtures/build-e2e/fallback/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/fallback/paper.tex +11 -0
- package/fixtures/build-e2e/guards/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/guards/paper.tex +10 -0
- package/fixtures/build-e2e/no-source/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/unbalanced/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/unbalanced/paper.tex +28 -0
- package/fixtures/build-e2e/unbalanced/refs.bib +269 -0
- package/fixtures/install-path-literals/clean.fixture.mjs +3 -0
- package/fixtures/install-path-literals/clean.md +15 -0
- package/fixtures/install-path-literals/defect.fixture.mjs +3 -0
- package/fixtures/install-path-literals/defect.md +14 -0
- package/fixtures/latex-language/clean.tex +50 -0
- package/fixtures/latex-language/defect.tex +52 -0
- package/fixtures/paper-research-question/comment-only/PIPELINE-STATUS.md +9 -0
- package/fixtures/paper-research-question/comment-only/paper.tex +7 -0
- package/fixtures/paper-research-question/declared-not-in-paper/PIPELINE-STATUS.md +10 -0
- package/fixtures/paper-research-question/declared-not-in-paper/paper.tex +6 -0
- package/fixtures/paper-research-question/draft/PIPELINE-STATUS.md +6 -0
- package/fixtures/paper-research-question/draft/paper.tex +2 -0
- package/fixtures/paper-research-question/markdown-no-rq/PIPELINE-STATUS.md +9 -0
- package/fixtures/paper-research-question/markdown-no-rq/paper.md +4 -0
- package/fixtures/paper-research-question/shipped-no-rq/PIPELINE-STATUS.md +12 -0
- package/fixtures/paper-research-question/shipped-no-rq/paper.tex +3 -0
- package/fixtures/paper-research-question/shipped-with-rq/PIPELINE-STATUS.md +10 -0
- package/fixtures/paper-research-question/shipped-with-rq/paper.tex +2 -0
- package/fixtures/paper-stages/authors-ran/PIPELINE-STATUS.md +16 -0
- package/fixtures/paper-stages/marker-in-prose/PIPELINE-STATUS.md +17 -0
- package/fixtures/paper-stages/nofile/PIPELINE-STATUS.md +8 -0
- package/fixtures/paper-stages/noheader/PIPELINE-STATUS.md +1 -0
- package/fixtures/paper-stages/noheader/versions/2026-07-22-submitted.pdf +0 -0
- package/fixtures/paper-stages/nothing/PIPELINE-STATUS.md +3 -0
- package/fixtures/paper-stages/ok/PIPELINE-STATUS.md +9 -0
- package/fixtures/paper-stages/ok/versions/2026-07-22-submitted.pdf +0 -0
- package/fixtures/paper-stages/stale/PIPELINE-STATUS.md +1 -0
- package/fixtures/paper-stages/stale/versions/2026-07-22-submitted.STALE-WRONG-FILE.pdf +0 -0
- package/fixtures/paper-stages/twice/PIPELINE-STATUS.md +14 -0
- package/fixtures/paper-stages/twice/versions/2026-08-06-submitted.pdf +0 -0
- package/fixtures/paper-stages/twice/versions/2026-10-24-submitted.pdf +0 -0
- package/fixtures/paper-stages/undeclared/PIPELINE-STATUS.md +8 -0
- package/fixtures/paper-stages/undeclared/versions/2026-07-22-submitted.pdf +0 -0
- package/fixtures/paper-stages/undeclared/versions/2026-08-29-camera-ready.pdf +0 -0
- package/fixtures/paper-stages/wrongsize/PIPELINE-STATUS.md +8 -0
- package/fixtures/paper-stages/wrongsize/versions/2026-07-22-submitted.pdf +0 -0
- package/fixtures/paper-typography/clean-paper/paper.tex +29 -0
- package/fixtures/paper-typography/messy-paper/paper.tex +27 -0
- package/fixtures/pdf-facts/README.md +22 -0
- package/fixtures/pdf-facts/corrupt-font.pdf +0 -0
- package/fixtures/pdf-facts/encrypted.pdf +0 -0
- package/fixtures/pdf-facts/hidden-text.pdf +0 -0
- package/fixtures/pdf-facts/hidden-text.tex +28 -0
- package/fixtures/pdf-facts/t3-all.pdf +0 -0
- package/fixtures/pdf-facts/t3-all.tex +8 -0
- package/fixtures/pdf-facts/t3-mixed.pdf +0 -0
- package/fixtures/pdf-facts/t3-mixed.tex +9 -0
- package/fixtures/pdf-facts/ttf.pdf +2240 -1
- package/fixtures/pdf-facts/ttf.tex +6 -0
- package/fixtures/real-markdown-paper/baseline.json +24 -0
- package/fixtures/real-markdown-paper/baseline.mjs +48 -0
- package/fixtures/render-paper/build-clean.sh +25 -0
- package/fixtures/render-paper/build-defect.sh +15 -0
- package/fixtures/review-findings-cause/clean.md +17 -0
- package/fixtures/review-findings-cause/defect.md +14 -0
- package/fixtures/review-findings-cause/old-debt.md +14 -0
- package/fixtures/review-findings-cause/quiet-in-fence.md +16 -0
- package/fixtures/tex-build/clean.tex +21 -0
- package/fixtures/tex-build/defect.tex +24 -0
- package/fixtures/tex-build/frontmatter-clean.tex +25 -0
- package/fixtures/tex-build/frontmatter-defect.tex +23 -0
- package/fixtures/toolchain-mirror/catalog.txt +5 -0
- package/fixtures/toolchain-mirror/install-tl +27 -0
- package/fixtures/toolchain-mirror/release-texlive.txt +3 -0
- package/fixtures/toolchain-mirror/release-year +1 -0
- package/fixtures/toolchain-mirror/stub-kpsewhich +8 -0
- package/fixtures/toolchain-mirror/stub-pdflatex +3 -0
- package/fixtures/toolchain-mirror/stub-tlmgr +44 -0
- package/hooks/hooks.harness.mjs +713 -0
- package/hooks/hooks.mutations.mjs +337 -0
- package/hooks/paper-edit-guard.hook.d.mts +13 -0
- package/hooks/paper-edit-guard.hook.mjs +457 -0
- package/hooks/paper-skills-nudge.hook.mjs +136 -0
- package/hooks/paper-status-gates.hook.mjs +156 -0
- package/hooks/paper-status-gates.sh +91 -0
- package/lib/agent-cli-version.harness.mjs +165 -0
- package/lib/agent-cli-version.mjs +106 -0
- package/lib/agent-cli-version.mutations.mjs +109 -0
- package/lib/markdown.mjs +386 -0
- package/lib/mutation-driver.harness.mjs +227 -0
- package/lib/mutation-driver.mjs +397 -0
- package/lib/mutation-driver.mutations.mjs +68 -0
- package/lib/paper-config.d.mts +34 -0
- package/lib/paper-config.harness.mjs +286 -0
- package/lib/paper-config.mjs +142 -0
- package/lib/paper-config.mutations.mjs +143 -0
- package/lib/skill-checks.mjs +701 -0
- package/lib/skill-corpus.mjs +403 -0
- package/lib/skill-eval-fixture.mjs +63 -0
- package/lib/skill-eval-kit.mjs +257 -0
- package/lib/skill-trigger-cases.harness.mjs +170 -0
- package/lib/skill-trigger-cases.mjs +446 -0
- package/lib/skill-trigger-cases.mutations.mjs +65 -0
- package/lib/trigger-ledger.mjs +215 -0
- package/package.json +97 -0
- package/plugin/.claude-plugin/plugin.json +8 -0
- package/plugin/hooks/hooks.json +30 -0
- package/scripts/check.harness.mjs +177 -0
- package/scripts/check.mjs +239 -0
- package/scripts/check.mutations.mjs +110 -0
- package/scripts/eslint-report-guard.mjs +82 -0
- package/scripts/exclusive.mjs +138 -0
- package/scripts/harness-api.frozen.json +76 -0
- package/scripts/harness-api.test.ts +175 -0
- package/scripts/layer-legacy-frozen.d.mts +28 -0
- package/scripts/layer-legacy-frozen.mjs +152 -0
- package/scripts/layer-legacy-frozen.test.ts +115 -0
- package/scripts/layer-legacy.frozen.json +50 -0
- package/scripts/mutation-batteries-frozen.harness.mjs +204 -0
- package/scripts/mutation-batteries-frozen.mjs +238 -0
- package/scripts/mutation-batteries.frozen.json +117 -0
- package/scripts/release-config.test.ts +90 -0
- package/scripts/rules-are-content-only.harness.mjs +113 -0
- package/scripts/rules-are-content-only.mjs +138 -0
- package/scripts/rules-are-content-only.mutations.mjs +81 -0
- package/scripts/rules-see-files.harness.mjs +115 -0
- package/scripts/rules-see-files.mjs +99 -0
- package/scripts/rules-see-files.mutations.mjs +131 -0
- package/scripts/run-mutations.mjs +100 -0
- package/scripts/semantic-release-plugins.d.ts +16 -0
- package/skills/README.md +15 -0
- package/skills/analyze-sibling-paper/SKILL.md +170 -0
- package/skills/analyze-sibling-paper/SKILL.md.spec.ts +186 -0
- package/skills/analyze-sibling-paper/analyze-sibling-paper.eval.mjs +19 -0
- package/skills/analyze-sibling-paper/analyze-sibling-paper.harness.mjs +23 -0
- package/skills/argument-arc/SKILL.md +177 -0
- package/skills/argument-arc/SKILL.md.spec.ts +192 -0
- package/skills/argument-arc/argument-arc.eval.mjs +19 -0
- package/skills/argument-arc/argument-arc.harness.mjs +23 -0
- package/skills/build-benchmark/SKILL.md +213 -0
- package/skills/build-benchmark/SKILL.md.spec.ts +220 -0
- package/skills/build-benchmark/build-benchmark.eval.mjs +19 -0
- package/skills/build-benchmark/build-benchmark.harness.mjs +23 -0
- package/skills/build-benchmark/references/adversarial-cold-repro.md +68 -0
- package/skills/camera-ready/SKILL.md +148 -0
- package/skills/camera-ready/SKILL.md.spec.ts +164 -0
- package/skills/camera-ready/camera-ready.eval.mjs +19 -0
- package/skills/camera-ready/camera-ready.harness.mjs +23 -0
- package/skills/cold-read-diff/SKILL.md +160 -0
- package/skills/cold-read-diff/SKILL.md.spec.ts +166 -0
- package/skills/cold-read-diff/cold-read-diff.eval.mjs +19 -0
- package/skills/cold-read-diff/cold-read-diff.harness.mjs +23 -0
- package/skills/draft-paper/SKILL.md +152 -0
- package/skills/draft-paper/SKILL.md.spec.ts +169 -0
- package/skills/draft-paper/draft-paper.eval.mjs +19 -0
- package/skills/draft-paper/draft-paper.harness.mjs +23 -0
- package/skills/extend-paper/SKILL.md +99 -0
- package/skills/extend-paper/SKILL.md.spec.ts +116 -0
- package/skills/extend-paper/extend-paper.eval.mjs +19 -0
- package/skills/extend-paper/extend-paper.harness.mjs +23 -0
- package/skills/find-venue/SKILL.md +128 -0
- package/skills/find-venue/SKILL.md.spec.ts +145 -0
- package/skills/find-venue/find-venue.eval.mjs +19 -0
- package/skills/find-venue/find-venue.harness.mjs +23 -0
- package/skills/grade-paper-writing/SKILL.md +436 -0
- package/skills/grade-paper-writing/SKILL.md.spec.ts +453 -0
- package/skills/grade-paper-writing/fixtures/control_gopen.txt +1 -0
- package/skills/grade-paper-writing/fixtures/control_human_paper.txt +1 -0
- package/skills/grade-paper-writing/fixtures/rewrite.txt +1 -0
- package/skills/grade-paper-writing/fixtures/specimen.txt +1 -0
- package/skills/grade-paper-writing/fixtures/structure-checks.md +22 -0
- package/skills/grade-paper-writing/grade-paper-writing.eval.mjs +19 -0
- package/skills/grade-paper-writing/grade-paper-writing.harness.mjs +23 -0
- package/skills/grade-paper-writing/prose-lint.mjs +713 -0
- package/skills/harden-paper/SKILL.md +318 -0
- package/skills/harden-paper/SKILL.md.spec.ts +336 -0
- package/skills/harden-paper/check-numbers.sh +33 -0
- package/skills/harden-paper/check-release-claims.sh +35 -0
- package/skills/harden-paper/fixtures/uncited-assertions-sample.md +43 -0
- package/skills/harden-paper/fixtures/uncited-assertions-sample.tex +77 -0
- package/skills/harden-paper/harden-paper.eval.mjs +19 -0
- package/skills/harden-paper/harden-paper.harness.mjs +23 -0
- package/skills/map-prior-work/SKILL.md +211 -0
- package/skills/map-prior-work/SKILL.md.spec.ts +227 -0
- package/skills/map-prior-work/map-prior-work.eval.mjs +19 -0
- package/skills/map-prior-work/map-prior-work.harness.mjs +23 -0
- package/skills/osf-artifact-upload/SKILL.md +52 -0
- package/skills/osf-artifact-upload/SKILL.md.spec.ts +59 -0
- package/skills/osf-artifact-upload/osf-artifact-upload.eval.mjs +22 -0
- package/skills/osf-artifact-upload/osf-artifact-upload.harness.mjs +103 -0
- package/skills/paper-adversarial-review/SKILL.md +126 -0
- package/skills/paper-adversarial-review/SKILL.md.spec.ts +142 -0
- package/skills/paper-adversarial-review/paper-adversarial-review.eval.mjs +19 -0
- package/skills/paper-adversarial-review/paper-adversarial-review.harness.mjs +23 -0
- package/skills/paper-pipeline/PIPELINE-MAP.md +371 -0
- package/skills/paper-pipeline/SKILL.md +499 -0
- package/skills/paper-pipeline/SKILL.md.spec.ts +517 -0
- package/skills/paper-pipeline/description-language.eval.mjs +347 -0
- package/skills/paper-pipeline/framing-vs-vocabulary.eval.mjs +891 -0
- package/skills/paper-pipeline/grade-paper-writing-ablation.eval.mjs +1254 -0
- package/skills/paper-pipeline/paper-pipeline.eval.mjs +22 -0
- package/skills/paper-pipeline/paper-pipeline.harness.mjs +143 -0
- package/skills/paper-pipeline/pipeline-firing.baseline.json +270 -0
- package/skills/paper-pipeline/pipeline-firing.eval.mjs +664 -0
- package/skills/paper-pipeline/pipeline-language.eval.mjs +672 -0
- package/skills/paper-pipeline/references/acceptance-gate.md +329 -0
- package/skills/paper-pipeline/references/acl-venue-rules.md +142 -0
- package/skills/paper-pipeline/references/anonymization.md +68 -0
- package/skills/paper-pipeline/references/artifact-checklist.md +93 -0
- package/skills/paper-pipeline/references/body-vs-appendix.md +97 -0
- package/skills/paper-pipeline/references/credit-criteria.md +69 -0
- package/skills/paper-pipeline/references/occupancy-2026-08-06-probe/README.md +35 -0
- package/skills/paper-pipeline/references/occupancy-2026-08-06-probe/run_retext.mjs +24 -0
- package/skills/paper-pipeline/references/occupancy-2026-08-06-probe/sentences.txt +11 -0
- package/skills/paper-pipeline/references/occupancy-2026-08-06-probe/test_sentences.py +25 -0
- package/skills/paper-pipeline/references/occupancy-2026-08-06-prose-checkers.md +538 -0
- package/skills/paper-pipeline/references/occupancy-2026-08-06-reproducible-tooling.md +431 -0
- package/skills/paper-pipeline/references/occupancy-2026-08-06-staleness-and-orchestration.md +592 -0
- package/skills/paper-pipeline/references/pipeline-status-template.md +162 -0
- package/skills/paper-pipeline/references/review-ratchet.md +36 -0
- package/skills/paper-pipeline/references/sweep-2026-08-09-ideal-pipeline.md +585 -0
- package/skills/paper-pipeline/references/writing-craft.md +448 -0
- package/skills/paper-pipeline/repro/2026-08-07-description-language-control.log +63 -0
- package/skills/paper-pipeline/repro/2026-08-07-fork-check.log +52 -0
- package/skills/paper-pipeline/repro/2026-08-07-fork-check2.log +33 -0
- package/skills/paper-pipeline/repro/2026-08-07-language-eval-pilot.log +33 -0
- package/skills/paper-pipeline/repro/2026-08-07-language-eval-raw.log +166 -0
- package/skills/paper-pipeline/repro/2026-08-08-framing-vs-vocabulary-oracle.json +338 -0
- package/skills/paper-pipeline/repro/2026-08-08-framing-vs-vocabulary-oracle.log +118 -0
- package/skills/paper-pipeline/repro/2026-08-08-framing-vs-vocabulary-raw.log +245 -0
- package/skills/paper-pipeline/repro/2026-08-08-framing-vs-vocabulary.json +776 -0
- package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-A6-oracle.log +53 -0
- package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-A6-raw.log +89 -0
- package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-oracle.json +450 -0
- package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-oracle.log +136 -0
- package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-raw.log +242 -0
- package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-setupdiff.log +59 -0
- package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation.json +1032 -0
- package/skills/paper-pipeline/repro/2026-08-08-parent-replication-gpw.json +139 -0
- package/skills/paper-pipeline/repro/2026-08-08-parent-replication-gpw.log +98 -0
- package/skills/paper-pipeline/repro/2026-08-08-parent-replication.mjs +92 -0
- package/skills/paper-pipeline/repro/README.md +129 -0
- package/skills/paper-pipeline/repro/analyze-language-eval.py +116 -0
- package/skills/paper-pipeline/scripts/README.md +344 -0
- package/skills/paper-pipeline/scripts/announce.mjs +67 -0
- package/skills/paper-pipeline/scripts/artifact-coverage.harness.mjs +496 -0
- package/skills/paper-pipeline/scripts/artifact-coverage.mjs +397 -0
- package/skills/paper-pipeline/scripts/artifact-coverage.mutations.mjs +218 -0
- package/skills/paper-pipeline/scripts/check-provenance.mjs +184 -0
- package/skills/paper-pipeline/scripts/consumer.d.mts +32 -0
- package/skills/paper-pipeline/scripts/consumer.harness.mjs +562 -0
- package/skills/paper-pipeline/scripts/consumer.mjs +535 -0
- package/skills/paper-pipeline/scripts/consumer.mutations.mjs +190 -0
- package/skills/paper-pipeline/scripts/extract-ref-facts.harness.mjs +457 -0
- package/skills/paper-pipeline/scripts/extract-ref-facts.mjs +656 -0
- package/skills/paper-pipeline/scripts/extract-ref-facts.mutations.mjs +54 -0
- package/skills/paper-pipeline/scripts/fixtures/clean/PIPELINE-STATUS.md +51 -0
- package/skills/paper-pipeline/scripts/fixtures/dirty/PIPELINE-STATUS.md +52 -0
- package/skills/paper-pipeline/scripts/fixtures/dirty/paper.md +6 -0
- package/skills/paper-pipeline/scripts/fixtures/real-bib/refs.bib +153 -0
- package/skills/paper-pipeline/scripts/generated-code.harness.mjs +466 -0
- package/skills/paper-pipeline/scripts/generated-code.mjs +338 -0
- package/skills/paper-pipeline/scripts/generated-code.mutations.mjs +254 -0
- package/skills/paper-pipeline/scripts/ledger.mjs +623 -0
- package/skills/paper-pipeline/scripts/ledger.selftest.mjs +286 -0
- package/skills/paper-pipeline/scripts/pipeline-check.harness.mjs +389 -0
- package/skills/paper-pipeline/scripts/pipeline-check.mjs +737 -0
- package/skills/paper-pipeline/scripts/pipeline-check.mutations.mjs +54 -0
- package/skills/paper-pipeline/scripts/pipeline-edges.mjs +169 -0
- package/skills/paper-pipeline/scripts/population-map.harness.mjs +178 -0
- package/skills/paper-pipeline/scripts/population-map.mjs +181 -0
- package/skills/paper-pipeline/scripts/population-map.mutations.mjs +65 -0
- package/skills/paper-pipeline/scripts/population-map.selftest.mjs +122 -0
- package/skills/paper-pipeline/scripts/provenance.harness.mjs +240 -0
- package/skills/paper-pipeline/scripts/provenance.mutations.mjs +59 -0
- package/skills/paper-pipeline/scripts/round-diff.harness.mjs +881 -0
- package/skills/paper-pipeline/scripts/round-diff.mjs +576 -0
- package/skills/paper-pipeline/scripts/round-diff.mutations.mjs +276 -0
- package/skills/paper-pipeline/scripts/run-mechanical.mjs +633 -0
- package/skills/paper-pipeline/scripts/status.mjs +295 -0
- package/skills/paper-status/SKILL.md +183 -0
- package/skills/paper-status/SKILL.md.spec.ts +190 -0
- package/skills/paper-status/paper-status.eval.mjs +22 -0
- package/skills/paper-status/paper-status.harness.mjs +25 -0
- package/skills/pc-panel-review/SKILL.md +263 -0
- package/skills/pc-panel-review/SKILL.md.spec.ts +280 -0
- package/skills/pc-panel-review/pc-panel-review.eval.mjs +19 -0
- package/skills/pc-panel-review/pc-panel-review.harness.mjs +23 -0
- package/skills/plan-paper-timeline/SKILL.md +182 -0
- package/skills/plan-paper-timeline/SKILL.md.spec.ts +200 -0
- package/skills/plan-paper-timeline/fixtures/fake-google-calendar.mjs +239 -0
- package/skills/plan-paper-timeline/plan-paper-timeline.effects.harness.mjs +431 -0
- package/skills/plan-paper-timeline/plan-paper-timeline.effects.mutations.mjs +65 -0
- package/skills/plan-paper-timeline/plan-paper-timeline.eval.mjs +19 -0
- package/skills/plan-paper-timeline/plan-paper-timeline.harness.mjs +23 -0
- package/skills/render-paper/SKILL.md +159 -0
- package/skills/render-paper/SKILL.md.spec.ts +166 -0
- package/skills/render-paper/check-render.sh +419 -0
- package/skills/render-paper/checkers-requirements.txt +55 -0
- package/skills/render-paper/ensure-checkers.sh +69 -0
- package/skills/render-paper/extract-pdf-facts.harness.mjs +166 -0
- package/skills/render-paper/extract-pdf-facts.mjs +144 -0
- package/skills/render-paper/render-paper.eval.mjs +19 -0
- package/skills/render-paper/render-paper.harness.mjs +339 -0
- package/skills/research-ideate/SKILL.md +136 -0
- package/skills/research-ideate/SKILL.md.spec.ts +152 -0
- package/skills/research-ideate/research-ideate.eval.mjs +19 -0
- package/skills/research-ideate/research-ideate.harness.mjs +23 -0
- package/skills/skill-contract.mutations.mjs +179 -0
- package/skills/study-accepted-papers/SKILL.md +206 -0
- package/skills/study-accepted-papers/SKILL.md.spec.ts +223 -0
- package/skills/study-accepted-papers/study-accepted-papers.eval.mjs +19 -0
- package/skills/study-accepted-papers/study-accepted-papers.harness.mjs +23 -0
- package/skills/submit-paper/SKILL.md +182 -0
- package/skills/submit-paper/SKILL.md.spec.ts +199 -0
- package/skills/submit-paper/check-deanon.sh +149 -0
- package/skills/submit-paper/references/publishers/acm.md +92 -0
- package/skills/submit-paper/references/venues/agenticdev.jsonc +108 -0
- package/skills/submit-paper/references/venues/agenticdev.md +139 -0
- package/skills/submit-paper/references/venues/agenticdev.tex +19 -0
- package/skills/submit-paper/references/venues/aisec.jsonc +101 -0
- package/skills/submit-paper/references/venues/aisec.md +105 -0
- package/skills/submit-paper/references/venues/paper-guards.tex +41 -0
- package/skills/submit-paper/references/venues/realm.jsonc +81 -0
- package/skills/submit-paper/references/venues/realm.md +155 -0
- package/skills/submit-paper/references/venues/tex-base.jsonc +50 -0
- package/skills/submit-paper/references/venues/venue-profile.schema.json +74 -0
- package/skills/submit-paper/submit-paper.eval.mjs +19 -0
- package/skills/submit-paper/submit-paper.harness.mjs +23 -0
- package/skills/sweep-design-space/SKILL.md +269 -0
- package/skills/sweep-design-space/SKILL.md.spec.ts +285 -0
- package/skills/sweep-design-space/sweep-design-space.eval.mjs +19 -0
- package/skills/sweep-design-space/sweep-design-space.harness.mjs +23 -0
- package/skills/tighten-paper/SKILL.md +368 -0
- package/skills/tighten-paper/SKILL.md.spec.ts +384 -0
- package/skills/tighten-paper/structure.mjs +371 -0
- package/skills/tighten-paper/tighten-paper.eval.mjs +19 -0
- package/skills/tighten-paper/tighten-paper.harness.mjs +23 -0
- package/skills/verify-citations/SKILL.md +328 -0
- package/skills/verify-citations/SKILL.md.spec.ts +345 -0
- package/skills/verify-citations/scripts/bib-authors.mjs +479 -0
- package/skills/verify-citations/scripts/bib-authors.test.mjs +175 -0
- package/skills/verify-citations/scripts/verify-cites.mjs +1108 -0
- package/skills/verify-citations/scripts/verify-cites.test.mjs +735 -0
- package/skills/verify-citations/verify-citations.eval.mjs +19 -0
- package/skills/verify-citations/verify-citations.harness.mjs +23 -0
- package/src/CLAUDE.md +51 -0
- package/src/action-ref.test.ts +26 -0
- package/src/action-ref.ts +15 -0
- package/src/adapters/banal/failure.test.ts +63 -0
- package/src/adapters/banal/failure.ts +118 -0
- package/src/adapters/banal/index.test.ts +119 -0
- package/src/adapters/banal/index.ts +100 -0
- package/src/adapters/banal/install.test.ts +20 -0
- package/src/adapters/banal/install.ts +41 -0
- package/src/adapters/banal/invocation.test.ts +74 -0
- package/src/adapters/banal/invocation.ts +95 -0
- package/src/adapters/banal/locate.test.ts +52 -0
- package/src/adapters/banal/locate.ts +84 -0
- package/src/adapters/banal/output.test.ts +140 -0
- package/src/adapters/banal/output.ts +141 -0
- package/src/adapters/banal/pin.ts +30 -0
- package/src/adapters/banal/probe.ts +35 -0
- package/src/adapters/banal/run.test.ts +191 -0
- package/src/adapters/banal/run.ts +244 -0
- package/src/adapters/banal/settings.test.ts +31 -0
- package/src/adapters/banal/settings.ts +55 -0
- package/src/adapters/banal/xml.test.ts +111 -0
- package/src/adapters/banal/xml.ts +112 -0
- package/src/adapters/curl/download.io.ts +73 -0
- package/src/adapters/curl/download.test.ts +55 -0
- package/src/adapters/curl/index.ts +5 -0
- package/src/adapters/memory/index.ts +131 -0
- package/src/adapters/node/files.io.ts +39 -0
- package/src/adapters/node/files.test.ts +28 -0
- package/src/adapters/node/host.io.ts +15 -0
- package/src/adapters/node/index.ts +36 -0
- package/src/adapters/node/process.io.ts +49 -0
- package/src/adapters/node/process.test.ts +46 -0
- package/src/adapters/node/workspace.io.ts +40 -0
- package/src/adapters/node/workspace.test.ts +58 -0
- package/src/adapters/pdfjs/fill.test.ts +111 -0
- package/src/adapters/pdfjs/fill.ts +141 -0
- package/src/build-engine.harness.mjs +314 -0
- package/src/build-engine.ts +219 -0
- package/src/build.harness.mjs +631 -0
- package/src/build.mutations.mjs +195 -0
- package/src/build.ts +793 -0
- package/src/cli.harness.mjs +2007 -0
- package/src/cli.mutations.mjs +448 -0
- package/src/cli.ts +1189 -0
- package/src/doctor.harness.mjs +396 -0
- package/src/doctor.mutations.mjs +175 -0
- package/src/doctor.ts +356 -0
- package/src/domain/geometry.ts +108 -0
- package/src/domain/host.ts +23 -0
- package/src/domain/page-layout.ts +32 -0
- package/src/domain/paths.ts +5 -0
- package/src/domain/result.test.ts +26 -0
- package/src/domain/result.ts +29 -0
- package/src/domain/sha256.test.ts +12 -0
- package/src/domain/sha256.ts +21 -0
- package/src/domain/text.ts +11 -0
- package/src/engine.harness.mjs +252 -0
- package/src/engine.ts +176 -0
- package/src/exit-code.test.ts +21 -0
- package/src/exit-code.ts +38 -0
- package/src/facts-file.test.ts +240 -0
- package/src/facts-file.ts +241 -0
- package/src/hooks-settings.harness.mjs +386 -0
- package/src/hooks-settings.mutations.mjs +116 -0
- package/src/hooks-settings.ts +434 -0
- package/src/init.ts +900 -0
- package/src/latex-log.harness.mjs +226 -0
- package/src/latex-log.ts +234 -0
- package/src/latex-loop.harness.mjs +449 -0
- package/src/latex-loop.ts +211 -0
- package/src/link-skills.harness.mjs +273 -0
- package/src/link-skills.mutations.mjs +136 -0
- package/src/link-skills.ts +258 -0
- package/src/new-paper.harness.mjs +216 -0
- package/src/new-paper.mutations.mjs +79 -0
- package/src/new-paper.ts +158 -0
- package/src/pdf-facts.harness.mjs +188 -0
- package/src/pdf-facts.ts +327 -0
- package/src/pdf-geometry.harness.mjs +254 -0
- package/src/pdf-geometry.ts +300 -0
- package/src/ports/download.ts +10 -0
- package/src/ports/files.ts +11 -0
- package/src/ports/measure-geometry.ts +8 -0
- package/src/ports/process.ts +46 -0
- package/src/ports/tool-installer.ts +33 -0
- package/src/ports/workspace.ts +20 -0
- package/src/rules-config.harness.mjs +114 -0
- package/src/rules-config.ts +178 -0
- package/src/structure.harness.mjs +179 -0
- package/src/structure.mutations.mjs +83 -0
- package/src/structure.ts +166 -0
- package/src/tex-requirements.harness.mjs +238 -0
- package/src/tex-requirements.ts +181 -0
- package/src/toolchain.harness.mjs +651 -0
- package/src/toolchain.ts +755 -0
- package/src/types.ts +106 -0
- package/templates/paper/PIPELINE-STATUS.md +72 -0
- package/templates/paper/paper.md +4 -0
- package/templates/paper/paper.tex +8 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/adapters/banal/output.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The banal paperlint runs: HotCRP at one commit, one file, one sha256. The licence boundary is in
|
|
3
|
+
* `./index.ts`: paperlint downloads and runs banal, it never contains it.
|
|
4
|
+
*/
|
|
5
|
+
import { type Sha256 } from "../../domain/sha256.ts";
|
|
6
|
+
/** Where to download banal from, and the bytes to accept. The pin by default; a test passes a local file. */
|
|
7
|
+
export interface BanalSource {
|
|
8
|
+
readonly url: string;
|
|
9
|
+
readonly sha256: Sha256;
|
|
10
|
+
}
|
|
11
|
+
export interface BanalPin extends BanalSource {
|
|
12
|
+
readonly version: string;
|
|
13
|
+
readonly commit: string;
|
|
14
|
+
}
|
|
15
|
+
/** Parsed at module load: a typo in the pin fails on import, not at the first download. */
|
|
16
|
+
export declare const BANAL_PIN: BanalPin;
|
|
17
|
+
/** How a person reads the pin: `banal 1.2 (HotCRP f3e4352)`. */
|
|
18
|
+
export declare const pinLabel: (pin?: BanalPin) => string;
|
|
19
|
+
//# sourceMappingURL=pin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pin.d.ts","sourceRoot":"","sources":["../../../src/adapters/banal/pin.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAe,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAElE,6GAA6G;AAC7G,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,QAAS,SAAQ,WAAW;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,2FAA2F;AAC3F,eAAO,MAAM,SAAS,EAAE,QAOvB,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,QAAQ,GAAI,MAAK,QAAoB,KAAG,MACM,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The banal paperlint runs: HotCRP at one commit, one file, one sha256. The licence boundary is in
|
|
3
|
+
* `./index.ts`: paperlint downloads and runs banal, it never contains it.
|
|
4
|
+
*/
|
|
5
|
+
import { parseSha256 } from "../../domain/sha256.js";
|
|
6
|
+
/** Parsed at module load: a typo in the pin fails on import, not at the first download. */
|
|
7
|
+
export const BANAL_PIN = {
|
|
8
|
+
version: "1.2",
|
|
9
|
+
commit: "f3e4352133f3184c7c42b0d5e6501124bead18e6",
|
|
10
|
+
url: "https://raw.githubusercontent.com/kohler/hotcrp/f3e4352133f3184c7c42b0d5e6501124bead18e6/src/banal",
|
|
11
|
+
sha256: parseSha256("fd8cc4ae189b9da02460ae442a34f14434e5784210489fb668313ac671006911"),
|
|
12
|
+
};
|
|
13
|
+
/** How a person reads the pin: `banal 1.2 (HotCRP f3e4352)`. */
|
|
14
|
+
export const pinLabel = (pin = BANAL_PIN) => `banal ${pin.version} (HotCRP ${pin.commit.slice(0, 7)})`;
|
|
15
|
+
//# sourceMappingURL=pin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pin.js","sourceRoot":"","sources":["../../../src/adapters/banal/pin.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,WAAW,EAAe,MAAM,wBAAwB,CAAC;AAalE,2FAA2F;AAC3F,MAAM,CAAC,MAAM,SAAS,GAAa;IACjC,OAAO,EAAE,KAAK;IACd,MAAM,EAAE,0CAA0C;IAClD,GAAG,EAAE,oGAAoG;IACzG,MAAM,EAAE,WAAW,CACjB,kEAAkE,CACnE;CACF,CAAC;AAEF,gEAAgE;AAChE,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,MAAgB,SAAS,EAAU,EAAE,CAC5D,SAAS,GAAG,CAAC,OAAO,YAAY,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Does a banal RUN — accepted by a measurement, not by the download's exit code. The probe is one
|
|
3
|
+
* US-letter page of 50 lines of 10 pt text: enough for banal to measure a body font size.
|
|
4
|
+
*/
|
|
5
|
+
import { type Result } from "../../domain/result.ts";
|
|
6
|
+
import type { BanalFailure } from "./failure.ts";
|
|
7
|
+
import type { BanalMeasurement } from "./output.ts";
|
|
8
|
+
import type { PageLayout } from "../../domain/page-layout.ts";
|
|
9
|
+
export declare const PROBE_PAGE: PageLayout;
|
|
10
|
+
/** A probe measurement is accepted when banal saw the one page and measured its body size. */
|
|
11
|
+
export declare const acceptProbe: (m: BanalMeasurement) => Result<BanalMeasurement, BanalFailure>;
|
|
12
|
+
//# sourceMappingURL=probe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../../src/adapters/banal/probe.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAe9D,eAAO,MAAM,UAAU,EAAE,UAIxB,CAAC;AAEF,8FAA8F;AAC9F,eAAO,MAAM,WAAW,GACtB,GAAG,gBAAgB,KAClB,MAAM,CAAC,gBAAgB,EAAE,YAAY,CAGK,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Does a banal RUN — accepted by a measurement, not by the download's exit code. The probe is one
|
|
3
|
+
* US-letter page of 50 lines of 10 pt text: enough for banal to measure a body font size.
|
|
4
|
+
*/
|
|
5
|
+
import { err, ok } from "../../domain/result.js";
|
|
6
|
+
/** One text line of 90 characters, 10 pt, at line `i` of a one-column page. */
|
|
7
|
+
const probeLine = (i) => ({
|
|
8
|
+
top: 72 + i * 12,
|
|
9
|
+
left: 72,
|
|
10
|
+
width: 468,
|
|
11
|
+
height: 10,
|
|
12
|
+
size: 10,
|
|
13
|
+
font: "Times-Roman",
|
|
14
|
+
text: "x".repeat(90),
|
|
15
|
+
upright: true,
|
|
16
|
+
fill: { kind: "unknown" },
|
|
17
|
+
});
|
|
18
|
+
export const PROBE_PAGE = {
|
|
19
|
+
widthPt: 612,
|
|
20
|
+
heightPt: 792,
|
|
21
|
+
boxes: Array.from({ length: 50 }, (_, i) => probeLine(i)),
|
|
22
|
+
};
|
|
23
|
+
/** A probe measurement is accepted when banal saw the one page and measured its body size. */
|
|
24
|
+
export const acceptProbe = (m) => m.pages.length === 1 && typeof m.bodyfontsize === "number"
|
|
25
|
+
? ok(m)
|
|
26
|
+
: err({ kind: "probe-rejected", got: m });
|
|
27
|
+
//# sourceMappingURL=probe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"probe.js","sourceRoot":"","sources":["../../../src/adapters/banal/probe.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,wBAAwB,CAAC;AAK9D,+EAA+E;AAC/E,MAAM,SAAS,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC;IAChC,GAAG,EAAE,EAAE,GAAG,CAAC,GAAG,EAAE;IAChB,IAAI,EAAE,EAAE;IACR,KAAK,EAAE,GAAG;IACV,MAAM,EAAE,EAAE;IACV,IAAI,EAAE,EAAE;IACR,IAAI,EAAE,aAAa;IACnB,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;IACpB,OAAO,EAAE,IAAI;IACb,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAW;CACnC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,UAAU,GAAe;IACpC,OAAO,EAAE,GAAG;IACZ,QAAQ,EAAE,GAAG;IACb,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;CAC1D,CAAC;AAEF,8FAA8F;AAC9F,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,CAAmB,EACqB,EAAE,CAC1C,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,CAAC,YAAY,KAAK,QAAQ;IACxD,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BANAL — the page-geometry script HotCRP's format checker runs — fetched, verified and run.
|
|
3
|
+
*
|
|
4
|
+
* banal (Eddie Kohler, Geoffrey M. Voelker; https://github.com/kohler/hotcrp/blob/master/src/banal)
|
|
5
|
+
* measures a paper's page size, column count, body and reference font sizes and page types. paperlint
|
|
6
|
+
* runs the REAL banal, unmodified, so the numbers in the facts file are the numbers HotCRP shows a
|
|
7
|
+
* reviewer at upload — a reimplementation would drift from them.
|
|
8
|
+
*
|
|
9
|
+
* ── THE LICENCE BOUNDARY ────────────────────────────────────────────────────────
|
|
10
|
+
* banal is GPL-2.0-or-later; paperlint is MIT. paperlint therefore never contains banal: `paperlint toolchain`
|
|
11
|
+
* DOWNLOADS it from HotCRP at a pinned commit, checks its sha256, and stores it in rpp's cache, and
|
|
12
|
+
* paperlint EXECUTES it as a separate program (`perl banal …`), reading its JSON output. Nothing of banal
|
|
13
|
+
* is copied, vendored, linked or translated into this package.
|
|
14
|
+
*
|
|
15
|
+
* ── WITHOUT POPPLER ──────────────────────────────────────────────────────────────
|
|
16
|
+
* banal reads a PDF by running poppler's `pdftohtml -xml` — but it also accepts that XML directly:
|
|
17
|
+
* `banal_open_input` (banal 1.2, line 1815) takes a file ending in `.xml` and opens it as is. paperlint
|
|
18
|
+
* writes that XML itself from the page layout pdf.js read (`./xml.ts`) and hands banal the `.xml` file,
|
|
19
|
+
* beside a stub that answers banal's one question to poppler (`./invocation.ts`).
|
|
20
|
+
*
|
|
21
|
+
* ── THIS FILE ───────────────────────────────────────────────────────────────────
|
|
22
|
+
* Running and installing banal, over the generic ports (`src/ports/`) and this folder's pure
|
|
23
|
+
* modules; it imports nothing from `node:*` that touches the outside world. Failures stay banal's
|
|
24
|
+
* own union here, so the tests can branch on them; `./index.ts` turns them into the ports the app
|
|
25
|
+
* sees (`MeasureGeometry`, `ToolInstaller`).
|
|
26
|
+
*/
|
|
27
|
+
import type { AbsolutePath } from "../../domain/paths.ts";
|
|
28
|
+
import type { PageGeometry } from "../../domain/geometry.ts";
|
|
29
|
+
import type { Download } from "../../ports/download.ts";
|
|
30
|
+
import type { Files } from "../../ports/files.ts";
|
|
31
|
+
import type { RunProcess } from "../../ports/process.ts";
|
|
32
|
+
import type { Workspace } from "../../ports/workspace.ts";
|
|
33
|
+
import { type Result } from "../../domain/result.ts";
|
|
34
|
+
import type { BanalFailure } from "./failure.ts";
|
|
35
|
+
import { type BanalCandidate, type PinnedBanal } from "./locate.ts";
|
|
36
|
+
import { type BanalSource } from "./pin.ts";
|
|
37
|
+
import type { BanalSettings } from "./settings.ts";
|
|
38
|
+
import type { PageLayout } from "../../domain/page-layout.ts";
|
|
39
|
+
/** Seconds: banal is ~90 KB. */
|
|
40
|
+
export declare const BANAL_DOWNLOAD_SECONDS = 60;
|
|
41
|
+
/** The ports banal runs with. */
|
|
42
|
+
export interface BanalDeps {
|
|
43
|
+
readonly run: RunProcess;
|
|
44
|
+
readonly files: Files;
|
|
45
|
+
readonly workspace: Workspace;
|
|
46
|
+
}
|
|
47
|
+
/** The ports installing banal needs besides: it downloads. */
|
|
48
|
+
export interface InstallDeps extends BanalDeps {
|
|
49
|
+
readonly download: Download;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* What measuring came to, in banal's own terms: the banal found and its geometry, or banal's
|
|
53
|
+
* failure and the banal that was tried. `./index.ts` projects it onto the domain's `Geometry`.
|
|
54
|
+
*/
|
|
55
|
+
export type BanalOutcome = {
|
|
56
|
+
readonly source: "banal";
|
|
57
|
+
readonly by: BanalCandidate;
|
|
58
|
+
readonly geometry: PageGeometry;
|
|
59
|
+
} | {
|
|
60
|
+
readonly source: "none";
|
|
61
|
+
readonly why: BanalFailure;
|
|
62
|
+
/** The banal that was run and failed; null when none was found. */
|
|
63
|
+
readonly tried: BanalCandidate | null;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* The page geometry banal measures for `pages` — the banal found by `$BANAL`, the project's
|
|
67
|
+
* `vendor/banal`, or `paperlint toolchain`'s — or why there is none.
|
|
68
|
+
*/
|
|
69
|
+
export declare function measureGeometry(d: BanalDeps, s: BanalSettings, projectRoot: AbsolutePath, pages: readonly PageLayout[]): BanalOutcome;
|
|
70
|
+
export interface Installed {
|
|
71
|
+
readonly banal: PinnedBanal;
|
|
72
|
+
/** True when this run downloaded it. */
|
|
73
|
+
readonly fresh: boolean;
|
|
74
|
+
}
|
|
75
|
+
export interface EnsureOptions {
|
|
76
|
+
/** What to download — the pin by default; a test passes a local file. */
|
|
77
|
+
readonly source?: BanalSource;
|
|
78
|
+
/** Told before a download starts (it can take a while). */
|
|
79
|
+
readonly onDownload?: (line: string) => void;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Make `paperlint toolchain`'s banal present, byte-identical to the pin, and RUNNING: perl is checked
|
|
83
|
+
* first, a file with the wrong sha256 is replaced, and acceptance is a probe run that has to measure
|
|
84
|
+
* a page — not the download's exit code.
|
|
85
|
+
*/
|
|
86
|
+
export declare function ensureBanal(d: InstallDeps, s: BanalSettings, o?: EnsureOptions): Result<Installed, BanalFailure>;
|
|
87
|
+
/** `--check`: is the pinned banal installed and running? The same predicate as `ensureBanal`, no download. */
|
|
88
|
+
export declare function checkBanal(d: BanalDeps, s: BanalSettings, source?: BanalSource): Result<PinnedBanal, BanalFailure>;
|
|
89
|
+
//# sourceMappingURL=run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/adapters/banal/run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAoB,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAQjD,OAAO,EAIL,KAAK,cAAc,EAEnB,KAAK,WAAW,EACjB,MAAM,aAAa,CAAC;AAMrB,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,gCAAgC;AAChC,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,iCAAiC;AACjC,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;CAC/B;AAED,8DAA8D;AAC9D,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GACpB;IACE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;CACjC,GACD;IACE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;CACvC,CAAC;AAsBN;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,CAAC,EAAE,SAAS,EACZ,CAAC,EAAE,aAAa,EAChB,WAAW,EAAE,YAAY,EACzB,KAAK,EAAE,SAAS,UAAU,EAAE,GAC3B,YAAY,CAed;AAsDD,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,wCAAwC;IACxC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,CAAC,EAAE,WAAW,EACd,CAAC,EAAE,aAAa,EAChB,CAAC,GAAE,aAAkB,GACpB,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,CAajC;AAED,8GAA8G;AAC9G,wBAAgB,UAAU,CACxB,CAAC,EAAE,SAAS,EACZ,CAAC,EAAE,aAAa,EAChB,MAAM,GAAE,WAAuB,GAC9B,MAAM,CAAC,WAAW,EAAE,YAAY,CAAC,CAYnC"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { andThen, err, ok } from "../../domain/result.js";
|
|
2
|
+
import { banalCommand, BANAL_RUN_MS, stage, stageBanalInput, } from "./invocation.js";
|
|
3
|
+
import { installedState, verifyPin } from "./install.js";
|
|
4
|
+
import { installedBanal, lookupOrder, pickBanal, } from "./locate.js";
|
|
5
|
+
import { geometryOf, parseBanalOutput, } from "./output.js";
|
|
6
|
+
import { BANAL_PIN, pinLabel } from "./pin.js";
|
|
7
|
+
import { acceptProbe, PROBE_PAGE } from "./probe.js";
|
|
8
|
+
/** Seconds: banal is ~90 KB. */
|
|
9
|
+
export const BANAL_DOWNLOAD_SECONDS = 60;
|
|
10
|
+
/** Run `banal` on `pages` in a scratch directory that is gone when this returns. */
|
|
11
|
+
function runBanal(d, s, banal, pages) {
|
|
12
|
+
return d.workspace.within("rpp-banal-", (scratch) => parseBanalOutput(d.run.run(banalCommand(banal, stage(scratch, stageBanalInput(pages)), s.processEnv))));
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The page geometry banal measures for `pages` — the banal found by `$BANAL`, the project's
|
|
16
|
+
* `vendor/banal`, or `paperlint toolchain`'s — or why there is none.
|
|
17
|
+
*/
|
|
18
|
+
export function measureGeometry(d, s, projectRoot, pages) {
|
|
19
|
+
const located = pickBanal(lookupOrder(s, projectRoot), (p) => d.files.isFile(p));
|
|
20
|
+
if (!located.ok)
|
|
21
|
+
return {
|
|
22
|
+
source: "none",
|
|
23
|
+
why: { kind: "banal-missing", missing: located.error },
|
|
24
|
+
tried: null,
|
|
25
|
+
};
|
|
26
|
+
const by = located.value;
|
|
27
|
+
const r = runBanal(d, s, located.value, pages);
|
|
28
|
+
return r.ok
|
|
29
|
+
? { source: "banal", by, geometry: geometryOf(r.value) }
|
|
30
|
+
: { source: "none", why: r.error, tried: by };
|
|
31
|
+
}
|
|
32
|
+
// ── installing it (`paperlint toolchain`) ──────────────────────────────────────────────────
|
|
33
|
+
/** Does perl start? banal is a Perl program; without perl nothing below can succeed. */
|
|
34
|
+
function perlRuns(d, s) {
|
|
35
|
+
const r = d.run.run({
|
|
36
|
+
file: "perl",
|
|
37
|
+
args: ["-e", "exit 0"],
|
|
38
|
+
env: s.processEnv,
|
|
39
|
+
timeoutMs: BANAL_RUN_MS,
|
|
40
|
+
});
|
|
41
|
+
return r.kind === "exited" && r.status === 0;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Does the installed, pin-verified banal RUN — accepted by measuring the probe page, not by a
|
|
45
|
+
* download's exit code. The one place a `PinnedBanal` is minted; callers verified the bytes first.
|
|
46
|
+
*/
|
|
47
|
+
function probe(d, s, path) {
|
|
48
|
+
const at = { path, provenance: { kind: "cache" } };
|
|
49
|
+
const r = andThen(runBanal(d, s, at, [PROBE_PAGE]), acceptProbe);
|
|
50
|
+
return r.ok
|
|
51
|
+
? ok(at)
|
|
52
|
+
: err({ kind: "does-not-run", path, why: r.error });
|
|
53
|
+
}
|
|
54
|
+
/** Download `source` into `dest`, keeping the bytes only when they hash to the pin. */
|
|
55
|
+
function install(d, source, dest) {
|
|
56
|
+
const got = d.download.fetch(source.url, BANAL_DOWNLOAD_SECONDS * 1000);
|
|
57
|
+
if (!got.ok)
|
|
58
|
+
return err({
|
|
59
|
+
kind: "download-failed",
|
|
60
|
+
url: source.url,
|
|
61
|
+
detail: got.error.detail,
|
|
62
|
+
});
|
|
63
|
+
const pinned = verifyPin(got.value, source);
|
|
64
|
+
if (!pinned.ok)
|
|
65
|
+
return err({ kind: "sha-mismatch", url: source.url, ...pinned.error });
|
|
66
|
+
d.files.writeAtomic(dest, pinned.value);
|
|
67
|
+
return ok(null);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Make `paperlint toolchain`'s banal present, byte-identical to the pin, and RUNNING: perl is checked
|
|
71
|
+
* first, a file with the wrong sha256 is replaced, and acceptance is a probe run that has to measure
|
|
72
|
+
* a page — not the download's exit code.
|
|
73
|
+
*/
|
|
74
|
+
export function ensureBanal(d, s, o = {}) {
|
|
75
|
+
if (!perlRuns(d, s))
|
|
76
|
+
return err({ kind: "perl-missing" });
|
|
77
|
+
const source = o.source ?? BANAL_PIN;
|
|
78
|
+
const dest = installedBanal(s);
|
|
79
|
+
const present = installedState(d.files.readBytes(dest), source).kind === "pinned";
|
|
80
|
+
if (!present) {
|
|
81
|
+
o.onDownload?.(` downloading ${pinLabel()}…`);
|
|
82
|
+
const done = install(d, source, dest);
|
|
83
|
+
if (!done.ok)
|
|
84
|
+
return done;
|
|
85
|
+
}
|
|
86
|
+
const ran = probe(d, s, dest);
|
|
87
|
+
return ran.ok ? ok({ banal: ran.value, fresh: !present }) : ran;
|
|
88
|
+
}
|
|
89
|
+
/** `--check`: is the pinned banal installed and running? The same predicate as `ensureBanal`, no download. */
|
|
90
|
+
export function checkBanal(d, s, source = BANAL_PIN) {
|
|
91
|
+
if (!perlRuns(d, s))
|
|
92
|
+
return err({ kind: "perl-missing" });
|
|
93
|
+
const dest = installedBanal(s);
|
|
94
|
+
const state = installedState(d.files.readBytes(dest), source);
|
|
95
|
+
if (state.kind === "absent")
|
|
96
|
+
return err({
|
|
97
|
+
kind: "banal-missing",
|
|
98
|
+
missing: { kind: "not-installed", installed: dest },
|
|
99
|
+
});
|
|
100
|
+
if (state.kind === "other-bytes")
|
|
101
|
+
return err({ kind: "not-pinned", path: dest });
|
|
102
|
+
return probe(d, s, dest);
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/adapters/banal/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Environment, type HostDirs } from "../../domain/host.ts";
|
|
2
|
+
import type { AbsolutePath } from "../../domain/paths.ts";
|
|
3
|
+
/** An explicit banal to use instead of rpp's (a path to the script). */
|
|
4
|
+
export declare const BANAL_ENV = "BANAL";
|
|
5
|
+
/** Where `paperlint toolchain` stores banal. Default: `$XDG_CACHE_HOME/rpp/banal`, else `~/.cache/rpp/banal`. */
|
|
6
|
+
export declare const BANAL_DIR_ENV = "RPP_BANAL_DIR";
|
|
7
|
+
export interface BanalSettings {
|
|
8
|
+
/** `$BANAL`: the user's explicit choice; null when unset. */
|
|
9
|
+
readonly explicit: AbsolutePath | null;
|
|
10
|
+
/** `$RPP_BANAL_DIR` › `$XDG_CACHE_HOME/rpp/banal` › `<home>/.cache/rpp/banal`. */
|
|
11
|
+
readonly cacheDir: AbsolutePath;
|
|
12
|
+
/** Where scratch directories go. */
|
|
13
|
+
readonly tmpDir: AbsolutePath;
|
|
14
|
+
/** The environment a child process (perl, curl) gets: every value a string, none undefined. */
|
|
15
|
+
readonly processEnv: Readonly<Record<string, string>>;
|
|
16
|
+
}
|
|
17
|
+
export declare function parseBanalSettings(env: Environment, dirs: HostDirs): BanalSettings;
|
|
18
|
+
//# sourceMappingURL=settings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../src/adapters/banal/settings.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,QAAQ,EACd,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,wEAAwE;AACxE,eAAO,MAAM,SAAS,UAAU,CAAC;AACjC,iHAAiH;AACjH,eAAO,MAAM,aAAa,kBAAkB,CAAC;AAE7C,MAAM,WAAW,aAAa;IAC5B,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IACvC,kFAAkF;IAClF,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,oCAAoC;IACpC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,+FAA+F;IAC/F,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACvD;AAgBD,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE,QAAQ,GACb,aAAa,CAQf"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* banal's settings, parsed from the environment VALUE the composition root read once
|
|
3
|
+
* (`domain/host.ts`): which banal the user named, where `paperlint toolchain` keeps it, where scratch
|
|
4
|
+
* directories go, and the environment perl and curl get. Nothing here reads the host itself.
|
|
5
|
+
*/
|
|
6
|
+
import { join, resolve } from "node:path";
|
|
7
|
+
import { childEnv, } from "../../domain/host.js";
|
|
8
|
+
/** An explicit banal to use instead of rpp's (a path to the script). */
|
|
9
|
+
export const BANAL_ENV = "BANAL";
|
|
10
|
+
/** Where `paperlint toolchain` stores banal. Default: `$XDG_CACHE_HOME/rpp/banal`, else `~/.cache/rpp/banal`. */
|
|
11
|
+
export const BANAL_DIR_ENV = "RPP_BANAL_DIR";
|
|
12
|
+
/** `resolve` with an absolute base never consults the process's cwd. */
|
|
13
|
+
const absolute = (cwd, p) => resolve(cwd, p);
|
|
14
|
+
/** An unset variable and an empty one mean the same: not set. */
|
|
15
|
+
const set = (v) => (v ? v : null);
|
|
16
|
+
function cacheDirOf(env, d) {
|
|
17
|
+
return (set(env[BANAL_DIR_ENV]) ??
|
|
18
|
+
join(set(env["XDG_CACHE_HOME"]) ?? join(d.home, ".cache"), "rpp", "banal"));
|
|
19
|
+
}
|
|
20
|
+
export function parseBanalSettings(env, dirs) {
|
|
21
|
+
const explicit = set(env[BANAL_ENV]);
|
|
22
|
+
return {
|
|
23
|
+
explicit: explicit === null ? null : absolute(dirs.cwd, explicit),
|
|
24
|
+
cacheDir: absolute(dirs.cwd, cacheDirOf(env, dirs)),
|
|
25
|
+
tmpDir: absolute(dirs.cwd, dirs.tmp),
|
|
26
|
+
processEnv: childEnv(env),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../src/adapters/banal/settings.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EACL,QAAQ,GAGT,MAAM,sBAAsB,CAAC;AAG9B,wEAAwE;AACxE,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC;AACjC,iHAAiH;AACjH,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAC;AAa7C,wEAAwE;AACxE,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,CAAS,EAAgB,EAAE,CACxD,OAAO,CAAC,GAAG,EAAE,CAAC,CAAiB,CAAC;AAElC,iEAAiE;AACjE,MAAM,GAAG,GAAG,CAAC,CAAqB,EAAiB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAErE,SAAS,UAAU,CAAC,GAAgB,EAAE,CAAW;IAC/C,OAAO,CACL,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAC3E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,GAAgB,EAChB,IAAc;IAEd,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;IACrC,OAAO;QACL,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC;QACjE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACnD,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC;QACpC,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC;KAC1B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE BANAL INPUT XML: the pdftohtml-format XML (text boxes with position, size and font per page)
|
|
3
|
+
* that paperlint writes from the domain's page layout, which is the input banal reads — PURE. No disk, no pdf.js,
|
|
4
|
+
* no process.
|
|
5
|
+
*
|
|
6
|
+
* `pdf-facts.ts` reads the PDF with pdf.js and hands this module plain data: every text item's box,
|
|
7
|
+
* size, font, fill colour and whether it is upright. This module decides which of them a page-layout
|
|
8
|
+
* tool would count, and writes them as the banal input XML, in the dialect `pdftohtml -xml` writes
|
|
9
|
+
* and banal (HotCRP's page-geometry script, see `./index.ts`) reads. banal then measures that XML exactly as it measures the XML poppler's
|
|
10
|
+
* `pdftohtml` writes — which is how paperlint gets banal's numbers without poppler (issue #61).
|
|
11
|
+
*
|
|
12
|
+
* ── WHAT MAKES THE XML EQUAL TO pdftohtml's, as far as banal can tell ─────────────
|
|
13
|
+
* Measured on 50 PDFs / 598 pages (2026-09-25): real banal on this XML gave the same page size,
|
|
14
|
+
* columns, body and reference font size, and page counts by type as real banal on real pdftohtml.
|
|
15
|
+
* It matched only with the conditions below; each gave a wrong answer when switched off.
|
|
16
|
+
*
|
|
17
|
+
* 1. ROTATED TEXT IS NOT WRITTEN. pdftohtml writes it with width 0 and banal drops zero-width
|
|
18
|
+
* text; writing it as a horizontal box would count a rotated margin note as body text.
|
|
19
|
+
* 2. INVISIBLE TEXT (render mode 3, an OCR layer) IS NOT WRITTEN — pdftohtml does not write it.
|
|
20
|
+
* 3. LIGHT TEXT IS WRITTEN WITH ITS COLOUR, and banal drops it itself. What counts as light is
|
|
21
|
+
* banal's decision (a watermark, grey code comments), so the colour goes into `<fontspec>`
|
|
22
|
+
* exactly as pdftohtml writes it and no threshold is copied here.
|
|
23
|
+
* 4. SIZES AND COORDINATES AT ZOOM 3, the scale banal assumes for a modern pdftohtml. A font size
|
|
24
|
+
* is written as `round(size × 3)` — an integer, as pdftohtml writes it — and banal applies its
|
|
25
|
+
* own rounding to it; coordinates are written unrounded and banal rounds them to 1/8 of a
|
|
26
|
+
* decipoint. Rounding them here would round twice.
|
|
27
|
+
*
|
|
28
|
+
* banal also has to be told which pdftohtml wrote the XML, because it asks `pdftohtml -v` and
|
|
29
|
+
* derives the zoom and a font-size correction from the answer. `./index.ts` answers that question
|
|
30
|
+
* with `XML_DIALECT` below; the dialect and the writer live together so they cannot disagree.
|
|
31
|
+
*/
|
|
32
|
+
import type { PageLayout, TextBox } from "../../domain/page-layout.ts";
|
|
33
|
+
/**
|
|
34
|
+
* The pdftohtml whose XML this module writes: the zoom it writes at, and the version banal is told.
|
|
35
|
+
* banal (1.2, lines 1848-1867) picks zoom 3 and a font-size correction of 1 for any version >= 0.85;
|
|
36
|
+
* told an older version it uses 3, and every font size it reports moves.
|
|
37
|
+
*/
|
|
38
|
+
export declare const XML_DIALECT: {
|
|
39
|
+
readonly zoom: 3;
|
|
40
|
+
readonly version: "24.02.0";
|
|
41
|
+
};
|
|
42
|
+
/** Whether pdftohtml would write this box at all (conditions 1 and 2 above). */
|
|
43
|
+
export declare const written: (b: TextBox) => boolean;
|
|
44
|
+
/** XML-escape text and attribute values the way pdftohtml does (a newline becomes a space). */
|
|
45
|
+
export declare function xmlEscape(s: string): string;
|
|
46
|
+
/** The pages as `pdftohtml -xml -i -zoom 3 -noroundcoord` would write them. */
|
|
47
|
+
export declare function pdf2xml(pages: readonly PageLayout[]): string;
|
|
48
|
+
//# sourceMappingURL=xml.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xml.d.ts","sourceRoot":"","sources":["../../../src/adapters/banal/xml.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,KAAK,EAAQ,UAAU,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAE7E;;;;GAIG;AACH,eAAO,MAAM,WAAW;;;CAA2C,CAAC;AAIpE,gFAAgF;AAChF,eAAO,MAAM,OAAO,GAAI,GAAG,OAAO,KAAG,OAC6B,CAAC;AAInE,+FAA+F;AAC/F,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAO3C;AA4CD,+EAA+E;AAC/E,wBAAgB,OAAO,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,CAU5D"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pdftohtml whose XML this module writes: the zoom it writes at, and the version banal is told.
|
|
3
|
+
* banal (1.2, lines 1848-1867) picks zoom 3 and a font-size correction of 1 for any version >= 0.85;
|
|
4
|
+
* told an older version it uses 3, and every font size it reports moves.
|
|
5
|
+
*/
|
|
6
|
+
export const XML_DIALECT = { zoom: 3, version: "24.02.0" };
|
|
7
|
+
const BLACK = "#000000";
|
|
8
|
+
/** Whether pdftohtml would write this box at all (conditions 1 and 2 above). */
|
|
9
|
+
export const written = (b) => b.upright && b.fill.kind !== "invisible" && b.text.trim() !== "";
|
|
10
|
+
const colourOf = (f) => (f.kind === "rgb" ? f.hex : BLACK);
|
|
11
|
+
/** XML-escape text and attribute values the way pdftohtml does (a newline becomes a space). */
|
|
12
|
+
export function xmlEscape(s) {
|
|
13
|
+
return s
|
|
14
|
+
.replace(/&/g, "&")
|
|
15
|
+
.replace(/</g, "<")
|
|
16
|
+
.replace(/>/g, ">")
|
|
17
|
+
.replace(/"/g, """)
|
|
18
|
+
.replace(/[\r\n]/g, " ");
|
|
19
|
+
}
|
|
20
|
+
/** A number as pdftohtml's `-noroundcoord` writes it: fixed, six decimals. */
|
|
21
|
+
const fixed = (n) => n.toFixed(6);
|
|
22
|
+
/**
|
|
23
|
+
* The document-wide font table. pdftohtml numbers fonts across the whole document and declares a
|
|
24
|
+
* font on the first page that uses it, before that page's text; banal keeps the table across pages.
|
|
25
|
+
*/
|
|
26
|
+
class FontTable {
|
|
27
|
+
ids = new Map();
|
|
28
|
+
/** The id of this font, and whether this is its first use. */
|
|
29
|
+
idOf(size, font, colour) {
|
|
30
|
+
const key = `${String(size)}|${font}|${colour}`;
|
|
31
|
+
const known = this.ids.get(key);
|
|
32
|
+
if (known !== undefined)
|
|
33
|
+
return [known, false];
|
|
34
|
+
const id = this.ids.size;
|
|
35
|
+
this.ids.set(key, id);
|
|
36
|
+
return [id, true];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** One page: its `<page>` line, the fonts it introduces, then its text lines. */
|
|
40
|
+
function pageXml(p, n, fonts) {
|
|
41
|
+
const z = XML_DIALECT.zoom;
|
|
42
|
+
const specs = [];
|
|
43
|
+
const texts = [];
|
|
44
|
+
for (const b of p.boxes.filter(written)) {
|
|
45
|
+
const size = Math.round(b.size * z);
|
|
46
|
+
const colour = colourOf(b.fill);
|
|
47
|
+
const [id, fresh] = fonts.idOf(size, b.font, colour);
|
|
48
|
+
if (fresh)
|
|
49
|
+
specs.push(`\t<fontspec id="${String(id)}" size="${String(size)}" family="${xmlEscape(b.font)}" color="${colour}"/>`);
|
|
50
|
+
texts.push(`<text top="${fixed(b.top * z)}" left="${fixed(b.left * z)}" width="${fixed(b.width * z)}" height="${fixed(b.height * z)}" font="${String(id)}">${xmlEscape(b.text)}</text>`);
|
|
51
|
+
}
|
|
52
|
+
const head = `<page number="${String(n)}" position="absolute" top="0" left="0" height="${String(Math.round(p.heightPt * z))}" width="${String(Math.round(p.widthPt * z))}">`;
|
|
53
|
+
return [head, ...specs, ...texts, "</page>"];
|
|
54
|
+
}
|
|
55
|
+
/** The pages as `pdftohtml -xml -i -zoom 3 -noroundcoord` would write them. */
|
|
56
|
+
export function pdf2xml(pages) {
|
|
57
|
+
const fonts = new FontTable();
|
|
58
|
+
const lines = [
|
|
59
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
60
|
+
'<!DOCTYPE pdf2xml SYSTEM "pdf2xml.dtd">',
|
|
61
|
+
`<pdf2xml producer="research-paper-pipeline (pdf.js)" version="${XML_DIALECT.version}">`,
|
|
62
|
+
...pages.flatMap((p, i) => pageXml(p, i + 1, fonts)),
|
|
63
|
+
"</pdf2xml>",
|
|
64
|
+
];
|
|
65
|
+
return `${lines.join("\n")}\n`;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=xml.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xml.js","sourceRoot":"","sources":["../../../src/adapters/banal/xml.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Download } from "../../ports/download.ts";
|
|
2
|
+
import type { ProcessExit, RunProcess } from "../../ports/process.ts";
|
|
3
|
+
/** Why a curl run did not download, in its own words; null when it exited 0. */
|
|
4
|
+
export declare function curlFailure(r: ProcessExit): string | null;
|
|
5
|
+
/**
|
|
6
|
+
* `run` is the process port (so a test can take curl away); `env` is curl's whole environment, the
|
|
7
|
+
* proxy variables included; `tmpDir` holds the file curl writes, removed before `fetch` returns.
|
|
8
|
+
*/
|
|
9
|
+
export declare function curlDownload(o: {
|
|
10
|
+
readonly run: RunProcess;
|
|
11
|
+
readonly env: Readonly<Record<string, string>>;
|
|
12
|
+
readonly tmpDir: string;
|
|
13
|
+
}): Download;
|
|
14
|
+
//# sourceMappingURL=download.io.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"download.io.d.ts","sourceRoot":"","sources":["../../../src/adapters/curl/download.io.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGtE,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAQzD;AAUD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE;IAC9B,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,GAAG,QAAQ,CAgCX"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Download` through `curl -fsSL`. Not Node's `fetch`: undici's `fetch` ignores `HTTPS_PROXY` unless
|
|
3
|
+
* a proxy agent is installed, and rpp's CI and the containers it runs in reach the network only
|
|
4
|
+
* through a proxy. curl reads the proxy variables itself. (A claim from documentation, not measured
|
|
5
|
+
* here — the port is what makes trying the other adapter cheap.)
|
|
6
|
+
*/
|
|
7
|
+
import { mkdtempSync, readFileSync, realpathSync, rmSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { firstLine } from "../../domain/text.js";
|
|
10
|
+
import { err, ok } from "../../domain/result.js";
|
|
11
|
+
/** Why a curl run did not download, in its own words; null when it exited 0. */
|
|
12
|
+
export function curlFailure(r) {
|
|
13
|
+
if (r.kind === "exited" && r.status === 0)
|
|
14
|
+
return null;
|
|
15
|
+
if (r.kind === "not-found")
|
|
16
|
+
return "curl is not installed";
|
|
17
|
+
if (r.kind === "spawn-failed")
|
|
18
|
+
return r.message;
|
|
19
|
+
if (r.kind === "timed-out")
|
|
20
|
+
return `no answer after ${String(r.afterMs)} ms`;
|
|
21
|
+
const what = r.kind === "exited" ? `curl exited ${String(r.status)}` : r.signal;
|
|
22
|
+
return firstLine(r.stderr) || what;
|
|
23
|
+
}
|
|
24
|
+
const readOrNull = (p) => {
|
|
25
|
+
try {
|
|
26
|
+
return readFileSync(p);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* `run` is the process port (so a test can take curl away); `env` is curl's whole environment, the
|
|
34
|
+
* proxy variables included; `tmpDir` holds the file curl writes, removed before `fetch` returns.
|
|
35
|
+
*/
|
|
36
|
+
export function curlDownload(o) {
|
|
37
|
+
return {
|
|
38
|
+
fetch(url, timeoutMs) {
|
|
39
|
+
const dir = realpathSync(mkdtempSync(join(o.tmpDir, "rpp-download-")));
|
|
40
|
+
const out = join(dir, "body");
|
|
41
|
+
try {
|
|
42
|
+
const seconds = String(Math.ceil(timeoutMs / 1000));
|
|
43
|
+
const failed = curlFailure(o.run.run({
|
|
44
|
+
file: "curl",
|
|
45
|
+
args: [
|
|
46
|
+
"-fsSL",
|
|
47
|
+
"--retry",
|
|
48
|
+
"2",
|
|
49
|
+
"--max-time",
|
|
50
|
+
seconds,
|
|
51
|
+
"-o",
|
|
52
|
+
out,
|
|
53
|
+
url,
|
|
54
|
+
],
|
|
55
|
+
env: o.env,
|
|
56
|
+
timeoutMs: timeoutMs + 30_000,
|
|
57
|
+
}));
|
|
58
|
+
const bytes = failed ? null : readOrNull(out);
|
|
59
|
+
if (bytes)
|
|
60
|
+
return ok(bytes);
|
|
61
|
+
return err({ detail: failed ?? "curl wrote no file" });
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
rmSync(dir, { recursive: true, force: true });
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=download.io.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"download.io.js","sourceRoot":"","sources":["../../../src/adapters/curl/download.io.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGjD,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAC;AAEjD,gFAAgF;AAChF,MAAM,UAAU,WAAW,CAAC,CAAc;IACxC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvD,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,uBAAuB,CAAC;IAC3D,IAAI,CAAC,CAAC,IAAI,KAAK,cAAc;QAAE,OAAO,CAAC,CAAC,OAAO,CAAC;IAChD,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,mBAAmB,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IAC7E,MAAM,IAAI,GACR,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,eAAe,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACrE,OAAO,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,CAAS,EAAqB,EAAE;IAClD,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,CAI5B;IACC,OAAO;QACL,KAAK,CAAC,GAAW,EAAE,SAAiB;YAClC,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;YACvE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC9B,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC;gBACpD,MAAM,MAAM,GAAG,WAAW,CACxB,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;oBACR,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE;wBACJ,OAAO;wBACP,SAAS;wBACT,GAAG;wBACH,YAAY;wBACZ,OAAO;wBACP,IAAI;wBACJ,GAAG;wBACH,GAAG;qBACJ;oBACD,GAAG,EAAE,CAAC,CAAC,GAAG;oBACV,SAAS,EAAE,SAAS,GAAG,MAAM;iBAC9B,CAAC,CACH,CAAC;gBACF,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;gBAC9C,IAAI,KAAK;oBAAE,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;gBAC5B,OAAO,GAAG,CAAC,EAAE,MAAM,EAAE,MAAM,IAAI,oBAAoB,EAAE,CAAC,CAAC;YACzD,CAAC;oBAAS,CAAC;gBACT,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* curl, as the `Download` port. Its own adapter because curl is its own program: what changes if
|
|
3
|
+
* curl does (its flags, its exit codes, its proxy handling) changes here and nowhere else.
|
|
4
|
+
*/
|
|
5
|
+
export { curlDownload, curlFailure } from "./download.io.ts";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/curl/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* curl, as the `Download` port. Its own adapter because curl is its own program: what changes if
|
|
3
|
+
* curl does (its flags, its exit codes, its proxy handling) changes here and nowhere else.
|
|
4
|
+
*/
|
|
5
|
+
export { curlDownload, curlFailure } from "./download.io.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/curl/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
|