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,8 @@
|
|
|
1
|
+
/** The port `facts-file.ts` measures page geometry through — shaped by the need, not by a tool. */
|
|
2
|
+
import type { Geometry } from "../domain/geometry.ts";
|
|
3
|
+
import type { PageLayout } from "../domain/page-layout.ts";
|
|
4
|
+
/** Measure a paper's page geometry from its text boxes. Never throws: "not measured" is a value. */
|
|
5
|
+
export interface MeasureGeometry {
|
|
6
|
+
measure(pages: readonly PageLayout[]): Geometry;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=measure-geometry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"measure-geometry.d.ts","sourceRoot":"","sources":["../../src/ports/measure-geometry.ts"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,oGAAoG;AACpG,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,QAAQ,CAAC;CACjD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"measure-geometry.js","sourceRoot":"","sources":["../../src/ports/measure-geometry.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Running a program — the generic port an adapter that drives another program is built over (banal's,
|
|
3
|
+
* curl's). The app does not see it where a need-shaped port (`MeasureGeometry`) would do.
|
|
4
|
+
*/
|
|
5
|
+
import type { AbsolutePath } from "../domain/paths.ts";
|
|
6
|
+
/** A program to run, as data. `env` is the child's WHOLE environment, never merged in by the adapter. */
|
|
7
|
+
export interface Command {
|
|
8
|
+
readonly file: string;
|
|
9
|
+
readonly args: readonly string[];
|
|
10
|
+
readonly env: Readonly<Record<string, string>>;
|
|
11
|
+
readonly timeoutMs: number;
|
|
12
|
+
readonly maxOutputBytes?: number;
|
|
13
|
+
readonly cwd?: AbsolutePath;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* What running a program can come to. `not-found` is the EXECUTABLE itself (ENOENT on `file`) —
|
|
17
|
+
* perl, curl — never one of its arguments, and it names the program so a message can too.
|
|
18
|
+
*/
|
|
19
|
+
export type ProcessExit = {
|
|
20
|
+
readonly kind: "exited";
|
|
21
|
+
readonly status: number;
|
|
22
|
+
readonly stdout: string;
|
|
23
|
+
readonly stderr: string;
|
|
24
|
+
} | {
|
|
25
|
+
readonly kind: "signalled";
|
|
26
|
+
readonly signal: string;
|
|
27
|
+
readonly stdout: string;
|
|
28
|
+
readonly stderr: string;
|
|
29
|
+
} | {
|
|
30
|
+
readonly kind: "timed-out";
|
|
31
|
+
readonly afterMs: number;
|
|
32
|
+
readonly stdout: string;
|
|
33
|
+
readonly stderr: string;
|
|
34
|
+
} | {
|
|
35
|
+
readonly kind: "not-found";
|
|
36
|
+
readonly file: string;
|
|
37
|
+
} | {
|
|
38
|
+
readonly kind: "spawn-failed";
|
|
39
|
+
readonly message: string;
|
|
40
|
+
};
|
|
41
|
+
/** Run a program to completion. Synchronous, like the `spawnSync` it replaces. */
|
|
42
|
+
export interface RunProcess {
|
|
43
|
+
run(c: Command): ProcessExit;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=process.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process.d.ts","sourceRoot":"","sources":["../../src/ports/process.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,yGAAyG;AACzG,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,MAAM,WAAW,GACnB;IACE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhE,kFAAkF;AAClF,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;CAC9B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process.js","sourceRoot":"","sources":["../../src/ports/process.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The port `paperlint toolchain` installs and checks an external program through. One port, many
|
|
3
|
+
* programs: banal implements it now, TeX Live in #76.
|
|
4
|
+
*/
|
|
5
|
+
import type { Opaque } from "ts-essentials";
|
|
6
|
+
import type { Result } from "../domain/result.ts";
|
|
7
|
+
import type { Lines } from "../domain/text.ts";
|
|
8
|
+
/**
|
|
9
|
+
* Present, verified, running. BRANDED: a literal `{ where, fresh, verified }` is not a `Ready`, so
|
|
10
|
+
* only an installer's adapter — one minting function each (banal's is `ready` in
|
|
11
|
+
* `adapters/banal/index.ts`) — can make one, and a ready line cannot be printed without it.
|
|
12
|
+
*/
|
|
13
|
+
export type Ready = Opaque<{
|
|
14
|
+
/** Where it is: the program's path or its bin directory. */
|
|
15
|
+
readonly where: string;
|
|
16
|
+
/** This run installed it. */
|
|
17
|
+
readonly fresh: boolean;
|
|
18
|
+
/** What was checked before calling it ready, as a person reads it. */
|
|
19
|
+
readonly verified: string;
|
|
20
|
+
}, "Ready">;
|
|
21
|
+
export interface ToolInstaller {
|
|
22
|
+
/** The program as a person reads it: `banal 1.2 (HotCRP f3e4352)`. */
|
|
23
|
+
readonly label: string;
|
|
24
|
+
/** Make it present, verified and running; `report` is told before a slow step (a download). */
|
|
25
|
+
ensure(report: (line: string) => void): Result<Ready, Lines>;
|
|
26
|
+
/** Is it present, verified and running? The same predicate as `ensure`, changing nothing. */
|
|
27
|
+
check(): Result<Ready, Lines>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=tool-installer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-installer.d.ts","sourceRoot":"","sources":["../../src/ports/tool-installer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE/C;;;;GAIG;AACH,MAAM,MAAM,KAAK,GAAG,MAAM,CACxB;IACE,4DAA4D;IAC5D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,6BAA6B;IAC7B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,EACD,OAAO,CACR,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,+FAA+F;IAC/F,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC7D,6FAA6F;IAC7F,KAAK,IAAI,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;CAC/B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-installer.js","sourceRoot":"","sources":["../../src/ports/tool-installer.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** A scratch directory with a lifetime — the generic port for temporary files. */
|
|
2
|
+
import type { AbsolutePath } from "../domain/paths.ts";
|
|
3
|
+
/** Rejects a Promise at the type level, so an `await` cannot escape a scope that ends synchronously. */
|
|
4
|
+
export type NotAPromise<T> = T extends PromiseLike<unknown> ? never : T;
|
|
5
|
+
/** A scratch directory that exists only inside `Workspace.within`. */
|
|
6
|
+
export interface Scratch {
|
|
7
|
+
readonly dir: AbsolutePath;
|
|
8
|
+
/** Write one file into `dir`; `exec` also sets its execute bit. Returns the file's path. */
|
|
9
|
+
write(name: string, content: string, mode: "read" | "exec"): AbsolutePath;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A scratch directory that cannot outlive the callback: it is created before `use` runs and removed
|
|
13
|
+
* after, whether `use` returns or throws. There is no other way to get one.
|
|
14
|
+
*/
|
|
15
|
+
export interface Workspace {
|
|
16
|
+
within<T>(prefix: string, use: (scratch: Scratch) => NotAPromise<T>): T;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=workspace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/ports/workspace.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,wGAAwG;AACxG,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS,WAAW,CAAC,OAAO,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;AAExE,sEAAsE;AACtE,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAC3B,4FAA4F;IAC5F,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,YAAY,CAAC;CAC3E;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;CACzE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/ports/workspace.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** ESLint's severities, in both of its spellings. */
|
|
2
|
+
export type Severity = "off" | "warn" | "error" | 0 | 1 | 2;
|
|
3
|
+
export type RuleEntry = Severity | readonly [Severity, ...unknown[]];
|
|
4
|
+
/** One block of the `rules` key, parsed. `basePath` is the settings file's directory. */
|
|
5
|
+
export interface RuleBlock {
|
|
6
|
+
readonly basePath: string;
|
|
7
|
+
readonly files?: readonly string[];
|
|
8
|
+
readonly ignores?: readonly string[];
|
|
9
|
+
readonly rules: Readonly<Record<string, RuleEntry>>;
|
|
10
|
+
}
|
|
11
|
+
export type Parsed<T> = {
|
|
12
|
+
readonly ok: true;
|
|
13
|
+
readonly value: T;
|
|
14
|
+
} | {
|
|
15
|
+
readonly ok: false;
|
|
16
|
+
readonly error: string;
|
|
17
|
+
};
|
|
18
|
+
/** Every top-level key must be one paperlint or its skills read. */
|
|
19
|
+
export declare function unknownKeys(settings: Record<string, unknown>): string[];
|
|
20
|
+
/**
|
|
21
|
+
* The `rules` key → config blocks, or one error naming the key path.
|
|
22
|
+
*
|
|
23
|
+
* @param raw the value under `rules` (undefined when absent)
|
|
24
|
+
* @param where how the settings are named in messages, e.g. `package.json → "paperlint"`
|
|
25
|
+
* @param shipped the rule ids paperlint ships (`shippedRuleIds`)
|
|
26
|
+
* @param baseDir the directory of the file holding the settings
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseRuleBlocks(raw: unknown, where: string, shipped: ReadonlySet<string>, baseDir: string): Parsed<readonly RuleBlock[]>;
|
|
29
|
+
/**
|
|
30
|
+
* The rule ids a config defines through its own plugins, as `<plugin>/<rule>`. Plugins passed in
|
|
31
|
+
* `foreign` (a dependency's plugin, such as `@eslint/markdown`) are not rpp's and are skipped.
|
|
32
|
+
*/
|
|
33
|
+
export declare function shippedRuleIds(config: readonly unknown[], foreign: readonly unknown[]): Set<string>;
|
|
34
|
+
//# sourceMappingURL=rules-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules-config.d.ts","sourceRoot":"","sources":["../src/rules-config.ts"],"names":[],"mappings":"AA6BA,qDAAqD;AACrD,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC5D,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;AAErE,yFAAyF;AACzF,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;CACrD;AAED,MAAM,MAAM,MAAM,CAAC,CAAC,IAChB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GACxC;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAOnD,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,CAEvE;AA8ED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAC5B,OAAO,EAAE,MAAM,GACd,MAAM,CAAC,SAAS,SAAS,EAAE,CAAC,CAa9B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,SAAS,OAAO,EAAE,EAC1B,OAAO,EAAE,SAAS,OAAO,EAAE,GAC1B,GAAG,CAAC,MAAM,CAAC,CAWb"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE CONSUMER'S SETTINGS, PARSED AT THE BOUNDARY — unknown keys refused, and the `rules` key
|
|
3
|
+
* turned into ESLint config blocks.
|
|
4
|
+
*
|
|
5
|
+
* ── THE `rules` KEY: ESLint'S OWN SHAPE, NOT A NEW ONE ──────────────────────────
|
|
6
|
+
* A consumer turns an optional rule on, or changes a built-in rule's severity, by writing what they
|
|
7
|
+
* would write in an ESLint flat config — a list of `{ files, ignores, rules }` blocks:
|
|
8
|
+
*
|
|
9
|
+
* "rules": [ { "files": ["papers/agenticdev-2026/**"],
|
|
10
|
+
* "rules": { "pdf/last-page-balance": ["error", { "tolerancePt": 120 }] } } ]
|
|
11
|
+
*
|
|
12
|
+
* The blocks are appended AFTER rpp's built-in config, so a later block wins, exactly as in ESLint.
|
|
13
|
+
* `files` and `ignores` are resolved relative to the directory of the file that holds the settings,
|
|
14
|
+
* as ESLint resolves them relative to its config file: each block gets that directory as ESLint's
|
|
15
|
+
* own `basePath`, so paperlint matches nothing itself.
|
|
16
|
+
*
|
|
17
|
+
* ── WHY PARSED HERE, AND WHY STRICT ─────────────────────────────────────────────
|
|
18
|
+
* ESLint would reject a bad severity or an unknown rule too — but as a stack trace from inside
|
|
19
|
+
* `lintFiles`, naming neither the settings file nor the block. And a key paperlint does not read, at the
|
|
20
|
+
* top level or in a block, ESLint never sees at all: a typo would silently read as "not set". So
|
|
21
|
+
* every problem is one line naming the key path, before ESLint starts, and nothing downstream sees
|
|
22
|
+
* the raw object again.
|
|
23
|
+
*
|
|
24
|
+
* Only rules paperlint ships may be named: the settings configure paperlint, and a rule from another plugin
|
|
25
|
+
* would need that plugin, which JSON cannot carry. Which rules paperlint ships is read off its own
|
|
26
|
+
* config (`buildConfig`), not listed a second time.
|
|
27
|
+
*/
|
|
28
|
+
import { SETTINGS_KEYS } from "../lib/paper-config.mjs";
|
|
29
|
+
const SEVERITIES = ["off", "warn", "error", 0, 1, 2];
|
|
30
|
+
const BLOCK_KEYS = new Set(["files", "ignores", "rules"]);
|
|
31
|
+
const bad = (error) => ({ ok: false, error });
|
|
32
|
+
/** Every top-level key must be one paperlint or its skills read. */
|
|
33
|
+
export function unknownKeys(settings) {
|
|
34
|
+
return Object.keys(settings).filter((k) => !Object.hasOwn(SETTINGS_KEYS, k));
|
|
35
|
+
}
|
|
36
|
+
const isStringList = (v) => Array.isArray(v) &&
|
|
37
|
+
v.length > 0 &&
|
|
38
|
+
v.every((x) => typeof x === "string" && x !== "");
|
|
39
|
+
/** A severity, or `[severity, ...options]`. */
|
|
40
|
+
function parseEntry(v) {
|
|
41
|
+
const sev = Array.isArray(v) ? v[0] : v;
|
|
42
|
+
if (!SEVERITIES.includes(sev))
|
|
43
|
+
return null;
|
|
44
|
+
return v;
|
|
45
|
+
}
|
|
46
|
+
/** One block's `rules` object. */
|
|
47
|
+
function parseRules(v, at, shipped) {
|
|
48
|
+
if (typeof v !== "object" || v === null || Array.isArray(v))
|
|
49
|
+
return bad(`${at}.rules must be an object of rule id → severity`);
|
|
50
|
+
const out = {};
|
|
51
|
+
for (const [id, raw] of Object.entries(v)) {
|
|
52
|
+
if (!shipped.has(id))
|
|
53
|
+
return bad(`${at}.rules: "${id}" is not a rule paperlint ships — known: ${[...shipped].sort().join(", ")}`);
|
|
54
|
+
const entry = parseEntry(raw);
|
|
55
|
+
if (entry === null)
|
|
56
|
+
return bad(`${at}.rules["${id}"]: ${JSON.stringify(raw)} is not a severity — use "off", "warn" or "error", or ["error", { options }]`);
|
|
57
|
+
out[id] = entry;
|
|
58
|
+
}
|
|
59
|
+
return { ok: true, value: out };
|
|
60
|
+
}
|
|
61
|
+
/** `files` and `ignores`, each absent or a non-empty list of globs; the first bad one, or null. */
|
|
62
|
+
function badGlobs(o, at) {
|
|
63
|
+
for (const k of ["files", "ignores"])
|
|
64
|
+
if (o[k] !== undefined && !isStringList(o[k]))
|
|
65
|
+
return `${at}.${k} must be a non-empty list of glob strings`;
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
/** The block's `files`/`ignores`, present only when given. */
|
|
69
|
+
const globsOf = (o) => ({
|
|
70
|
+
...(o["files"] ? { files: o["files"] } : {}),
|
|
71
|
+
...(o["ignores"] ? { ignores: o["ignores"] } : {}),
|
|
72
|
+
});
|
|
73
|
+
/** One element of the `rules` list. */
|
|
74
|
+
function parseBlock(v, at, ctx) {
|
|
75
|
+
if (typeof v !== "object" || v === null || Array.isArray(v))
|
|
76
|
+
return bad(`${at} must be an object like { "files": [...], "rules": {...} }`);
|
|
77
|
+
const o = v;
|
|
78
|
+
const extra = Object.keys(o).filter((k) => !BLOCK_KEYS.has(k));
|
|
79
|
+
if (extra.length)
|
|
80
|
+
return bad(`${at}: unknown key "${extra[0]}" — a block takes "files", "ignores" and "rules"`);
|
|
81
|
+
const globs = badGlobs(o, at);
|
|
82
|
+
if (globs)
|
|
83
|
+
return bad(globs);
|
|
84
|
+
const rules = parseRules(o["rules"], at, ctx.shipped);
|
|
85
|
+
if (!rules.ok)
|
|
86
|
+
return rules;
|
|
87
|
+
return {
|
|
88
|
+
ok: true,
|
|
89
|
+
value: { basePath: ctx.baseDir, ...globsOf(o), rules: rules.value },
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The `rules` key → config blocks, or one error naming the key path.
|
|
94
|
+
*
|
|
95
|
+
* @param raw the value under `rules` (undefined when absent)
|
|
96
|
+
* @param where how the settings are named in messages, e.g. `package.json → "paperlint"`
|
|
97
|
+
* @param shipped the rule ids paperlint ships (`shippedRuleIds`)
|
|
98
|
+
* @param baseDir the directory of the file holding the settings
|
|
99
|
+
*/
|
|
100
|
+
export function parseRuleBlocks(raw, where, shipped, baseDir) {
|
|
101
|
+
if (raw === undefined)
|
|
102
|
+
return { ok: true, value: [] };
|
|
103
|
+
if (!Array.isArray(raw))
|
|
104
|
+
return bad(`${where}.rules must be a list of blocks, like ESLint's flat config: [{ "files": [...], "rules": {...} }]`);
|
|
105
|
+
const out = [];
|
|
106
|
+
for (const [i, v] of raw.entries()) {
|
|
107
|
+
const b = parseBlock(v, `${where}.rules[${i}]`, { shipped, baseDir });
|
|
108
|
+
if (!b.ok)
|
|
109
|
+
return b;
|
|
110
|
+
out.push(b.value);
|
|
111
|
+
}
|
|
112
|
+
return { ok: true, value: out };
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* The rule ids a config defines through its own plugins, as `<plugin>/<rule>`. Plugins passed in
|
|
116
|
+
* `foreign` (a dependency's plugin, such as `@eslint/markdown`) are not rpp's and are skipped.
|
|
117
|
+
*/
|
|
118
|
+
export function shippedRuleIds(config, foreign) {
|
|
119
|
+
const ids = new Set();
|
|
120
|
+
for (const block of config) {
|
|
121
|
+
const plugins = block.plugins;
|
|
122
|
+
for (const [name, plugin] of Object.entries(plugins ?? {})) {
|
|
123
|
+
if (foreign.includes(plugin))
|
|
124
|
+
continue;
|
|
125
|
+
const rules = plugin.rules;
|
|
126
|
+
for (const rule of Object.keys(rules ?? {}))
|
|
127
|
+
ids.add(`${name}/${rule}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return ids;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=rules-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules-config.js","sourceRoot":"","sources":["../src/rules-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { StructureConfig, StructureFinding } from "./types.ts";
|
|
2
|
+
/** The requirements after the consumer's config is laid over the defaults. */
|
|
3
|
+
type Rules = Required<StructureConfig>;
|
|
4
|
+
/**
|
|
5
|
+
* The defaults are MEASURED against a live corpus of five paper directories, not picked by taste:
|
|
6
|
+
* under them it passes in full — zero findings. The counter-case was run too: `paper.pdf` added to
|
|
7
|
+
* `require` yields two findings straight away on papers that are perfectly fine — two of the four
|
|
8
|
+
* keep their pdf under a different name. That is why it is not in the defaults; declared pdfs are
|
|
9
|
+
* byte-compared by the `paper/stages` rule anyway.
|
|
10
|
+
*/
|
|
11
|
+
export declare const STRUCTURE_DEFAULTS: {
|
|
12
|
+
markers: string[];
|
|
13
|
+
require: string[];
|
|
14
|
+
requireOneOf: string[][];
|
|
15
|
+
ignore: never[];
|
|
16
|
+
};
|
|
17
|
+
/** The consumer's config over the defaults; `structure: false` turns the check off entirely. */
|
|
18
|
+
export declare function structureRules(structure: StructureConfig | false | undefined): Rules | null;
|
|
19
|
+
/**
|
|
20
|
+
* @returns {{file: string, message: string}[]} findings, one per missing file.
|
|
21
|
+
*/
|
|
22
|
+
export declare function checkStructure(paths: readonly string[], structure: StructureConfig | false | undefined, { cwd }?: {
|
|
23
|
+
cwd?: string;
|
|
24
|
+
}): StructureFinding[];
|
|
25
|
+
export declare function formatStructure(findings: readonly StructureFinding[]): string;
|
|
26
|
+
/**
|
|
27
|
+
* 🔴 ONE SCHEMA FOR BOTH HALVES. Findings about absence are emitted in THE SAME shape as ESLint
|
|
28
|
+
* findings, so `--json` stays a single parseable array. A separate channel would force every
|
|
29
|
+
* consumer to write a second parser — and the first one who did not write it would read "there
|
|
30
|
+
* are no structural findings" instead of "I do not parse them".
|
|
31
|
+
*/
|
|
32
|
+
export declare function asEslintResults(findings: readonly StructureFinding[]): unknown[];
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=structure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structure.d.ts","sourceRoot":"","sources":["../src/structure.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEpE,8EAA8E;AAC9E,KAAK,KAAK,GAAG,QAAQ,CAAC,eAAe,CAAC,CAAC;AAEvC;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB;;;;;CAK9B,CAAC;AAEF,gGAAgG;AAChG,wBAAgB,cAAc,CAC5B,SAAS,EAAE,eAAe,GAAG,KAAK,GAAG,SAAS,GAC7C,KAAK,GAAG,IAAI,CAGd;AAaD;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,SAAS,EAAE,eAAe,GAAG,KAAK,GAAG,SAAS,EAE9C,EAAE,GAAmB,EAAE,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7C,gBAAgB,EAAE,CAyCpB;AAcD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,GAAG,MAAM,CAO7E;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,SAAS,gBAAgB,EAAE,GACpC,OAAO,EAAE,CAqBX"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `paperlint lint` — the half ESLint cannot do BY CONSTRUCTION: checking that the required file
|
|
3
|
+
* IS THERE.
|
|
4
|
+
*
|
|
5
|
+
* 🔴 WHY THIS IS A SEPARATE MODULE AND NOT A RULE. A rule is invoked for a file that was handed
|
|
6
|
+
* to the linter. A file that does not exist is never handed over — so the rule is not invoked,
|
|
7
|
+
* and, not having been invoked, it physically cannot report the absence. A paper directory with
|
|
8
|
+
* no `PIPELINE-STATUS.md` yields NOT ONE finding: not a single pipeline rule runs over it, and
|
|
9
|
+
* the run is green. This is exactly the green zero the `nothing was linted` guard in the CLI
|
|
10
|
+
* stands for, only one level down — not "nothing was linted", but "not everything here was".
|
|
11
|
+
*
|
|
12
|
+
* ⚠️ THIS IS NOT ls-lint's JOB, AND THE TWO ARE NOT INTERCHANGEABLE. ls-lint judges the NAMES of
|
|
13
|
+
* files that exist (`versions/2026-07-22-submitted.pdf` is named to the scheme). About a file
|
|
14
|
+
* that does not exist it says nothing — it has nothing to match. The two halves of structure:
|
|
15
|
+
* ls-lint — "what is there is named correctly"
|
|
16
|
+
* this module — "what is required is there"
|
|
17
|
+
*
|
|
18
|
+
* 🔴 DETECTION IS GENEROUS, REQUIREMENTS ARE STRICT — and this is for the sake of false positives.
|
|
19
|
+
* An error-level rule that fails on a correct tree does not get fixed, it gets turned off, and the
|
|
20
|
+
* real findings go with it. So a directory counts as a paper only if it ALREADY holds at least one
|
|
21
|
+
* pipeline marker; `research/`, `plans/` and the other neighbours in the corpus are not touched at
|
|
22
|
+
* all.
|
|
23
|
+
*/
|
|
24
|
+
// eslint-disable-next-line boundaries/dependencies -- legacy I/O, moves behind a port in #76
|
|
25
|
+
import { readdirSync, existsSync } from "node:fs";
|
|
26
|
+
import { join, relative, basename, isAbsolute, sep } from "node:path";
|
|
27
|
+
/**
|
|
28
|
+
* The defaults are MEASURED against a live corpus of five paper directories, not picked by taste:
|
|
29
|
+
* under them it passes in full — zero findings. The counter-case was run too: `paper.pdf` added to
|
|
30
|
+
* `require` yields two findings straight away on papers that are perfectly fine — two of the four
|
|
31
|
+
* keep their pdf under a different name. That is why it is not in the defaults; declared pdfs are
|
|
32
|
+
* byte-compared by the `paper/stages` rule anyway.
|
|
33
|
+
*/
|
|
34
|
+
export const STRUCTURE_DEFAULTS = {
|
|
35
|
+
markers: ["PIPELINE-STATUS.md", "paper.tex", "paper.md", "venue.json"],
|
|
36
|
+
require: ["PIPELINE-STATUS.md"],
|
|
37
|
+
requireOneOf: [["paper.tex", "paper.md"]],
|
|
38
|
+
ignore: [],
|
|
39
|
+
};
|
|
40
|
+
/** The consumer's config over the defaults; `structure: false` turns the check off entirely. */
|
|
41
|
+
export function structureRules(structure) {
|
|
42
|
+
if (structure === false)
|
|
43
|
+
return null;
|
|
44
|
+
return { ...STRUCTURE_DEFAULTS, ...(structure ?? {}) };
|
|
45
|
+
}
|
|
46
|
+
const dirsIn = (dir) => {
|
|
47
|
+
try {
|
|
48
|
+
return readdirSync(dir, { withFileTypes: true })
|
|
49
|
+
.filter((e) => e.isDirectory() && !e.name.startsWith("."))
|
|
50
|
+
.map((e) => e.name);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// A non-existent directory is not our concern: the empty-set guard says so loudly.
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* @returns {{file: string, message: string}[]} findings, one per missing file.
|
|
59
|
+
*/
|
|
60
|
+
export function checkStructure(paths, structure,
|
|
61
|
+
// eslint-disable-next-line no-restricted-globals -- legacy I/O, moves behind a port in #76
|
|
62
|
+
{ cwd = process.cwd() } = {}) {
|
|
63
|
+
const rules = structureRules(structure);
|
|
64
|
+
if (!rules)
|
|
65
|
+
return [];
|
|
66
|
+
const findings = [];
|
|
67
|
+
// Relative to where the command was typed — unless the paper lives outside it (#48): then the
|
|
68
|
+
// absolute path, not a ladder of `../../../` that has to be counted to be read.
|
|
69
|
+
const say = (p) => {
|
|
70
|
+
const rel = relative(cwd, p);
|
|
71
|
+
return rel &&
|
|
72
|
+
rel !== ".." &&
|
|
73
|
+
!rel.startsWith(`..${sep}`) &&
|
|
74
|
+
!isAbsolute(rel)
|
|
75
|
+
? rel
|
|
76
|
+
: p;
|
|
77
|
+
};
|
|
78
|
+
for (const root of paths) {
|
|
79
|
+
for (const name of dirsIn(root)) {
|
|
80
|
+
if (rules.ignore.includes(name))
|
|
81
|
+
continue;
|
|
82
|
+
const dir = join(root, name);
|
|
83
|
+
// Generous detection: with not one marker this is just a neighbour directory, not a paper.
|
|
84
|
+
if (!rules.markers.some((m) => existsSync(join(dir, m))))
|
|
85
|
+
continue;
|
|
86
|
+
for (const required of rules.require)
|
|
87
|
+
if (!existsSync(join(dir, required)))
|
|
88
|
+
findings.push({
|
|
89
|
+
file: say(dir),
|
|
90
|
+
message: `missing \`${required}\` — ${whyMissingMatters(required, basename(dir))}`,
|
|
91
|
+
});
|
|
92
|
+
for (const group of rules.requireOneOf)
|
|
93
|
+
if (!group.some((f) => existsSync(join(dir, f))))
|
|
94
|
+
findings.push({
|
|
95
|
+
file: say(dir),
|
|
96
|
+
message: `missing all of ${group.map((f) => `\`${f}\``).join(", ")} — a paper directory with no source is not something the rules can check`,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return findings;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* The message NAMES THE CONSEQUENCE rather than restating the condition. "missing
|
|
104
|
+
* PIPELINE-STATUS.md" without the second half reads as nitpicking about formatting; with it you
|
|
105
|
+
* can see which checks the directory silently loses — the rules that read the scorecard; the rules
|
|
106
|
+
* over `paper.md` / `paper.tex` still run.
|
|
107
|
+
*/
|
|
108
|
+
function whyMissingMatters(file, dirName) {
|
|
109
|
+
if (file === "PIPELINE-STATUS.md")
|
|
110
|
+
return `\`paper/stages\`, \`paper/source\` and \`paper/author-list\` read this file, so nothing \`${dirName}\` declares about its stages, sources or authors is checked`;
|
|
111
|
+
return `declared as required by your \`structure\` configuration`;
|
|
112
|
+
}
|
|
113
|
+
export function formatStructure(findings) {
|
|
114
|
+
const byDir = new Map();
|
|
115
|
+
for (const f of findings)
|
|
116
|
+
byDir.set(f.file, [...(byDir.get(f.file) ?? []), f.message]);
|
|
117
|
+
return [...byDir]
|
|
118
|
+
.map(([dir, msgs]) => [dir, ...msgs.map((m) => ` error ${m}`)].join("\n"))
|
|
119
|
+
.join("\n\n");
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* 🔴 ONE SCHEMA FOR BOTH HALVES. Findings about absence are emitted in THE SAME shape as ESLint
|
|
123
|
+
* findings, so `--json` stays a single parseable array. A separate channel would force every
|
|
124
|
+
* consumer to write a second parser — and the first one who did not write it would read "there
|
|
125
|
+
* are no structural findings" instead of "I do not parse them".
|
|
126
|
+
*/
|
|
127
|
+
export function asEslintResults(findings) {
|
|
128
|
+
const byDir = new Map();
|
|
129
|
+
for (const f of findings)
|
|
130
|
+
byDir.set(f.file, [...(byDir.get(f.file) ?? []), f.message]);
|
|
131
|
+
return [...byDir].map(([filePath, msgs]) => ({
|
|
132
|
+
filePath,
|
|
133
|
+
messages: msgs.map((message) => ({
|
|
134
|
+
ruleId: "structure/required-file",
|
|
135
|
+
severity: 2,
|
|
136
|
+
message,
|
|
137
|
+
line: 0,
|
|
138
|
+
column: 0,
|
|
139
|
+
})),
|
|
140
|
+
errorCount: msgs.length,
|
|
141
|
+
fatalErrorCount: 0,
|
|
142
|
+
warningCount: 0,
|
|
143
|
+
fixableErrorCount: 0,
|
|
144
|
+
fixableWarningCount: 0,
|
|
145
|
+
suppressedMessages: [],
|
|
146
|
+
usedDeprecatedRules: [],
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=structure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structure.js","sourceRoot":"","sources":["../src/structure.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** CTAN package name → the names that prove it is installed. */
|
|
2
|
+
export type PackageProofs = Readonly<Record<string, readonly string[]>>;
|
|
3
|
+
export interface TexRequirements {
|
|
4
|
+
/** Proved by `kpsewhich <file>` — files LaTeX loads. */
|
|
5
|
+
readonly packages: PackageProofs;
|
|
6
|
+
/** Proved by an executable in TeX Live's bin directory — programs, not files. */
|
|
7
|
+
readonly tools: PackageProofs;
|
|
8
|
+
}
|
|
9
|
+
/** The requirements for one paper, and where they came from — printed, never guessed silently. */
|
|
10
|
+
export interface PaperRequirements {
|
|
11
|
+
readonly source: string;
|
|
12
|
+
readonly tex: TexRequirements;
|
|
13
|
+
}
|
|
14
|
+
/** The profile every paper gets, and the only one a paper with an unknown venue gets. */
|
|
15
|
+
export declare const BASE_PROFILE = "tex-base.jsonc";
|
|
16
|
+
export declare const SCHEMA_FILE = "venue-profile.schema.json";
|
|
17
|
+
export declare const NO_REQUIREMENTS: TexRequirements;
|
|
18
|
+
/**
|
|
19
|
+
* The text of one profile → its typed requirements, or an Error naming every problem.
|
|
20
|
+
*
|
|
21
|
+
* @param text the file's contents
|
|
22
|
+
* @param file the name to put in messages
|
|
23
|
+
* @param dir the directory holding the schema (the shipped venues directory by default)
|
|
24
|
+
*/
|
|
25
|
+
export declare function parseProfile(text: string, file: string, dir?: string): TexRequirements;
|
|
26
|
+
/** The venues that have a profile — every `.jsonc` in the directory except the base set. */
|
|
27
|
+
export declare function venueNames(dir?: string): string[];
|
|
28
|
+
/** The union of two sets of requirements; a package declared by both keeps every proof of both. */
|
|
29
|
+
export declare function mergeRequirements(a: TexRequirements, b: TexRequirements): TexRequirements;
|
|
30
|
+
/** Every package name, packages and tools together, sorted — what tlmgr is asked for. */
|
|
31
|
+
export declare function packageNames(tex: TexRequirements): string[];
|
|
32
|
+
/**
|
|
33
|
+
* What ONE paper needs: the base set plus its venue's block. A paper with no venue, or a venue this
|
|
34
|
+
* package has no profile for, gets the base set — and the source says which, so an ACM paper built
|
|
35
|
+
* without `venue.json` is visibly running on the base set rather than silently.
|
|
36
|
+
*/
|
|
37
|
+
export declare function requirementsFor(venue: string | null, dir?: string): PaperRequirements;
|
|
38
|
+
/** Everything any profile declares — the set `paperlint toolchain` installs, so one tree builds any paper. */
|
|
39
|
+
export declare function declaredUnion(dir?: string): {
|
|
40
|
+
readonly tex: TexRequirements;
|
|
41
|
+
readonly profiles: number;
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=tex-requirements.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tex-requirements.d.ts","sourceRoot":"","sources":["../src/tex-requirements.ts"],"names":[],"mappings":"AA6BA,gEAAgE;AAChE,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;AAExE,MAAM,WAAW,eAAe;IAC9B,wDAAwD;IACxD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,iFAAiF;IACjF,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;CAC/B;AAED,kGAAkG;AAClG,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAC;CAC/B;AAED,yFAAyF;AACzF,eAAO,MAAM,YAAY,mBAAmB,CAAC;AAC7C,eAAO,MAAM,WAAW,8BAA8B,CAAC;AAGvD,eAAO,MAAM,eAAe,EAAE,eAA6C,CAAC;AA8B5E;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,GAAG,GAAE,MAA2B,GAC/B,eAAe,CAajB;AAMD,4FAA4F;AAC5F,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAA2B,GAAG,MAAM,EAAE,CAKrE;AAED,mGAAmG;AACnG,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,eAAe,EAClB,CAAC,EAAE,eAAe,GACjB,eAAe,CAWjB;AAED,yFAAyF;AACzF,wBAAgB,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,EAAE,CAI3D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,GAAG,GAAE,MAA2B,GAC/B,iBAAiB,CAiBnB;AAED,8GAA8G;AAC9G,wBAAgB,aAAa,CAAC,GAAG,GAAE,MAA2B,GAAG;IAC/D,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAOA"}
|