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,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every way getting a measurement from banal can fail, as ONE union — and `describe`, the only
|
|
3
|
+
* place a sentence about it is written. Callers branch on `kind`; nobody parses a message.
|
|
4
|
+
*/
|
|
5
|
+
import type { Lines } from "../../domain/text.ts";
|
|
6
|
+
import type { BanalMissing } from "./locate.ts";
|
|
7
|
+
export type { BanalMissing } from "./locate.ts";
|
|
8
|
+
export type BanalFailure = {
|
|
9
|
+
readonly kind: "perl-missing";
|
|
10
|
+
} | {
|
|
11
|
+
readonly kind: "banal-missing";
|
|
12
|
+
readonly missing: BanalMissing;
|
|
13
|
+
} | {
|
|
14
|
+
readonly kind: "process-failed";
|
|
15
|
+
readonly status: number;
|
|
16
|
+
readonly stderrHead: string;
|
|
17
|
+
} | {
|
|
18
|
+
readonly kind: "signalled";
|
|
19
|
+
readonly signal: string;
|
|
20
|
+
readonly stderrHead: string;
|
|
21
|
+
} | {
|
|
22
|
+
readonly kind: "spawn-failed";
|
|
23
|
+
readonly message: string;
|
|
24
|
+
} | {
|
|
25
|
+
readonly kind: "timed-out";
|
|
26
|
+
readonly afterMs: number;
|
|
27
|
+
} | {
|
|
28
|
+
readonly kind: "no-json";
|
|
29
|
+
readonly head: string;
|
|
30
|
+
}
|
|
31
|
+
/** banal's own `{"error": true}` — printed with exit 0 for an input it could not read. */
|
|
32
|
+
| {
|
|
33
|
+
readonly kind: "banal-error";
|
|
34
|
+
readonly stderrHead: string;
|
|
35
|
+
} | {
|
|
36
|
+
readonly kind: "unexpected-shape";
|
|
37
|
+
readonly issues: readonly string[];
|
|
38
|
+
} | {
|
|
39
|
+
readonly kind: "probe-rejected";
|
|
40
|
+
readonly got: unknown;
|
|
41
|
+
} | {
|
|
42
|
+
readonly kind: "download-failed";
|
|
43
|
+
readonly url: string;
|
|
44
|
+
readonly detail: string;
|
|
45
|
+
} | {
|
|
46
|
+
readonly kind: "sha-mismatch";
|
|
47
|
+
readonly url: string;
|
|
48
|
+
readonly expected: string;
|
|
49
|
+
readonly got: string;
|
|
50
|
+
}
|
|
51
|
+
/** The installed file is there, and is not the pin. */
|
|
52
|
+
| {
|
|
53
|
+
readonly kind: "not-pinned";
|
|
54
|
+
readonly path: string;
|
|
55
|
+
}
|
|
56
|
+
/** The installed, pinned banal did not measure the probe page. */
|
|
57
|
+
| {
|
|
58
|
+
readonly kind: "does-not-run";
|
|
59
|
+
readonly path: string;
|
|
60
|
+
readonly why: BanalFailure;
|
|
61
|
+
};
|
|
62
|
+
export declare const PERL_MISSING: string;
|
|
63
|
+
/**
|
|
64
|
+
* What to tell a person. Most failures are one line; a sha256 mismatch shows both hashes.
|
|
65
|
+
*
|
|
66
|
+
* The one assertion below narrows the table's entry for `f.kind` to a function of `f`: the mapped
|
|
67
|
+
* type already pairs each kind with its own variant, and TypeScript cannot correlate the index with
|
|
68
|
+
* the argument on its own.
|
|
69
|
+
*/
|
|
70
|
+
export declare function describe(f: BanalFailure): Lines;
|
|
71
|
+
/** `describe` as one line, for a caller that has a single line to fill. */
|
|
72
|
+
export declare function describeLine(f: BanalFailure): string;
|
|
73
|
+
//# sourceMappingURL=failure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"failure.d.ts","sourceRoot":"","sources":["../../../src/adapters/banal/failure.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,MAAM,YAAY,GACpB;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAA;CAAE,GACjC;IAAE,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAA;CAAE,GAClE;IACE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AACrD,0FAA0F;GACxF;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC7D;IAAE,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACzE;IAAE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;CAAE,GAC1D;IACE,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AACH,uDAAuD;GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AACxD,kEAAkE;GAChE;IACE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;CAC5B,CAAC;AAEN,eAAO,MAAM,YAAY,QAE+E,CAAC;AAmDzG;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,YAAY,GAAG,KAAK,CAG/C;AAED,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,CAEpD"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export const PERL_MISSING = "perl is not installed — banal, the page-geometry script HotCRP runs, is a Perl program. " +
|
|
2
|
+
"Install perl (Debian/Ubuntu: apt-get install perl; macOS ships it) and run `npx paperlint toolchain`";
|
|
3
|
+
function missing(m) {
|
|
4
|
+
return m.kind === "explicit-not-found"
|
|
5
|
+
? `banal not found: $BANAL names ${m.path}, which does not exist`
|
|
6
|
+
: `banal not found: ${m.installed} — \`npx paperlint toolchain\` installs it`;
|
|
7
|
+
}
|
|
8
|
+
const orNone = (s) => s || "no output";
|
|
9
|
+
const DESCRIBE = {
|
|
10
|
+
"perl-missing": () => [PERL_MISSING],
|
|
11
|
+
"banal-missing": (f) => [missing(f.missing)],
|
|
12
|
+
"process-failed": (f) => [
|
|
13
|
+
`banal failed (exit ${String(f.status)}): ${orNone(f.stderrHead)}`,
|
|
14
|
+
],
|
|
15
|
+
signalled: (f) => [`banal failed (${f.signal}): ${orNone(f.stderrHead)}`],
|
|
16
|
+
"spawn-failed": (f) => [`banal failed: ${f.message}`],
|
|
17
|
+
"timed-out": (f) => [`banal failed: no answer after ${String(f.afterMs)} ms`],
|
|
18
|
+
"no-json": (f) => [`banal printed no JSON: ${f.head || "nothing"}`],
|
|
19
|
+
"banal-error": (f) => [
|
|
20
|
+
`banal could not read the banal input XML: ${f.stderrHead}`,
|
|
21
|
+
],
|
|
22
|
+
"unexpected-shape": (f) => [
|
|
23
|
+
`banal printed JSON that is not a measurement: ${f.issues.join("; ")}`,
|
|
24
|
+
],
|
|
25
|
+
"probe-rejected": (f) => [
|
|
26
|
+
`banal ran on a one-page probe but measured nothing: ${JSON.stringify(f.got)}`,
|
|
27
|
+
],
|
|
28
|
+
"download-failed": (f) => [
|
|
29
|
+
`could not download banal from ${f.url}: ${f.detail}`,
|
|
30
|
+
],
|
|
31
|
+
"sha-mismatch": (f) => [
|
|
32
|
+
`banal from ${f.url} does not have the pinned sha256 — refusing to install it`,
|
|
33
|
+
`expected ${f.expected}`,
|
|
34
|
+
`got ${f.got}`,
|
|
35
|
+
],
|
|
36
|
+
"not-pinned": (f) => [
|
|
37
|
+
`banal in ${f.path} is not the pinned one (sha256 differs)`,
|
|
38
|
+
],
|
|
39
|
+
"does-not-run": (f) => [
|
|
40
|
+
`banal in ${f.path} does not run: ${describeLine(f.why)}`,
|
|
41
|
+
],
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* What to tell a person. Most failures are one line; a sha256 mismatch shows both hashes.
|
|
45
|
+
*
|
|
46
|
+
* The one assertion below narrows the table's entry for `f.kind` to a function of `f`: the mapped
|
|
47
|
+
* type already pairs each kind with its own variant, and TypeScript cannot correlate the index with
|
|
48
|
+
* the argument on its own.
|
|
49
|
+
*/
|
|
50
|
+
export function describe(f) {
|
|
51
|
+
const write = DESCRIBE[f.kind];
|
|
52
|
+
return write(f);
|
|
53
|
+
}
|
|
54
|
+
/** `describe` as one line, for a caller that has a single line to fill. */
|
|
55
|
+
export function describeLine(f) {
|
|
56
|
+
return describe(f).join("; ");
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=failure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"failure.js","sourceRoot":"","sources":["../../../src/adapters/banal/failure.ts"],"names":[],"mappings":"AAiDA,MAAM,CAAC,MAAM,YAAY,GACvB,0FAA0F;IAC1F,sGAAsG,CAAC;AAEzG,SAAS,OAAO,CAAC,CAAe;IAC9B,OAAO,CAAC,CAAC,IAAI,KAAK,oBAAoB;QACpC,CAAC,CAAC,iCAAiC,CAAC,CAAC,IAAI,wBAAwB;QACjE,CAAC,CAAC,oBAAoB,CAAC,CAAC,SAAS,4CAA4C,CAAC;AAClF,CAAC;AAQD,MAAM,MAAM,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,CAAC,IAAI,WAAW,CAAC;AAEvD,MAAM,QAAQ,GAAe;IAC3B,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC,YAAY,CAAC;IACpC,eAAe,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAC5C,gBAAgB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;QACvB,sBAAsB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE;KACnE;IACD,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,CAAC,MAAM,MAAM,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC;IACzE,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,CAAC,OAAO,EAAE,CAAC;IACrD,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,iCAAiC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IAC7E,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,0BAA0B,CAAC,CAAC,IAAI,IAAI,SAAS,EAAE,CAAC;IACnE,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;QACpB,6CAA6C,CAAC,CAAC,UAAU,EAAE;KAC5D;IACD,kBAAkB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;QACzB,iDAAiD,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;KACvE;IACD,gBAAgB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;QACvB,uDAAuD,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE;KAC/E;IACD,iBAAiB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;QACxB,iCAAiC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE;KACtD;IACD,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;QACrB,cAAc,CAAC,CAAC,GAAG,2DAA2D;QAC9E,YAAY,CAAC,CAAC,QAAQ,EAAE;QACxB,YAAY,CAAC,CAAC,GAAG,EAAE;KACpB;IACD,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;QACnB,YAAY,CAAC,CAAC,IAAI,yCAAyC;KAC5D;IACD,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;QACrB,YAAY,CAAC,CAAC,IAAI,kBAAkB,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE;KAC1D;CACF,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,CAAe;IACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAA+B,CAAC;IAC7D,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,YAAY,CAAC,CAAe;IAC1C,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AbsolutePath } from "../../domain/paths.ts";
|
|
2
|
+
import type { MeasureGeometry } from "../../ports/measure-geometry.ts";
|
|
3
|
+
import type { ToolInstaller } from "../../ports/tool-installer.ts";
|
|
4
|
+
import { type BanalSource } from "./pin.ts";
|
|
5
|
+
import { type BanalDeps, type InstallDeps } from "./run.ts";
|
|
6
|
+
import type { BanalSettings } from "./settings.ts";
|
|
7
|
+
export { BANAL_DIR_ENV, BANAL_ENV, parseBanalSettings, type BanalSettings, } from "./settings.ts";
|
|
8
|
+
export type { BanalDeps, InstallDeps } from "./run.ts";
|
|
9
|
+
export type { BanalSource } from "./pin.ts";
|
|
10
|
+
/** banal as the `MeasureGeometry` port: `$BANAL`, the project's `vendor/banal`, then the cache. */
|
|
11
|
+
export declare function banalMeasurer(d: BanalDeps, s: BanalSettings, projectRoot: AbsolutePath): MeasureGeometry;
|
|
12
|
+
/**
|
|
13
|
+
* banal as the `ToolInstaller` port: download at the pin, check the sha256, accept by measuring a
|
|
14
|
+
* probe page. `source` is the pin unless a test passes a local file.
|
|
15
|
+
*/
|
|
16
|
+
export declare function banalInstaller(d: InstallDeps, s: BanalSettings, source?: BanalSource): ToolInstaller;
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/banal/index.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAS,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAG1E,OAAO,EAAY,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAIL,KAAK,SAAS,EAEd,KAAK,WAAW,EACjB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,EACL,aAAa,EACb,SAAS,EACT,kBAAkB,EAClB,KAAK,aAAa,GACnB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvD,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAS5C,mGAAmG;AACnG,wBAAgB,aAAa,CAC3B,CAAC,EAAE,SAAS,EACZ,CAAC,EAAE,aAAa,EAChB,WAAW,EAAE,YAAY,GACxB,eAAe,CAajB;AAUD;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,CAAC,EAAE,WAAW,EACd,CAAC,EAAE,aAAa,EAChB,MAAM,CAAC,EAAE,WAAW,GACnB,aAAa,CAiBf"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { err, ok } from "../../domain/result.js";
|
|
2
|
+
import { describe } from "./failure.js";
|
|
3
|
+
import { provenanceLabel } from "./locate.js";
|
|
4
|
+
import { pinLabel } from "./pin.js";
|
|
5
|
+
import { checkBanal, ensureBanal, measureGeometry, } from "./run.js";
|
|
6
|
+
export { BANAL_DIR_ENV, BANAL_ENV, parseBanalSettings, } from "./settings.js";
|
|
7
|
+
/** The domain's provenance for a banal: what the facts file writes, and which rule found it. */
|
|
8
|
+
const provenance = (c) => ({
|
|
9
|
+
tool: "banal",
|
|
10
|
+
path: c.path,
|
|
11
|
+
how: provenanceLabel(c.provenance),
|
|
12
|
+
});
|
|
13
|
+
/** banal as the `MeasureGeometry` port: `$BANAL`, the project's `vendor/banal`, then the cache. */
|
|
14
|
+
export function banalMeasurer(d, s, projectRoot) {
|
|
15
|
+
return {
|
|
16
|
+
measure(pages) {
|
|
17
|
+
const g = measureGeometry(d, s, projectRoot, pages);
|
|
18
|
+
return g.source === "banal"
|
|
19
|
+
? { kind: "measured", by: provenance(g.by), geometry: g.geometry }
|
|
20
|
+
: {
|
|
21
|
+
kind: "unmeasured",
|
|
22
|
+
why: describe(g.why),
|
|
23
|
+
tried: g.tried ? provenance(g.tried) : null,
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** The one place banal's `Ready` is minted: from an `Installed`, whose `PinnedBanal` only run.ts mints. */
|
|
29
|
+
const ready = (i) => ({
|
|
30
|
+
where: i.banal.path,
|
|
31
|
+
fresh: i.fresh,
|
|
32
|
+
verified: "sha256 verified, and it measured a probe page",
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* banal as the `ToolInstaller` port: download at the pin, check the sha256, accept by measuring a
|
|
36
|
+
* probe page. `source` is the pin unless a test passes a local file.
|
|
37
|
+
*/
|
|
38
|
+
export function banalInstaller(d, s, source) {
|
|
39
|
+
return {
|
|
40
|
+
label: pinLabel(),
|
|
41
|
+
ensure(report) {
|
|
42
|
+
const r = ensureBanal(d, s, {
|
|
43
|
+
...(source ? { source } : {}),
|
|
44
|
+
onDownload: report,
|
|
45
|
+
});
|
|
46
|
+
return r.ok ? ok(ready(r.value)) : err(describe(r.error));
|
|
47
|
+
},
|
|
48
|
+
check() {
|
|
49
|
+
const r = checkBanal(d, s, source);
|
|
50
|
+
return r.ok
|
|
51
|
+
? ok(ready({ banal: r.value, fresh: false }))
|
|
52
|
+
: err(describe(r.error));
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/banal/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAC;AAGjD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,eAAe,EAAuB,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAoB,MAAM,UAAU,CAAC;AACtD,OAAO,EACL,UAAU,EACV,WAAW,EACX,eAAe,GAIhB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,aAAa,EACb,SAAS,EACT,kBAAkB,GAEnB,MAAM,eAAe,CAAC;AAIvB,gGAAgG;AAChG,MAAM,UAAU,GAAG,CAAC,CAAiB,EAAc,EAAE,CAAC,CAAC;IACrD,IAAI,EAAE,OAAO;IACb,IAAI,EAAE,CAAC,CAAC,IAAI;IACZ,GAAG,EAAE,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC;CACnC,CAAC,CAAC;AAEH,mGAAmG;AACnG,MAAM,UAAU,aAAa,CAC3B,CAAY,EACZ,CAAgB,EAChB,WAAyB;IAEzB,OAAO;QACL,OAAO,CAAC,KAAK;YACX,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;YACpD,OAAO,CAAC,CAAC,MAAM,KAAK,OAAO;gBACzB,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE;gBAClE,CAAC,CAAC;oBACE,IAAI,EAAE,YAAY;oBAClB,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC;oBACpB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI;iBAC5C,CAAC;QACR,CAAC;KACF,CAAC;AACJ,CAAC;AAED,2GAA2G;AAC3G,MAAM,KAAK,GAAG,CAAC,CAAY,EAAS,EAAE,CACpC,CAAC;IACC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,IAAc;IAC7B,KAAK,EAAE,CAAC,CAAC,KAAK;IACd,QAAQ,EAAE,+CAA+C;CAC1D,CAAU,CAAC;AAEd;;;GAGG;AACH,MAAM,UAAU,cAAc,CAC5B,CAAc,EACd,CAAgB,EAChB,MAAoB;IAEpB,OAAO;QACL,KAAK,EAAE,QAAQ,EAAE;QACjB,MAAM,CAAC,MAAM;YACX,MAAM,CAAC,GAAG,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE;gBAC1B,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC7B,UAAU,EAAE,MAAM;aACnB,CAAC,CAAC;YACH,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5D,CAAC;QACD,KAAK;YACH,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;YACnC,OAAO,CAAC,CAAC,EAAE;gBACT,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC7C,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7B,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The install decisions, on bytes: is what is on disk the pin, and may downloaded bytes be kept.
|
|
3
|
+
* One predicate for `paperlint toolchain` and `paperlint toolchain --check`, so the two cannot disagree.
|
|
4
|
+
*/
|
|
5
|
+
import type { Opaque } from "ts-essentials";
|
|
6
|
+
import { type Result } from "../../domain/result.ts";
|
|
7
|
+
import { type Sha256 } from "../../domain/sha256.ts";
|
|
8
|
+
import type { BanalSource } from "./pin.ts";
|
|
9
|
+
/** Bytes that hash to the pin. Minted by `verifyPin` only; the installer writes nothing else. */
|
|
10
|
+
export type PinnedBytes = Opaque<Uint8Array, "PinnedBytes">;
|
|
11
|
+
export interface ShaMismatch {
|
|
12
|
+
readonly expected: Sha256;
|
|
13
|
+
readonly got: Sha256;
|
|
14
|
+
}
|
|
15
|
+
export declare function verifyPin(bytes: Uint8Array, source: BanalSource): Result<PinnedBytes, ShaMismatch>;
|
|
16
|
+
/** What is installed, judged against the pin. */
|
|
17
|
+
export type InstalledState = {
|
|
18
|
+
readonly kind: "absent";
|
|
19
|
+
} | {
|
|
20
|
+
readonly kind: "other-bytes";
|
|
21
|
+
readonly mismatch: ShaMismatch;
|
|
22
|
+
} | {
|
|
23
|
+
readonly kind: "pinned";
|
|
24
|
+
};
|
|
25
|
+
export declare function installedState(current: Uint8Array | null, source: BanalSource): InstalledState;
|
|
26
|
+
//# sourceMappingURL=install.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/adapters/banal/install.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAa,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,iGAAiG;AACjG,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAE5D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,SAAS,CACvB,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,WAAW,GAClB,MAAM,CAAC,WAAW,EAAE,WAAW,CAAC,CAKlC;AAED,iDAAiD;AACjD,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC3B;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAA;CAAE,GAChE;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEhC,wBAAgB,cAAc,CAC5B,OAAO,EAAE,UAAU,GAAG,IAAI,EAC1B,MAAM,EAAE,WAAW,GAClB,cAAc,CAIhB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { err, ok } from "../../domain/result.js";
|
|
2
|
+
import { sha256Hex } from "../../domain/sha256.js";
|
|
3
|
+
export function verifyPin(bytes, source) {
|
|
4
|
+
const got = sha256Hex(bytes);
|
|
5
|
+
return got === source.sha256
|
|
6
|
+
? ok(bytes)
|
|
7
|
+
: err({ expected: source.sha256, got });
|
|
8
|
+
}
|
|
9
|
+
export function installedState(current, source) {
|
|
10
|
+
if (current === null)
|
|
11
|
+
return { kind: "absent" };
|
|
12
|
+
const v = verifyPin(current, source);
|
|
13
|
+
return v.ok ? { kind: "pinned" } : { kind: "other-bytes", mismatch: v.error };
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/adapters/banal/install.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAe,MAAM,wBAAwB,CAAC;AAWhE,MAAM,UAAU,SAAS,CACvB,KAAiB,EACjB,MAAmB;IAEnB,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAC7B,OAAO,GAAG,KAAK,MAAM,CAAC,MAAM;QAC1B,CAAC,CAAC,EAAE,CAAC,KAAoB,CAAC;QAC1B,CAAC,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;AAC5C,CAAC;AAQD,MAAM,UAAU,cAAc,CAC5B,OAA0B,EAC1B,MAAmB;IAEnB,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAChD,MAAM,CAAC,GAAG,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACrC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;AAChF,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A banal run, as DATA. What must be on disk before banal starts — the banal input XML and the
|
|
3
|
+
* `pdftohtml -v` stub, always together — and the command that runs it.
|
|
4
|
+
*
|
|
5
|
+
* Why the stub: banal asks `$pdftohtml -v` once, before it reads any input (the XML included), to
|
|
6
|
+
* pick the zoom and a font-size correction (banal 1.2, lines 1828-1868). With no pdftohtml it stops
|
|
7
|
+
* (`Error: Failed to run pdftohtml`, measured); told a version below 0.85 it applies a larger
|
|
8
|
+
* correction and every font size moves. So `$PDFTOHTML` (banal's own override, line 166) points at a
|
|
9
|
+
* stub that answers `-v` with `XML_DIALECT.version` — the pdftohtml whose XML `xml.ts` writes — and
|
|
10
|
+
* refuses anything else. `test/e2e/banal.mjs` shows both failures with the real banal.
|
|
11
|
+
*/
|
|
12
|
+
import type { Opaque } from "ts-essentials";
|
|
13
|
+
import type { AbsolutePath } from "../../domain/paths.ts";
|
|
14
|
+
import type { Command } from "../../ports/process.ts";
|
|
15
|
+
import type { Scratch } from "../../ports/workspace.ts";
|
|
16
|
+
import type { LocatedBanal } from "./locate.ts";
|
|
17
|
+
import type { PageLayout } from "../../domain/page-layout.ts";
|
|
18
|
+
/** banal takes well under a second on a paper; a hang still has to end. */
|
|
19
|
+
export declare const BANAL_RUN_MS = 120000;
|
|
20
|
+
/** A path quoted for `/bin/sh`. Minted by `shQuote` only. */
|
|
21
|
+
export type ShQuoted = Opaque<string, "ShQuoted">;
|
|
22
|
+
/** banal interpolates `$PDFTOHTML` into a shell command unquoted — so the value is quoted here. */
|
|
23
|
+
export declare const shQuote: (s: string) => ShQuoted;
|
|
24
|
+
/** The stub standing in for `pdftohtml`: it answers `-v` and refuses to convert anything. */
|
|
25
|
+
export declare const PDFTOHTML_STUB: string;
|
|
26
|
+
export interface StagedFile<N extends string, M extends "read" | "exec"> {
|
|
27
|
+
readonly name: N;
|
|
28
|
+
readonly content: string;
|
|
29
|
+
readonly mode: M;
|
|
30
|
+
}
|
|
31
|
+
/** What must exist on disk before banal runs. Both files, always: there is no way to build one alone. */
|
|
32
|
+
export interface BanalStaging {
|
|
33
|
+
readonly files: readonly [
|
|
34
|
+
StagedFile<"paper.xml", "read">,
|
|
35
|
+
StagedFile<"pdftohtml", "exec">
|
|
36
|
+
];
|
|
37
|
+
}
|
|
38
|
+
export declare const stageBanalInput: (pages: readonly PageLayout[]) => BanalStaging;
|
|
39
|
+
/** The staging written to disk. Minted by `stage` only: both files written, or nothing returned. */
|
|
40
|
+
export type StagedInput = Opaque<{
|
|
41
|
+
readonly xml: AbsolutePath;
|
|
42
|
+
readonly stub: AbsolutePath;
|
|
43
|
+
}, "StagedInput">;
|
|
44
|
+
/** Write a staging into a scratch directory, the stub executable. The only minter of `StagedInput`. */
|
|
45
|
+
export declare function stage(s: Scratch, staging: BanalStaging): StagedInput;
|
|
46
|
+
/** `perl banal -no-time -json <xml>`, with `$PDFTOHTML` quoted by construction. */
|
|
47
|
+
export declare function banalCommand(banal: LocatedBanal, staged: StagedInput, baseEnv: Readonly<Record<string, string>>): Command;
|
|
48
|
+
//# sourceMappingURL=invocation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invocation.d.ts","sourceRoot":"","sources":["../../../src/adapters/banal/invocation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAG9D,2EAA2E;AAC3E,eAAO,MAAM,YAAY,SAAU,CAAC;AAEpC,6DAA6D;AAC7D,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAElD,mGAAmG;AACnG,eAAO,MAAM,OAAO,GAAI,GAAG,MAAM,KAAG,QACS,CAAC;AAE9C,6FAA6F;AAC7F,eAAO,MAAM,cAAc,QAWf,CAAC;AAEb,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM;IACrE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;CAClB;AAED,yGAAyG;AACzG,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,SAAS;QACvB,UAAU,CAAC,WAAW,EAAE,MAAM,CAAC;QAC/B,UAAU,CAAC,WAAW,EAAE,MAAM,CAAC;KAChC,CAAC;CACH;AAED,eAAO,MAAM,eAAe,GAC1B,OAAO,SAAS,UAAU,EAAE,KAC3B,YAKD,CAAC;AAEH,oGAAoG;AACpG,MAAM,MAAM,WAAW,GAAG,MAAM,CAC9B;IAAE,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;CAAE,EAC3D,aAAa,CACd,CAAC;AAEF,uGAAuG;AACvG,wBAAgB,KAAK,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,GAAG,WAAW,CAMpE;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAC1B,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACxC,OAAO,CAQT"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { pdf2xml, XML_DIALECT } from "./xml.js";
|
|
2
|
+
/** banal takes well under a second on a paper; a hang still has to end. */
|
|
3
|
+
export const BANAL_RUN_MS = 120_000;
|
|
4
|
+
/** banal interpolates `$PDFTOHTML` into a shell command unquoted — so the value is quoted here. */
|
|
5
|
+
export const shQuote = (s) => `'${s.replace(/'/g, `'"'"'`)}'`;
|
|
6
|
+
/** The stub standing in for `pdftohtml`: it answers `-v` and refuses to convert anything. */
|
|
7
|
+
export const PDFTOHTML_STUB = [
|
|
8
|
+
"#!/bin/sh",
|
|
9
|
+
"# research-paper-pipeline: banal reads the banal input XML rpp writes, never a PDF. banal still",
|
|
10
|
+
"# asks `pdftohtml -v` which dialect to expect; this answers with the one rpp writes.",
|
|
11
|
+
'if [ "$1" = "-v" ]; then',
|
|
12
|
+
` echo "pdftohtml version ${XML_DIALECT.version}"`,
|
|
13
|
+
" exit 0",
|
|
14
|
+
"fi",
|
|
15
|
+
'echo "rpp: this pdftohtml only answers -v; banal was given a PDF instead of the banal input XML" >&2',
|
|
16
|
+
"exit 1",
|
|
17
|
+
"",
|
|
18
|
+
].join("\n");
|
|
19
|
+
export const stageBanalInput = (pages) => ({
|
|
20
|
+
files: [
|
|
21
|
+
{ name: "paper.xml", content: pdf2xml(pages), mode: "read" },
|
|
22
|
+
{ name: "pdftohtml", content: PDFTOHTML_STUB, mode: "exec" },
|
|
23
|
+
],
|
|
24
|
+
});
|
|
25
|
+
/** Write a staging into a scratch directory, the stub executable. The only minter of `StagedInput`. */
|
|
26
|
+
export function stage(s, staging) {
|
|
27
|
+
const [xml, stub] = staging.files;
|
|
28
|
+
return {
|
|
29
|
+
xml: s.write(xml.name, xml.content, xml.mode),
|
|
30
|
+
stub: s.write(stub.name, stub.content, stub.mode),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** `perl banal -no-time -json <xml>`, with `$PDFTOHTML` quoted by construction. */
|
|
34
|
+
export function banalCommand(banal, staged, baseEnv) {
|
|
35
|
+
return {
|
|
36
|
+
file: "perl",
|
|
37
|
+
args: [banal.path, "-no-time", "-json", staged.xml],
|
|
38
|
+
env: { ...baseEnv, PDFTOHTML: shQuote(staged.stub) },
|
|
39
|
+
timeoutMs: BANAL_RUN_MS,
|
|
40
|
+
maxOutputBytes: 64 * 1024 * 1024,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=invocation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invocation.js","sourceRoot":"","sources":["../../../src/adapters/banal/invocation.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEhD,2EAA2E;AAC3E,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC;AAKpC,mGAAmG;AACnG,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAS,EAAY,EAAE,CAC7C,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAe,CAAC;AAE9C,6FAA6F;AAC7F,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,WAAW;IACX,iGAAiG;IACjG,sFAAsF;IACtF,0BAA0B;IAC1B,6BAA6B,WAAW,CAAC,OAAO,GAAG;IACnD,UAAU;IACV,IAAI;IACJ,sGAAsG;IACtG,QAAQ;IACR,EAAE;CACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAgBb,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,KAA4B,EACd,EAAE,CAAC,CAAC;IAClB,KAAK,EAAE;QACL,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE;QAC5D,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE;KAC7D;CACF,CAAC,CAAC;AAQH,uGAAuG;AACvG,MAAM,UAAU,KAAK,CAAC,CAAU,EAAE,OAAqB;IACrD,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;IAClC,OAAO;QACL,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC;QAC7C,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC;KACnC,CAAC;AACnB,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,YAAY,CAC1B,KAAmB,EACnB,MAAmB,EACnB,OAAyC;IAEzC,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC;QACnD,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;QACpD,SAAS,EAAE,YAAY;QACvB,cAAc,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;KACjC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Opaque } from "ts-essentials";
|
|
2
|
+
import type { AbsolutePath } from "../../domain/paths.ts";
|
|
3
|
+
import { type Result } from "../../domain/result.ts";
|
|
4
|
+
import type { BanalSettings } from "./settings.ts";
|
|
5
|
+
export type Provenance = {
|
|
6
|
+
readonly kind: "env";
|
|
7
|
+
} | {
|
|
8
|
+
readonly kind: "vendor";
|
|
9
|
+
} | {
|
|
10
|
+
readonly kind: "cache";
|
|
11
|
+
};
|
|
12
|
+
export interface BanalCandidate {
|
|
13
|
+
readonly path: AbsolutePath;
|
|
14
|
+
readonly provenance: Provenance;
|
|
15
|
+
}
|
|
16
|
+
/** A candidate the `Files` port confirmed is a file. Minted by `pickBanal` only. */
|
|
17
|
+
export type LocatedBanal = Opaque<BanalCandidate, "LocatedBanal">;
|
|
18
|
+
/**
|
|
19
|
+
* `paperlint toolchain`'s banal after its bytes hashed to the pin AND it measured the probe page. Minted by
|
|
20
|
+
* `ensureBanal` / `checkBanal` only (`./index.ts`): a "ready" line cannot be printed without one.
|
|
21
|
+
*/
|
|
22
|
+
export type PinnedBanal = Opaque<BanalCandidate, "PinnedBanal">;
|
|
23
|
+
/** Why there is no banal to run. */
|
|
24
|
+
export type BanalMissing =
|
|
25
|
+
/** `$BANAL` names a file that is not there. An explicit choice: no fallback to another banal. */
|
|
26
|
+
{
|
|
27
|
+
readonly kind: "explicit-not-found";
|
|
28
|
+
readonly path: string;
|
|
29
|
+
}
|
|
30
|
+
/** Nothing named, nothing vendored, and `paperlint toolchain` has not installed it (here). */
|
|
31
|
+
| {
|
|
32
|
+
readonly kind: "not-installed";
|
|
33
|
+
readonly installed: string;
|
|
34
|
+
};
|
|
35
|
+
/** Where to look. An explicit `$BANAL` is the whole search; otherwise vendor, then the cache. */
|
|
36
|
+
export type LookupOrder = {
|
|
37
|
+
readonly kind: "explicit";
|
|
38
|
+
readonly path: AbsolutePath;
|
|
39
|
+
} | {
|
|
40
|
+
readonly kind: "search";
|
|
41
|
+
readonly vendor: AbsolutePath;
|
|
42
|
+
readonly cache: AbsolutePath;
|
|
43
|
+
};
|
|
44
|
+
/** Where `paperlint toolchain` puts the pinned banal: one directory per HotCRP commit. */
|
|
45
|
+
export declare const installedBanal: (s: BanalSettings) => AbsolutePath;
|
|
46
|
+
export declare function lookupOrder(s: BanalSettings, projectRoot: AbsolutePath): LookupOrder;
|
|
47
|
+
export declare function pickBanal(order: LookupOrder, isFile: (p: AbsolutePath) => boolean): Result<LocatedBanal, BanalMissing>;
|
|
48
|
+
/** Which rule found it, as a person reads it. */
|
|
49
|
+
export declare const provenanceLabel: (p: Provenance) => string;
|
|
50
|
+
//# sourceMappingURL=locate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locate.d.ts","sourceRoot":"","sources":["../../../src/adapters/banal/locate.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;CAAE,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC3B;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAE/B,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CACjC;AAED,oFAAoF;AACpF,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;AAElE;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,cAAc,EAAE,aAAa,CAAC,CAAC;AAEhE,oCAAoC;AACpC,MAAM,MAAM,YAAY;AACtB,iGAAiG;AAC/F;IAAE,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AAChE,8FAA8F;GAC5F;IAAE,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,iGAAiG;AACjG,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;CAAE,GAC1D;IACE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;CAC9B,CAAC;AAEN,0FAA0F;AAC1F,eAAO,MAAM,cAAc,GAAI,GAAG,aAAa,KAAG,YACwB,CAAC;AAE3E,wBAAgB,WAAW,CACzB,CAAC,EAAE,aAAa,EAChB,WAAW,EAAE,YAAY,GACxB,WAAW,CAOb;AAKD,wBAAgB,SAAS,CACvB,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,OAAO,GACnC,MAAM,CAAC,YAAY,EAAE,YAAY,CAAC,CAQpC;AAED,iDAAiD;AACjD,eAAO,MAAM,eAAe,GAAI,GAAG,UAAU,KAAG,MAG7C,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a banal may be, in order; which one is there; and which rule found it. The order:
|
|
3
|
+
* `$BANAL` (an explicit choice — if it names nothing, there is NO fallback), `<project>/vendor/banal`
|
|
4
|
+
* (a project that vendors its own copy), then the one `paperlint toolchain` installed.
|
|
5
|
+
*/
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { err, ok } from "../../domain/result.js";
|
|
8
|
+
import { BANAL_PIN } from "./pin.js";
|
|
9
|
+
/** Where `paperlint toolchain` puts the pinned banal: one directory per HotCRP commit. */
|
|
10
|
+
export const installedBanal = (s) => join(s.cacheDir, BANAL_PIN.commit.slice(0, 12), "banal");
|
|
11
|
+
export function lookupOrder(s, projectRoot) {
|
|
12
|
+
if (s.explicit)
|
|
13
|
+
return { kind: "explicit", path: s.explicit };
|
|
14
|
+
return {
|
|
15
|
+
kind: "search",
|
|
16
|
+
vendor: join(projectRoot, "vendor", "banal"),
|
|
17
|
+
cache: installedBanal(s),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const located = (path, kind) => ok({ path, provenance: { kind } });
|
|
21
|
+
export function pickBanal(order, isFile) {
|
|
22
|
+
if (order.kind === "explicit")
|
|
23
|
+
return isFile(order.path)
|
|
24
|
+
? located(order.path, "env")
|
|
25
|
+
: err({ kind: "explicit-not-found", path: order.path });
|
|
26
|
+
if (isFile(order.vendor))
|
|
27
|
+
return located(order.vendor, "vendor");
|
|
28
|
+
if (isFile(order.cache))
|
|
29
|
+
return located(order.cache, "cache");
|
|
30
|
+
return err({ kind: "not-installed", installed: order.cache });
|
|
31
|
+
}
|
|
32
|
+
/** Which rule found it, as a person reads it. */
|
|
33
|
+
export const provenanceLabel = (p) => ({ env: "$BANAL", vendor: "vendor/banal", cache: "paperlint toolchain" })[p.kind];
|
|
34
|
+
//# sourceMappingURL=locate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locate.js","sourceRoot":"","sources":["../../../src/adapters/banal/locate.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAsCrC,0FAA0F;AAC1F,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAgB,EAAgB,EAAE,CAC/D,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,OAAO,CAAiB,CAAC;AAE3E,MAAM,UAAU,WAAW,CACzB,CAAgB,EAChB,WAAyB;IAEzB,IAAI,CAAC,CAAC,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC9D,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAiB;QAC5D,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC;KACzB,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,GAAG,CAAC,IAAkB,EAAE,IAAwB,EAAE,EAAE,CAC/D,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,EAAkB,CAAC,CAAC;AAErD,MAAM,UAAU,SAAS,CACvB,KAAkB,EAClB,MAAoC;IAEpC,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU;QAC3B,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;YACvB,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC;YAC5B,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5D,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;QAAE,OAAO,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjE,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC9D,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,SAAS,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;AAChE,CAAC;AAED,iDAAiD;AACjD,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAa,EAAU,EAAE,CACvD,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CACvE,CAAC,CAAC,IAAI,CACP,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* banal's output, PARSED — one schema, one type, read by both consumers (the facts file and the
|
|
3
|
+
* install probe). What banal prints was measured on the pinned banal 1.2 (2026-09-25): an object
|
|
4
|
+
* with `papersize` ([height, width] in points), `columns`, `bodyfontsize` — null on an empty
|
|
5
|
+
* document — and `pages`, one entry per page, where a page's `type` is OMITTED when it is "body".
|
|
6
|
+
*/
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import type { PageGeometry } from "../../domain/geometry.ts";
|
|
9
|
+
import type { ProcessExit } from "../../ports/process.ts";
|
|
10
|
+
import { type Result } from "../../domain/result.ts";
|
|
11
|
+
import type { BanalFailure } from "./failure.ts";
|
|
12
|
+
export declare const measurementSchema: z.ZodObject<{
|
|
13
|
+
papersize: z.ZodOptional<z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>>;
|
|
14
|
+
columns: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
15
|
+
bodyfontsize: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
16
|
+
pages: z.ZodArray<z.ZodObject<{
|
|
17
|
+
type: z.ZodOptional<z.ZodString>;
|
|
18
|
+
reffontsize: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
19
|
+
}, z.core.$loose>>;
|
|
20
|
+
}, z.core.$loose>;
|
|
21
|
+
/** A measurement banal printed. banal's `{"error": true}` object cannot be one: it is refused first. */
|
|
22
|
+
export type BanalMeasurement = z.infer<typeof measurementSchema>;
|
|
23
|
+
/** A banal run as a measurement, or which failure it was. Total over `ProcessExit`. */
|
|
24
|
+
export declare const parseBanalOutput: (r: ProcessExit) => Result<BanalMeasurement, BanalFailure>;
|
|
25
|
+
/** The measurement → the domain's page geometry. */
|
|
26
|
+
export declare function geometryOf(m: BanalMeasurement): PageGeometry;
|
|
27
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../../src/adapters/banal/output.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAoB,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAUjD,eAAO,MAAM,iBAAiB;;;;;;;;iBAM5B,CAAC;AAEH,wGAAwG;AACxG,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AA8DjE,uFAAuF;AACvF,eAAO,MAAM,gBAAgB,GAC3B,GAAG,WAAW,KACb,MAAM,CAAC,gBAAgB,EAAE,YAAY,CACF,CAAC;AA2BvC,oDAAoD;AACpD,wBAAgB,UAAU,CAAC,CAAC,EAAE,gBAAgB,GAAG,YAAY,CAgB5D"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* banal's output, PARSED — one schema, one type, read by both consumers (the facts file and the
|
|
3
|
+
* install probe). What banal prints was measured on the pinned banal 1.2 (2026-09-25): an object
|
|
4
|
+
* with `papersize` ([height, width] in points), `columns`, `bodyfontsize` — null on an empty
|
|
5
|
+
* document — and `pages`, one entry per page, where a page's `type` is OMITTED when it is "body".
|
|
6
|
+
*/
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { firstLine } from "../../domain/text.js";
|
|
9
|
+
import { andThen, err, ok } from "../../domain/result.js";
|
|
10
|
+
const page = z.looseObject({
|
|
11
|
+
type: z.string().optional(),
|
|
12
|
+
reffontsize: z.number().nullable().optional(),
|
|
13
|
+
});
|
|
14
|
+
/** banal's own failure object: exit 0 and `{"error": true, …}`. It has no measurement in it. */
|
|
15
|
+
const banalError = z.looseObject({ error: z.literal(true) });
|
|
16
|
+
export const measurementSchema = z.looseObject({
|
|
17
|
+
papersize: z.tuple([z.number(), z.number()]).optional(),
|
|
18
|
+
columns: z.number().nullable().optional(),
|
|
19
|
+
bodyfontsize: z.number().nullable().optional(),
|
|
20
|
+
/** Required: banal emits it on every run, an empty document included (measured). */
|
|
21
|
+
pages: z.array(page),
|
|
22
|
+
});
|
|
23
|
+
/** The process-level outcome, before stdout is read: banal's streams, or why there are none. */
|
|
24
|
+
function streamsOf(r) {
|
|
25
|
+
switch (r.kind) {
|
|
26
|
+
case "not-found":
|
|
27
|
+
return err({ kind: "perl-missing" });
|
|
28
|
+
case "spawn-failed":
|
|
29
|
+
return err({ kind: "spawn-failed", message: r.message });
|
|
30
|
+
case "timed-out":
|
|
31
|
+
return err({ kind: "timed-out", afterMs: r.afterMs });
|
|
32
|
+
case "signalled":
|
|
33
|
+
return err({
|
|
34
|
+
kind: "signalled",
|
|
35
|
+
signal: r.signal,
|
|
36
|
+
stderrHead: firstLine(r.stderr),
|
|
37
|
+
});
|
|
38
|
+
case "exited":
|
|
39
|
+
return r.status === 0
|
|
40
|
+
? ok(r)
|
|
41
|
+
: err({
|
|
42
|
+
kind: "process-failed",
|
|
43
|
+
status: r.status,
|
|
44
|
+
stderrHead: firstLine(r.stderr),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function jsonOf(stdout) {
|
|
49
|
+
try {
|
|
50
|
+
return ok(JSON.parse(stdout));
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return err(null);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** What banal printed, as a measurement — or which failure it is. */
|
|
57
|
+
function measurementOf(o) {
|
|
58
|
+
const json = jsonOf(o.stdout);
|
|
59
|
+
if (!json.ok)
|
|
60
|
+
return err({
|
|
61
|
+
kind: "no-json",
|
|
62
|
+
head: firstLine(o.stdout) || firstLine(o.stderr),
|
|
63
|
+
});
|
|
64
|
+
if (banalError.safeParse(json.value).success)
|
|
65
|
+
return err({ kind: "banal-error", stderrHead: firstLine(o.stderr) });
|
|
66
|
+
const m = measurementSchema.safeParse(json.value);
|
|
67
|
+
return m.success
|
|
68
|
+
? ok(m.data)
|
|
69
|
+
: err({
|
|
70
|
+
kind: "unexpected-shape",
|
|
71
|
+
issues: m.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/** A banal run as a measurement, or which failure it was. Total over `ProcessExit`. */
|
|
75
|
+
export const parseBanalOutput = (r) => andThen(streamsOf(r), measurementOf);
|
|
76
|
+
const inches = (pt) => pt === undefined ? null : Number((pt / 72).toFixed(3));
|
|
77
|
+
/**
|
|
78
|
+
* 🔴 banal OMITS a page's `type` when it is "body" (its line 1022: `push … if $page->{type} ne
|
|
79
|
+
* "body"`), so counting pages whose type equals "body" gives ZERO for every paper in the world —
|
|
80
|
+
* that is how the first page-limit gate was written, and it could not fire once. A page without a
|
|
81
|
+
* type IS a body page.
|
|
82
|
+
*/
|
|
83
|
+
const typeOf = (p) => p.type ?? "body";
|
|
84
|
+
/** Pages per type, body pages included under "body". */
|
|
85
|
+
function countByType(pages) {
|
|
86
|
+
const byType = {};
|
|
87
|
+
for (const p of pages)
|
|
88
|
+
byType[typeOf(p)] = (byType[typeOf(p)] ?? 0) + 1;
|
|
89
|
+
return byType;
|
|
90
|
+
}
|
|
91
|
+
/** The reference font size: the first bibliography page that has one. */
|
|
92
|
+
const refFontSize = (pages) => pages.find((p) => p.type === "bib" && p.reffontsize != null)?.reffontsize ??
|
|
93
|
+
null;
|
|
94
|
+
/** The measurement → the domain's page geometry. */
|
|
95
|
+
export function geometryOf(m) {
|
|
96
|
+
const byType = countByType(m.pages);
|
|
97
|
+
const refPages = byType["bib"] ?? 0;
|
|
98
|
+
const appendixPages = byType["appendix"] ?? 0;
|
|
99
|
+
return {
|
|
100
|
+
// banal gives papersize as [height, width] in points — checked against live output 2026-08-26.
|
|
101
|
+
pageWidthIn: inches(m.papersize?.[1]),
|
|
102
|
+
pageHeightIn: inches(m.papersize?.[0]),
|
|
103
|
+
columns: m.columns ?? null,
|
|
104
|
+
bodyPt: m.bodyfontsize ?? null,
|
|
105
|
+
refPt: refFontSize(m.pages),
|
|
106
|
+
bodyPages: m.pages.length - refPages - appendixPages,
|
|
107
|
+
refPages,
|
|
108
|
+
appendixPages,
|
|
109
|
+
pagesByType: byType,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=output.js.map
|