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,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What makes a file a HARNESS. A `*.harness.*` file tests the agent surface, so it drives it through
|
|
3
|
+
* vigiles: it imports `runHook`, `runHarnessTest` or `runEval` from `vigiles` (or a `vigiles/…`
|
|
4
|
+
* entry point). Anything else is a plain unit test and is named `*.test.ts`, run by vitest.
|
|
5
|
+
*
|
|
6
|
+
* The rule is read from the file's IMPORTS, parsed with the TypeScript compiler — not from its
|
|
7
|
+
* folder and not from a text search: a comment or a string that mentions `runHook` is not an import,
|
|
8
|
+
* and `src/cli.harness.mjs` calls a function of rpp's own that happens to be called `runHook`.
|
|
9
|
+
*
|
|
10
|
+
* Harnesses that predate the rule and import none of the three are frozen in
|
|
11
|
+
* `harness-api.frozen.json` (issue #77). That list only shrinks: an entry that now imports the API,
|
|
12
|
+
* or that no longer exists, has to leave it.
|
|
13
|
+
*/
|
|
14
|
+
import assert from "node:assert/strict";
|
|
15
|
+
import { execFileSync } from "node:child_process";
|
|
16
|
+
import { readFileSync } from "node:fs";
|
|
17
|
+
import { basename, dirname, join } from "node:path";
|
|
18
|
+
import { test } from "vitest";
|
|
19
|
+
import { fileURLToPath } from "node:url";
|
|
20
|
+
import ts from "typescript";
|
|
21
|
+
|
|
22
|
+
const ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
23
|
+
const FROZEN: readonly string[] = (
|
|
24
|
+
JSON.parse(
|
|
25
|
+
readFileSync(join(ROOT, "scripts", "harness-api.frozen.json"), "utf8"),
|
|
26
|
+
) as { harnesses: string[] }
|
|
27
|
+
).harnesses;
|
|
28
|
+
|
|
29
|
+
/** vigiles' agent-testing API — what a harness exists to call. */
|
|
30
|
+
export const AGENT_API = new Set(["runHook", "runHarnessTest", "runEval"]);
|
|
31
|
+
|
|
32
|
+
const isHarnessName = (path: string): boolean =>
|
|
33
|
+
/\.harness\.[cm]?[jt]s$/.test(basename(path));
|
|
34
|
+
|
|
35
|
+
const fromVigiles = (spec: ts.Expression | undefined): boolean =>
|
|
36
|
+
spec !== undefined &&
|
|
37
|
+
ts.isStringLiteral(spec) &&
|
|
38
|
+
(spec.text === "vigiles" || spec.text.startsWith("vigiles/"));
|
|
39
|
+
|
|
40
|
+
/** Names bound by `import { a, b as c } from "vigiles…"` — the EXPORTED names, a and b. */
|
|
41
|
+
function staticNames(node: ts.Node): string[] {
|
|
42
|
+
if (!ts.isImportDeclaration(node) || !fromVigiles(node.moduleSpecifier))
|
|
43
|
+
return [];
|
|
44
|
+
const named = node.importClause?.namedBindings;
|
|
45
|
+
if (!named || !ts.isNamedImports(named)) return [];
|
|
46
|
+
return named.elements.map((e) => (e.propertyName ?? e.name).text);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Names destructured from `await import("vigiles…")`: `const { runHook } = await import(…)`. */
|
|
50
|
+
function dynamicNames(node: ts.Node): string[] {
|
|
51
|
+
if (!ts.isVariableDeclaration(node) || !node.initializer) return [];
|
|
52
|
+
if (!ts.isObjectBindingPattern(node.name)) return [];
|
|
53
|
+
const init = ts.isAwaitExpression(node.initializer)
|
|
54
|
+
? node.initializer.expression
|
|
55
|
+
: node.initializer;
|
|
56
|
+
const isImport =
|
|
57
|
+
ts.isCallExpression(init) &&
|
|
58
|
+
init.expression.kind === ts.SyntaxKind.ImportKeyword &&
|
|
59
|
+
fromVigiles(init.arguments[0]);
|
|
60
|
+
if (!isImport) return [];
|
|
61
|
+
return node.name.elements.map((e) => {
|
|
62
|
+
const key = e.propertyName ?? e.name;
|
|
63
|
+
return ts.isIdentifier(key) ? key.text : "";
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Does this source import at least one of vigiles' agent-testing functions? */
|
|
68
|
+
export function importsAgentApi(fileName: string, source: string): boolean {
|
|
69
|
+
const sf = ts.createSourceFile(fileName, source, ts.ScriptTarget.Latest);
|
|
70
|
+
let found = false;
|
|
71
|
+
const visit = (node: ts.Node): void => {
|
|
72
|
+
if (
|
|
73
|
+
[...staticNames(node), ...dynamicNames(node)].some((n) =>
|
|
74
|
+
AGENT_API.has(n),
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
found = true;
|
|
78
|
+
if (!found) ts.forEachChild(node, visit);
|
|
79
|
+
};
|
|
80
|
+
visit(sf);
|
|
81
|
+
return found;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Harness-named files, among `paths`, that import none of the API and are not frozen. */
|
|
85
|
+
export function misnamed(
|
|
86
|
+
files: ReadonlyMap<string, string>,
|
|
87
|
+
frozen: readonly string[],
|
|
88
|
+
): string[] {
|
|
89
|
+
return [...files]
|
|
90
|
+
.filter(([p]) => isHarnessName(p) && !frozen.includes(p))
|
|
91
|
+
.filter(([p, src]) => !importsAgentApi(p, src))
|
|
92
|
+
.map(([p]) => p);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Frozen entries that must leave: gone from the tree, or now importing the API. */
|
|
96
|
+
export function mustLeave(
|
|
97
|
+
files: ReadonlyMap<string, string>,
|
|
98
|
+
frozen: readonly string[],
|
|
99
|
+
): string[] {
|
|
100
|
+
return frozen.filter((f) => {
|
|
101
|
+
const src = files.get(f);
|
|
102
|
+
return src === undefined || importsAgentApi(f, src);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Every harness-named file git knows about (tracked, or new and not ignored), with its source. */
|
|
107
|
+
function harnessesOnDisk(): Map<string, string> {
|
|
108
|
+
const listed = execFileSync(
|
|
109
|
+
"git",
|
|
110
|
+
["ls-files", "--cached", "--others", "--exclude-standard"],
|
|
111
|
+
{ cwd: ROOT, encoding: "utf8" },
|
|
112
|
+
)
|
|
113
|
+
.split("\n")
|
|
114
|
+
.filter(isHarnessName);
|
|
115
|
+
return new Map(
|
|
116
|
+
listed.map((p) => [p, readFileSync(join(ROOT, p), "utf8")] as const),
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
test("every harness imports vigiles' agent-testing API, or is on the frozen list", () => {
|
|
121
|
+
// Guards: the rule on the real tree — a new plain test named `*.harness.*` turns this red.
|
|
122
|
+
assert.deepEqual(misnamed(harnessesOnDisk(), FROZEN), []);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("the frozen list only shrinks", () => {
|
|
126
|
+
// Guards: a renamed, deleted or converted harness must leave the list, or it stops meaning anything.
|
|
127
|
+
assert.deepEqual(mustLeave(harnessesOnDisk(), FROZEN), []);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("both halves, on planted files", () => {
|
|
131
|
+
const plain = 'import assert from "node:assert";\nassert.ok(true);\n';
|
|
132
|
+
const real = 'import { runHook } from "vigiles";\nrunHook("true", {});\n';
|
|
133
|
+
const files = new Map([
|
|
134
|
+
["skills/x/x.harness.ts", plain],
|
|
135
|
+
["src/y.harness.mjs", real],
|
|
136
|
+
[
|
|
137
|
+
"hooks/h.harness.mjs",
|
|
138
|
+
'const { runEval } = await import("vigiles/eval");\n',
|
|
139
|
+
],
|
|
140
|
+
["src/z.test.ts", plain],
|
|
141
|
+
]);
|
|
142
|
+
// Guards: the fire half — a plain test named as a harness fails EVEN inside skills/.
|
|
143
|
+
assert.deepEqual(misnamed(files, []), ["skills/x/x.harness.ts"]);
|
|
144
|
+
// Guards: a file that is on the list but now imports the API has to leave it.
|
|
145
|
+
assert.deepEqual(mustLeave(files, ["src/y.harness.mjs"]), [
|
|
146
|
+
"src/y.harness.mjs",
|
|
147
|
+
]);
|
|
148
|
+
// Guards: an entry whose file is gone has to leave it.
|
|
149
|
+
assert.deepEqual(mustLeave(files, ["gone.harness.mjs"]), [
|
|
150
|
+
"gone.harness.mjs",
|
|
151
|
+
]);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test("an import is what counts — not a mention, not a same-named local function", () => {
|
|
155
|
+
// Guards: a comment and a string naming runHook do not make a harness.
|
|
156
|
+
const mention =
|
|
157
|
+
'// runHook\nconst s = "runHarnessTest";\nimport { x } from "vigiles";\n';
|
|
158
|
+
assert.equal(importsAgentApi("a.harness.mjs", mention), false);
|
|
159
|
+
// Guards: rpp's own `runHook` (src/cli.ts) is not vigiles'.
|
|
160
|
+
assert.equal(
|
|
161
|
+
importsAgentApi(
|
|
162
|
+
"b.harness.mjs",
|
|
163
|
+
'import { runHook } from "../src/cli.ts";\n',
|
|
164
|
+
),
|
|
165
|
+
false,
|
|
166
|
+
);
|
|
167
|
+
// Guards: an aliased import still counts by the name vigiles exports.
|
|
168
|
+
assert.equal(
|
|
169
|
+
importsAgentApi(
|
|
170
|
+
"c.harness.mjs",
|
|
171
|
+
'import { runHook as hook } from "vigiles";\n',
|
|
172
|
+
),
|
|
173
|
+
true,
|
|
174
|
+
);
|
|
175
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Types for `layer-legacy-frozen.mjs`, for its TypeScript test. */
|
|
2
|
+
export interface Suppressed {
|
|
3
|
+
readonly filePath: string;
|
|
4
|
+
readonly suppressedMessages?: readonly {
|
|
5
|
+
readonly ruleId: string | null;
|
|
6
|
+
readonly line: number;
|
|
7
|
+
readonly suppressions?: readonly { readonly justification?: string }[];
|
|
8
|
+
}[];
|
|
9
|
+
}
|
|
10
|
+
export type Counts = Record<string, Record<string, number>>;
|
|
11
|
+
export declare const FROZEN_FILE: string;
|
|
12
|
+
export declare const LAYER_RULES: readonly string[];
|
|
13
|
+
export declare const NO_LEGACY_UNDER: readonly string[];
|
|
14
|
+
export declare const LEGACY: RegExp;
|
|
15
|
+
export declare function tally(results: readonly Suppressed[]): {
|
|
16
|
+
counts: Counts;
|
|
17
|
+
unexplained: string[];
|
|
18
|
+
};
|
|
19
|
+
export declare function judge(o: {
|
|
20
|
+
counts: Counts;
|
|
21
|
+
unexplained: readonly string[];
|
|
22
|
+
frozen: Counts;
|
|
23
|
+
}): string[];
|
|
24
|
+
export declare function checkFrozen(root?: string): Promise<{
|
|
25
|
+
problems: string[];
|
|
26
|
+
frozen: Counts;
|
|
27
|
+
counts: Counts;
|
|
28
|
+
}>;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* layer-legacy-frozen.mjs — the legacy exemptions from `src/`'s layer rules may only SHRINK.
|
|
4
|
+
*
|
|
5
|
+
* `src/` is hexagonal on two axes (src/CLAUDE.md): who may know whom, and where effects may be
|
|
6
|
+
* written. The flat `src/*.ts` files predate both. Each site in them that still breaks a rule
|
|
7
|
+
* carries a directive naming the debt:
|
|
8
|
+
*
|
|
9
|
+
* // eslint-disable-next-line boundaries/dependencies -- legacy I/O, moves behind a port in #76
|
|
10
|
+
* // eslint-disable-next-line boundaries/dependencies -- legacy layer, moves behind a port in #76
|
|
11
|
+
*
|
|
12
|
+
* `reportUnusedDisableDirectives: "error"` already makes a directive that suppresses nothing a lint
|
|
13
|
+
* error, so a fixed site must drop its comment. What that cannot stop is a NEW directive: a new file,
|
|
14
|
+
* or a new import in an old one, silenced the same way. This check freezes the per-file counts, in
|
|
15
|
+
* the shape `mutation-batteries-frozen.mjs` gives the mutation batteries:
|
|
16
|
+
*
|
|
17
|
+
* 1. a file carrying a legacy suppression that is not in the frozen list fails — a new exemption;
|
|
18
|
+
* 2. a listed file with no legacy suppression left fails — the list must shrink with the code;
|
|
19
|
+
* 3. a count that grew fails;
|
|
20
|
+
* 4. a count that shrank fails until the recorded number is lowered — otherwise a fixed site
|
|
21
|
+
* leaves room for a different one to be silenced later.
|
|
22
|
+
*
|
|
23
|
+
* Plus two refusals the frozen list cannot express: no file under `src/domain/`, `src/ports/` or
|
|
24
|
+
* `src/adapters/` may carry one at all (those folders were written under the rules, so there is no
|
|
25
|
+
* legacy there to hold), and a layer finding silenced WITHOUT naming #76 is not a legacy site but
|
|
26
|
+
* an unexplained exemption.
|
|
27
|
+
*
|
|
28
|
+
* ── COUNTED FROM ESLINT'S OWN REPORT, NOT FROM THE SOURCE TEXT ─────────────────────────────
|
|
29
|
+
* The unit is a SUPPRESSED FINDING, read from `LintResult.suppressedMessages[].suppressions[]`:
|
|
30
|
+
* the linter itself says which finding a directive silenced and with what justification. A
|
|
31
|
+
* comment that only looks like a directive, or one on a line with nothing to silence, cannot be
|
|
32
|
+
* counted by construction — and a range directive (`/* eslint-disable … *\/` around a multi-line
|
|
33
|
+
* import) counts exactly what it silences.
|
|
34
|
+
*
|
|
35
|
+
* Run: `node scripts/layer-legacy-frozen.mjs` (also part of `npm run check`)
|
|
36
|
+
*/
|
|
37
|
+
import { readFileSync } from "node:fs";
|
|
38
|
+
import { dirname, join, relative, sep } from "node:path";
|
|
39
|
+
import { fileURLToPath } from "node:url";
|
|
40
|
+
import { ESLint } from "eslint";
|
|
41
|
+
|
|
42
|
+
const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
43
|
+
export const FROZEN_FILE = join("scripts", "layer-legacy.frozen.json");
|
|
44
|
+
|
|
45
|
+
/** The rules that enforce the layers. A suppression of any other rule is not this check's business. */
|
|
46
|
+
export const LAYER_RULES = ["boundaries/dependencies", "no-restricted-globals"];
|
|
47
|
+
|
|
48
|
+
/** Where a legacy suppression may never appear: the folders written under the rules. */
|
|
49
|
+
export const NO_LEGACY_UNDER = ["src/domain/", "src/ports/", "src/adapters/"];
|
|
50
|
+
|
|
51
|
+
/** The justification every legacy directive carries — `I/O` or `layer`, then the issue. */
|
|
52
|
+
export const LEGACY = /^legacy (I\/O|layer), moves behind a port in #76$/;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Per file, per rule: how many layer findings a legacy directive suppressed. Pure: takes ESLint's
|
|
56
|
+
* results (`filePath` relative to the repository, POSIX separators) and returns the tally plus
|
|
57
|
+
* every layer suppression that is not a legacy one.
|
|
58
|
+
*/
|
|
59
|
+
export function tally(results) {
|
|
60
|
+
const counts = {};
|
|
61
|
+
const unexplained = [];
|
|
62
|
+
for (const r of results)
|
|
63
|
+
for (const m of r.suppressedMessages ?? []) {
|
|
64
|
+
if (!LAYER_RULES.includes(m.ruleId ?? "")) continue;
|
|
65
|
+
const why = (m.suppressions ?? []).map((s) => s.justification ?? "");
|
|
66
|
+
if (!why.some((j) => LEGACY.test(j.trim()))) {
|
|
67
|
+
unexplained.push(
|
|
68
|
+
`${r.filePath}:${String(m.line)}: ${String(m.ruleId)} is silenced with "${why.join(" | ")}" — a layer exemption must say "legacy I/O|layer, moves behind a port in #76", or the site must be fixed.`,
|
|
69
|
+
);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const file = (counts[r.filePath] ??= {});
|
|
73
|
+
file[m.ruleId] = (file[m.ruleId] ?? 0) + 1;
|
|
74
|
+
}
|
|
75
|
+
return { counts, unexplained };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Compare the tally with the frozen list. Pure. `frozen` is `{ path: { rule: count } }`. */
|
|
79
|
+
export function judge({ counts, unexplained, frozen }) {
|
|
80
|
+
const problems = [...unexplained];
|
|
81
|
+
for (const [f, rules] of Object.entries(counts)) {
|
|
82
|
+
if (NO_LEGACY_UNDER.some((d) => f.startsWith(d)))
|
|
83
|
+
problems.push(
|
|
84
|
+
`${f}: carries a legacy layer exemption, and nothing under ${NO_LEGACY_UNDER.join(", ")} may — those folders are written under the rules. Fix the site (src/CLAUDE.md).`,
|
|
85
|
+
);
|
|
86
|
+
else if (!(f in frozen))
|
|
87
|
+
problems.push(
|
|
88
|
+
`${f}: a new legacy layer exemption is not accepted (#76). A module that needs the world is a new *.io.ts in the adapter of the program it talks to; an app file takes a port.`,
|
|
89
|
+
);
|
|
90
|
+
for (const [rule, got] of Object.entries(rules)) {
|
|
91
|
+
const want = frozen[f]?.[rule];
|
|
92
|
+
if (want === undefined) {
|
|
93
|
+
if (f in frozen)
|
|
94
|
+
problems.push(
|
|
95
|
+
`${f}: ${String(got)} legacy ${rule} suppression(s), frozen at 0 — no new exemptions in existing files (#76).`,
|
|
96
|
+
);
|
|
97
|
+
} else if (got > want)
|
|
98
|
+
problems.push(
|
|
99
|
+
`${f}: ${String(got)} legacy ${rule} suppressions, frozen at ${String(want)} — no new exemptions in existing files (#76).`,
|
|
100
|
+
);
|
|
101
|
+
else if (got < want)
|
|
102
|
+
problems.push(
|
|
103
|
+
`${f}: ${String(got)} legacy ${rule} suppressions, frozen at ${String(want)} — lower it to ${String(got)} in ${FROZEN_FILE} (the list must shrink with the code).`,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
for (const [f, rules] of Object.entries(frozen))
|
|
108
|
+
for (const [rule, want] of Object.entries(rules))
|
|
109
|
+
if (!counts[f]?.[rule])
|
|
110
|
+
problems.push(
|
|
111
|
+
`${f}: no legacy ${rule} suppression left (frozen at ${String(want)}) — remove it from ${FROZEN_FILE}.`,
|
|
112
|
+
);
|
|
113
|
+
return problems;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Lint `src/` with the repository's configuration and run the whole check. */
|
|
117
|
+
export async function checkFrozen(root = ROOT) {
|
|
118
|
+
const data = JSON.parse(readFileSync(join(root, FROZEN_FILE), "utf8"));
|
|
119
|
+
const frozen = data.files ?? {};
|
|
120
|
+
const eslint = new ESLint({ cwd: root });
|
|
121
|
+
const raw = await eslint.lintFiles(["src/**/*.ts"]);
|
|
122
|
+
// Guards: a glob that matched nothing tallies nothing and reports every frozen file as fixed.
|
|
123
|
+
if (raw.length === 0)
|
|
124
|
+
return {
|
|
125
|
+
problems: ["src/**/*.ts matched no file — nothing was counted."],
|
|
126
|
+
frozen,
|
|
127
|
+
counts: {},
|
|
128
|
+
};
|
|
129
|
+
const results = raw.map((r) => ({
|
|
130
|
+
...r,
|
|
131
|
+
filePath: relative(root, r.filePath).split(sep).join("/"),
|
|
132
|
+
}));
|
|
133
|
+
const t = tally(results);
|
|
134
|
+
return { problems: judge({ ...t, frozen }), frozen, counts: t.counts };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
138
|
+
const { problems, counts } = await checkFrozen(ROOT);
|
|
139
|
+
if (problems.length) {
|
|
140
|
+
console.error(
|
|
141
|
+
`🔴 legacy layer exemptions are frozen and may only shrink (#76) — ${String(problems.length)} problem(s):`,
|
|
142
|
+
);
|
|
143
|
+
for (const p of problems) console.error(` ${p}`);
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
const n = Object.values(counts)
|
|
147
|
+
.flatMap((r) => Object.values(r))
|
|
148
|
+
.reduce((s, v) => s + v, 0);
|
|
149
|
+
console.log(
|
|
150
|
+
`✓ ${String(Object.keys(counts).length)} legacy files, ${String(n)} frozen layer exemptions, none new, none grown (#76)`,
|
|
151
|
+
);
|
|
152
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The legacy-exemption ratchet (`layer-legacy-frozen.mjs`): each of its refusals fires on a planted
|
|
3
|
+
* case and stays silent on the matching clean one. The inputs are ESLint's own result shape, so the
|
|
4
|
+
* tally is tested on what the linter reports, not on source text.
|
|
5
|
+
*/
|
|
6
|
+
import assert from "node:assert/strict";
|
|
7
|
+
import { test } from "vitest";
|
|
8
|
+
import { judge, tally, type Suppressed } from "./layer-legacy-frozen.mjs";
|
|
9
|
+
|
|
10
|
+
const IO = "legacy I/O, moves behind a port in #76";
|
|
11
|
+
const LAYER = "legacy layer, moves behind a port in #76";
|
|
12
|
+
|
|
13
|
+
/** One file's result with a suppressed finding per `[rule, justification]`. */
|
|
14
|
+
const result = (filePath: string, ...s: [string, string][]): Suppressed => ({
|
|
15
|
+
filePath,
|
|
16
|
+
suppressedMessages: s.map(([ruleId, justification], i) => ({
|
|
17
|
+
ruleId,
|
|
18
|
+
line: i + 1,
|
|
19
|
+
suppressions: [{ justification }],
|
|
20
|
+
})),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const BUILD = result(
|
|
24
|
+
"src/build.ts",
|
|
25
|
+
["boundaries/dependencies", IO],
|
|
26
|
+
["boundaries/dependencies", LAYER],
|
|
27
|
+
["no-restricted-globals", IO],
|
|
28
|
+
);
|
|
29
|
+
const FROZEN = {
|
|
30
|
+
"src/build.ts": { "boundaries/dependencies": 2, "no-restricted-globals": 1 },
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const problemsOf = (results: Suppressed[], frozen = FROZEN) =>
|
|
34
|
+
judge({ ...tally(results), frozen });
|
|
35
|
+
|
|
36
|
+
test("counts per file and rule, and a tally equal to the frozen list is clean", () => {
|
|
37
|
+
assert.deepEqual(tally([BUILD]).counts, FROZEN);
|
|
38
|
+
assert.deepEqual(problemsOf([BUILD]), []);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("a legacy suppression in a file the list does not name is a new exemption", () => {
|
|
42
|
+
const p = problemsOf([
|
|
43
|
+
BUILD,
|
|
44
|
+
result("src/new.ts", ["boundaries/dependencies", IO]),
|
|
45
|
+
]);
|
|
46
|
+
assert.equal(p.length, 1);
|
|
47
|
+
assert.match(p[0] ?? "", /^src\/new\.ts: a new legacy layer exemption/);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("a count that grew fails, and so does a rule the file was not frozen with", () => {
|
|
51
|
+
const grown = result(
|
|
52
|
+
"src/build.ts",
|
|
53
|
+
["boundaries/dependencies", IO],
|
|
54
|
+
["boundaries/dependencies", IO],
|
|
55
|
+
["boundaries/dependencies", IO],
|
|
56
|
+
["no-restricted-globals", IO],
|
|
57
|
+
);
|
|
58
|
+
assert.match(
|
|
59
|
+
problemsOf([grown]).join("\n"),
|
|
60
|
+
/3 legacy boundaries\/dependencies suppressions, frozen at 2/,
|
|
61
|
+
);
|
|
62
|
+
const newRule = judge({
|
|
63
|
+
...tally([BUILD]),
|
|
64
|
+
frozen: { "src/build.ts": { "boundaries/dependencies": 2 } },
|
|
65
|
+
});
|
|
66
|
+
assert.match(
|
|
67
|
+
newRule.join("\n"),
|
|
68
|
+
/no-restricted-globals suppression\(s\), frozen at 0/,
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test("a count that shrank fails until the frozen number is lowered, and a fixed file must leave", () => {
|
|
73
|
+
const shrunk = result(
|
|
74
|
+
"src/build.ts",
|
|
75
|
+
["boundaries/dependencies", IO],
|
|
76
|
+
["no-restricted-globals", IO],
|
|
77
|
+
);
|
|
78
|
+
assert.match(problemsOf([shrunk]).join("\n"), /lower it to 1/);
|
|
79
|
+
assert.match(
|
|
80
|
+
problemsOf([]).join("\n"),
|
|
81
|
+
/src\/build\.ts: no legacy boundaries\/dependencies suppression left/,
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("no file inside the new folders may carry one, even if someone froze it", () => {
|
|
86
|
+
for (const f of [
|
|
87
|
+
"src/domain/x.ts",
|
|
88
|
+
"src/ports/x.ts",
|
|
89
|
+
"src/adapters/banal/x.ts",
|
|
90
|
+
]) {
|
|
91
|
+
const p = problemsOf([BUILD, result(f, ["boundaries/dependencies", IO])], {
|
|
92
|
+
...FROZEN,
|
|
93
|
+
[f]: { "boundaries/dependencies": 1 },
|
|
94
|
+
});
|
|
95
|
+
assert.equal(p.length, 1, p.join("\n"));
|
|
96
|
+
assert.match(p[0] ?? "", /written under the rules/);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("a layer finding silenced without naming #76 is reported; other rules' suppressions are not counted", () => {
|
|
101
|
+
const r = result(
|
|
102
|
+
"src/build.ts",
|
|
103
|
+
["boundaries/dependencies", IO],
|
|
104
|
+
["boundaries/dependencies", LAYER],
|
|
105
|
+
["no-restricted-globals", IO],
|
|
106
|
+
["boundaries/dependencies", "temporary"],
|
|
107
|
+
["@typescript-eslint/no-explicit-any", "#49: replace with a real type"],
|
|
108
|
+
);
|
|
109
|
+
const p = problemsOf([r]);
|
|
110
|
+
assert.equal(p.length, 1, p.join("\n"));
|
|
111
|
+
assert.match(
|
|
112
|
+
p[0] ?? "",
|
|
113
|
+
/src\/build\.ts:4: boundaries\/dependencies is silenced with "temporary"/,
|
|
114
|
+
);
|
|
115
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"issue": "https://github.com/zernie/research-paper-pipeline/issues/76",
|
|
3
|
+
"why": "Legacy src/*.ts files that still do I/O or import an adapter or a tool package directly. May only shrink: fix a site, delete its directive, lower the count here (delete the file entry at zero). A new file may not appear. Counted from ESLint suppressedMessages by scripts/layer-legacy-frozen.mjs, part of npm run check.",
|
|
4
|
+
"files": {
|
|
5
|
+
"src/build-engine.ts": {
|
|
6
|
+
"boundaries/dependencies": 2,
|
|
7
|
+
"no-restricted-globals": 2
|
|
8
|
+
},
|
|
9
|
+
"src/build.ts": {
|
|
10
|
+
"boundaries/dependencies": 5,
|
|
11
|
+
"no-restricted-globals": 2
|
|
12
|
+
},
|
|
13
|
+
"src/doctor.ts": {
|
|
14
|
+
"boundaries/dependencies": 2,
|
|
15
|
+
"no-restricted-globals": 1
|
|
16
|
+
},
|
|
17
|
+
"src/engine.ts": {
|
|
18
|
+
"boundaries/dependencies": 2,
|
|
19
|
+
"no-restricted-globals": 1
|
|
20
|
+
},
|
|
21
|
+
"src/hooks-settings.ts": {
|
|
22
|
+
"boundaries/dependencies": 1
|
|
23
|
+
},
|
|
24
|
+
"src/init.ts": {
|
|
25
|
+
"boundaries/dependencies": 4,
|
|
26
|
+
"no-restricted-globals": 6
|
|
27
|
+
},
|
|
28
|
+
"src/link-skills.ts": {
|
|
29
|
+
"boundaries/dependencies": 1
|
|
30
|
+
},
|
|
31
|
+
"src/new-paper.ts": {
|
|
32
|
+
"boundaries/dependencies": 1
|
|
33
|
+
},
|
|
34
|
+
"src/pdf-facts.ts": {
|
|
35
|
+
"boundaries/dependencies": 3,
|
|
36
|
+
"no-restricted-globals": 1
|
|
37
|
+
},
|
|
38
|
+
"src/structure.ts": {
|
|
39
|
+
"boundaries/dependencies": 1,
|
|
40
|
+
"no-restricted-globals": 1
|
|
41
|
+
},
|
|
42
|
+
"src/tex-requirements.ts": {
|
|
43
|
+
"boundaries/dependencies": 2
|
|
44
|
+
},
|
|
45
|
+
"src/toolchain.ts": {
|
|
46
|
+
"boundaries/dependencies": 3,
|
|
47
|
+
"no-restricted-globals": 2
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|