paperlint 3.1.3 → 4.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/workflows/ci.yml +12 -7
- package/CLAUDE.md +5 -5
- package/CONTRIBUTING.md +34 -5
- package/dist/adapters/banal/failure.d.ts +1 -7
- package/dist/adapters/banal/failure.d.ts.map +1 -1
- package/dist/adapters/banal/failure.js +5 -7
- package/dist/adapters/banal/failure.js.map +1 -1
- package/dist/adapters/banal/index.d.ts.map +1 -1
- package/dist/adapters/banal/index.js +4 -3
- package/dist/adapters/banal/index.js.map +1 -1
- package/dist/adapters/banal/install.d.ts.map +1 -1
- package/dist/adapters/banal/install.js +4 -3
- package/dist/adapters/banal/install.js.map +1 -1
- package/dist/adapters/banal/invocation.d.ts +10 -5
- package/dist/adapters/banal/invocation.d.ts.map +1 -1
- package/dist/adapters/banal/invocation.js +13 -1
- package/dist/adapters/banal/invocation.js.map +1 -1
- package/dist/adapters/banal/locate.d.ts +12 -9
- package/dist/adapters/banal/locate.d.ts.map +1 -1
- package/dist/adapters/banal/locate.js +19 -12
- package/dist/adapters/banal/locate.js.map +1 -1
- package/dist/adapters/banal/run.d.ts +10 -1
- package/dist/adapters/banal/run.d.ts.map +1 -1
- package/dist/adapters/banal/run.js +8 -4
- package/dist/adapters/banal/run.js.map +1 -1
- package/dist/adapters/banal/settings.d.ts +1 -1
- package/dist/adapters/banal/settings.d.ts.map +1 -1
- package/dist/adapters/banal/settings.js +2 -1
- package/dist/adapters/banal/settings.js.map +1 -1
- package/dist/adapters/memory/index.d.ts.map +1 -1
- package/dist/adapters/memory/index.js +8 -2
- package/dist/adapters/memory/index.js.map +1 -1
- package/dist/adapters/node/files.io.d.ts.map +1 -1
- package/dist/adapters/node/files.io.js +2 -1
- package/dist/adapters/node/files.io.js.map +1 -1
- package/dist/adapters/node/process.io.d.ts +5 -7
- package/dist/adapters/node/process.io.d.ts.map +1 -1
- package/dist/adapters/node/process.io.js +4 -3
- package/dist/adapters/node/process.io.js.map +1 -1
- package/dist/adapters/node/workspace.io.d.ts.map +1 -1
- package/dist/adapters/node/workspace.io.js +4 -2
- package/dist/adapters/node/workspace.io.js.map +1 -1
- package/dist/adapters/pdfjs/fill.d.ts.map +1 -1
- package/dist/adapters/pdfjs/fill.js +13 -7
- package/dist/adapters/pdfjs/fill.js.map +1 -1
- package/dist/adapters/references/index.d.ts.map +1 -1
- package/dist/adapters/references/index.js +8 -7
- package/dist/adapters/references/index.js.map +1 -1
- package/dist/adapters/references/pool.d.ts.map +1 -1
- package/dist/adapters/references/pool.js +4 -5
- package/dist/adapters/references/pool.js.map +1 -1
- package/dist/adapters/references/reach.io.d.ts.map +1 -1
- package/dist/adapters/references/reach.io.js +2 -1
- package/dist/adapters/references/reach.io.js.map +1 -1
- package/dist/build-engine.d.ts +1 -1
- package/dist/build-engine.d.ts.map +1 -1
- package/dist/build-engine.js +10 -3
- package/dist/build-engine.js.map +1 -1
- package/dist/build.d.ts +2 -3
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +19 -17
- package/dist/build.js.map +1 -1
- package/dist/caller-path.d.ts +3 -0
- package/dist/caller-path.d.ts.map +1 -0
- package/dist/caller-path.js +13 -0
- package/dist/caller-path.js.map +1 -0
- package/dist/cli.d.ts +10 -17
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +93 -46
- package/dist/cli.js.map +1 -1
- package/dist/doctor.d.ts +12 -3
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +5 -3
- package/dist/doctor.js.map +1 -1
- package/dist/domain/lookup-cache.d.ts.map +1 -1
- package/dist/domain/lookup-cache.js +10 -8
- package/dist/domain/lookup-cache.js.map +1 -1
- package/dist/domain/paths.d.ts +8 -2
- package/dist/domain/paths.d.ts.map +1 -1
- package/dist/domain/paths.js +12 -1
- package/dist/domain/paths.js.map +1 -1
- package/dist/domain/ready.d.ts +24 -0
- package/dist/domain/ready.d.ts.map +1 -0
- package/dist/domain/ready.js +11 -0
- package/dist/domain/ready.js.map +1 -0
- package/dist/domain/record.d.ts +8 -0
- package/dist/domain/record.d.ts.map +1 -0
- package/dist/domain/record.js +8 -0
- package/dist/domain/record.js.map +1 -0
- package/dist/domain/sha256.d.ts.map +1 -1
- package/dist/domain/sha256.js +4 -2
- package/dist/domain/sha256.js.map +1 -1
- package/dist/domain/text.d.ts +12 -0
- package/dist/domain/text.d.ts.map +1 -1
- package/dist/domain/text.js +17 -0
- package/dist/domain/text.js.map +1 -1
- package/dist/engine.d.ts +23 -22
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +4 -3
- package/dist/engine.js.map +1 -1
- package/dist/eslint-rules/bib-reachable-entry.d.ts +22 -0
- package/dist/eslint-rules/bib-reachable-entry.d.ts.map +1 -0
- package/dist/eslint-rules/bib-reachable-entry.js +75 -0
- package/dist/eslint-rules/bib-reachable-entry.js.map +1 -0
- package/dist/eslint-rules/install-path-literals.d.ts +80 -0
- package/dist/eslint-rules/install-path-literals.d.ts.map +1 -0
- package/dist/eslint-rules/install-path-literals.js +105 -0
- package/dist/eslint-rules/install-path-literals.js.map +1 -0
- package/dist/eslint-rules/latex-language.d.ts +136 -0
- package/dist/eslint-rules/latex-language.d.ts.map +1 -0
- package/dist/eslint-rules/latex-language.js +639 -0
- package/dist/eslint-rules/latex-language.js.map +1 -0
- package/dist/eslint-rules/paper-research-question.d.ts +31 -0
- package/dist/eslint-rules/paper-research-question.d.ts.map +1 -0
- package/dist/eslint-rules/paper-research-question.js +188 -0
- package/dist/eslint-rules/paper-research-question.js.map +1 -0
- package/dist/eslint-rules/paper-stages.d.ts +83 -0
- package/dist/eslint-rules/paper-stages.d.ts.map +1 -0
- package/dist/eslint-rules/paper-stages.js +358 -0
- package/dist/eslint-rules/paper-stages.js.map +1 -0
- package/dist/eslint-rules/paper-typography.d.ts +74 -0
- package/dist/eslint-rules/paper-typography.d.ts.map +1 -0
- package/dist/eslint-rules/paper-typography.js +404 -0
- package/dist/eslint-rules/paper-typography.js.map +1 -0
- package/dist/eslint-rules/papers.d.ts +42 -0
- package/dist/eslint-rules/papers.d.ts.map +1 -0
- package/dist/eslint-rules/papers.js +145 -0
- package/dist/eslint-rules/papers.js.map +1 -0
- package/dist/eslint-rules/pdf-last-page-balance.d.ts +72 -0
- package/dist/eslint-rules/pdf-last-page-balance.d.ts.map +1 -0
- package/dist/eslint-rules/pdf-last-page-balance.js +237 -0
- package/dist/eslint-rules/pdf-last-page-balance.js.map +1 -0
- package/dist/eslint-rules/review-frontmatter.d.ts +57 -0
- package/dist/eslint-rules/review-frontmatter.d.ts.map +1 -0
- package/dist/eslint-rules/review-frontmatter.js +126 -0
- package/dist/eslint-rules/review-frontmatter.js.map +1 -0
- package/dist/eslint-rules/review-frontmatter.schema.json +36 -0
- package/dist/eslint-rules/rule-context.d.ts +55 -0
- package/dist/eslint-rules/rule-context.d.ts.map +1 -0
- package/dist/eslint-rules/rule-context.js +9 -0
- package/dist/eslint-rules/rule-context.js.map +1 -0
- package/dist/eslint-rules/sibling-frontmatter.d.ts +25 -0
- package/dist/eslint-rules/sibling-frontmatter.d.ts.map +1 -0
- package/dist/eslint-rules/sibling-frontmatter.js +16 -0
- package/dist/eslint-rules/sibling-frontmatter.js.map +1 -0
- package/dist/eslint-rules/sibling-frontmatter.schema.json +14 -0
- package/dist/eslint-rules/temp-root-realpath.d.ts +71 -0
- package/dist/eslint-rules/temp-root-realpath.d.ts.map +1 -0
- package/dist/eslint-rules/temp-root-realpath.js +139 -0
- package/dist/eslint-rules/temp-root-realpath.js.map +1 -0
- package/dist/eslint-rules/tex-build.d.ts +35 -0
- package/dist/eslint-rules/tex-build.d.ts.map +1 -0
- package/dist/eslint-rules/tex-build.js +313 -0
- package/dist/eslint-rules/tex-build.js.map +1 -0
- package/dist/facts-file.d.ts.map +1 -1
- package/dist/facts-file.js +31 -27
- package/dist/facts-file.js.map +1 -1
- package/dist/hooks-settings.d.ts +1 -1
- package/dist/hooks-settings.d.ts.map +1 -1
- package/dist/hooks-settings.js +31 -11
- package/dist/hooks-settings.js.map +1 -1
- package/dist/init.d.ts +8 -9
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +33 -15
- package/dist/init.js.map +1 -1
- package/dist/latex-loop.d.ts +2 -2
- package/dist/latex-loop.d.ts.map +1 -1
- package/dist/latex-loop.js +2 -2
- package/dist/latex-loop.js.map +1 -1
- package/dist/lib/agent-cli-version.d.ts +65 -0
- package/dist/lib/agent-cli-version.d.ts.map +1 -0
- package/dist/lib/agent-cli-version.js +77 -0
- package/dist/lib/agent-cli-version.js.map +1 -0
- package/dist/lib/check.d.ts +19 -0
- package/dist/lib/check.d.ts.map +1 -0
- package/dist/lib/check.js +52 -0
- package/dist/lib/check.js.map +1 -0
- package/dist/lib/markdown.d.ts +180 -0
- package/dist/lib/markdown.d.ts.map +1 -0
- package/dist/lib/markdown.js +302 -0
- package/dist/lib/markdown.js.map +1 -0
- package/dist/lib/paper-config.d.ts +84 -0
- package/dist/lib/paper-config.d.ts.map +1 -0
- package/dist/lib/paper-config.js +138 -0
- package/dist/lib/paper-config.js.map +1 -0
- package/dist/lib/skill-eval-fixture.d.ts +29 -0
- package/dist/lib/skill-eval-fixture.d.ts.map +1 -0
- package/dist/lib/skill-eval-fixture.js +62 -0
- package/dist/lib/skill-eval-fixture.js.map +1 -0
- package/dist/link-skills.d.ts.map +1 -1
- package/dist/link-skills.js +5 -4
- package/dist/link-skills.js.map +1 -1
- package/dist/new-paper.d.ts.map +1 -1
- package/dist/new-paper.js +7 -3
- package/dist/new-paper.js.map +1 -1
- package/dist/paper-files.d.ts +4 -4
- package/dist/paper-files.d.ts.map +1 -1
- package/dist/paper-files.js +6 -6
- package/dist/paper-files.js.map +1 -1
- package/dist/paper-settings.d.ts.map +1 -1
- package/dist/paper-settings.js +8 -7
- package/dist/paper-settings.js.map +1 -1
- package/dist/pdf-facts.d.ts +51 -1
- package/dist/pdf-facts.d.ts.map +1 -1
- package/dist/pdf-facts.js +25 -16
- package/dist/pdf-facts.js.map +1 -1
- package/dist/pdf-geometry.d.ts.map +1 -1
- package/dist/pdf-geometry.js +3 -4
- package/dist/pdf-geometry.js.map +1 -1
- package/dist/ports/tool-installer.d.ts +2 -14
- package/dist/ports/tool-installer.d.ts.map +1 -1
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +19 -6
- package/dist/presets.js.map +1 -1
- package/dist/references.d.ts.map +1 -1
- package/dist/references.js +15 -10
- package/dist/references.js.map +1 -1
- package/dist/rules-config.d.ts +26 -1
- package/dist/rules-config.d.ts.map +1 -1
- package/dist/rules-config.js +15 -12
- package/dist/rules-config.js.map +1 -1
- package/dist/structure.js +1 -1
- package/dist/structure.js.map +1 -1
- package/dist/tex-requirements.d.ts +4 -0
- package/dist/tex-requirements.d.ts.map +1 -1
- package/dist/tex-requirements.js +22 -5
- package/dist/tex-requirements.js.map +1 -1
- package/dist/toolchain.d.ts.map +1 -1
- package/dist/toolchain.js +21 -16
- package/dist/toolchain.js.map +1 -1
- package/dist/types.d.ts +5 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/venue-rules.d.ts.map +1 -1
- package/dist/venue-rules.js +21 -8
- package/dist/venue-rules.js.map +1 -1
- package/docs/configuration.md +2 -2
- package/docs/e2e.md +7 -7
- package/docs/install.md +1 -1
- package/docs/prior-art/README.md +1 -1
- package/docs/prior-art/package-location.md +5 -5
- package/docs/prior-art/repro/README.md +1 -1
- package/docs/prior-art/test-tooling.md +2 -2
- package/docs/testing.md +11 -8
- package/docs/toolchain.md +1 -1
- package/eslint-rules/{bib-reachable-entry.mjs → bib-reachable-entry.ts} +5 -4
- package/eslint-rules/install-path-literals.harness.mjs +1 -1
- package/eslint-rules/{install-path-literals.mjs → install-path-literals.ts} +18 -10
- package/eslint-rules/latex-language.harness.mjs +2 -2
- package/eslint-rules/latex-language.test.mjs +7 -1
- package/eslint-rules/{latex-language.mjs → latex-language.ts} +297 -109
- package/eslint-rules/paper-research-question.harness.mjs +3 -3
- package/eslint-rules/{paper-research-question.mjs → paper-research-question.ts} +35 -16
- package/eslint-rules/paper-stages.harness.mjs +2 -2
- package/eslint-rules/paper-stages.test.mjs +8 -2
- package/eslint-rules/{paper-stages.mjs → paper-stages.ts} +76 -31
- package/eslint-rules/paper-typography.test.mjs +3 -3
- package/eslint-rules/{paper-typography.mjs → paper-typography.ts} +134 -56
- package/eslint-rules/papers.harness.mjs +2 -2
- package/eslint-rules/{papers.mjs → papers.ts} +7 -4
- package/eslint-rules/pdf-last-page-balance.harness.mjs +3 -3
- package/eslint-rules/{pdf-last-page-balance.mjs → pdf-last-page-balance.ts} +89 -32
- package/eslint-rules/review-frontmatter.test.mjs +2 -2
- package/eslint-rules/{review-frontmatter.mjs → review-frontmatter.ts} +38 -16
- package/eslint-rules/rule-context.ts +62 -0
- package/eslint-rules/{sibling-frontmatter.mjs → sibling-frontmatter.ts} +1 -1
- package/eslint-rules/temp-root-realpath.harness.mjs +1 -1
- package/eslint-rules/{temp-root-realpath.mjs → temp-root-realpath.ts} +20 -7
- package/eslint-rules/tex-build.harness.mjs +2 -2
- package/eslint-rules/{tex-build.mjs → tex-build.ts} +6 -5
- package/eslint.config.mjs +146 -30
- package/fixtures/install-path-literals/clean.fixture.mjs +1 -1
- package/fixtures/install-path-literals/clean.md +2 -2
- package/fixtures/install-path-literals/defect.fixture.mjs +1 -1
- package/fixtures/install-path-literals/defect.md +2 -2
- package/fixtures/pdf-facts/README.md +2 -2
- package/fixtures/real-markdown-paper/{baseline.mjs → baseline.ts} +31 -10
- package/hooks/{hooks.harness.mjs → hooks.harness.ts} +51 -34
- package/hooks/paper-edit-guard.hook.mjs +1 -1
- package/hooks/{paper-edit-guard.test.mjs → paper-edit-guard.test.ts} +3 -7
- package/hooks/paper-skills-nudge.hook.mjs +1 -1
- package/hooks/{paper-skills-nudge.test.mjs → paper-skills-nudge.test.ts} +2 -6
- package/hooks/paper-status-gates.sh +9 -19
- package/hooks/{paper-status-gates.test.mjs → paper-status-gates.test.ts} +2 -6
- package/lib/agent-cli-version.harness.mjs +1 -1
- package/lib/{agent-cli-version.mjs → agent-cli-version.ts} +32 -18
- package/lib/check.test.ts +14 -9
- package/lib/{check.mjs → check.ts} +22 -9
- package/lib/markdown.test.mjs +7 -7
- package/lib/{markdown.mjs → markdown.ts} +68 -29
- package/lib/paper-config.harness.mjs +9 -9
- package/lib/{paper-config.mjs → paper-config.ts} +20 -19
- package/lib/skill-checks.mjs +24 -381
- package/lib/skill-checks.test.mjs +64 -116
- package/lib/skill-corpus.mjs +10 -251
- package/lib/skill-corpus.test.mjs +2 -13
- package/lib/skill-eval-kit.mjs +1 -1
- package/lib/skill-trigger-cases.mjs +1 -1
- package/package.json +42 -10
- package/scripts/{check.harness.mjs → check.harness.ts} +111 -10
- package/scripts/{check.test.mjs → check.test.ts} +13 -10
- package/scripts/{check.mjs → check.ts} +116 -42
- package/scripts/coverage-config.test.ts +80 -38
- package/scripts/eslint-report-guard.test.mjs +1 -1
- package/scripts/harness-api.frozen.json +14 -16
- package/scripts/harness-api.test.ts +8 -5
- package/scripts/layer-legacy-frozen.test.ts +17 -13
- package/scripts/{layer-legacy-frozen.mjs → layer-legacy-frozen.ts} +128 -39
- package/scripts/release-config.test.ts +12 -4
- package/scripts/rules-see-files.test.mjs +1 -1
- package/scripts/test.test.ts +78 -0
- package/scripts/test.ts +87 -0
- package/skills/analyze-sibling-paper/SKILL.md +1 -39
- package/skills/analyze-sibling-paper/SKILL.md.spec.ts +0 -38
- package/skills/argument-arc/SKILL.md +2 -36
- package/skills/argument-arc/SKILL.md.spec.ts +1 -43
- package/skills/build-benchmark/SKILL.md +1 -41
- package/skills/build-benchmark/SKILL.md.spec.ts +0 -40
- package/skills/camera-ready/SKILL.md +1 -34
- package/skills/camera-ready/SKILL.md.spec.ts +0 -33
- package/skills/cold-read-diff/SKILL.md +1 -35
- package/skills/cold-read-diff/SKILL.md.spec.ts +0 -34
- package/skills/draft-paper/SKILL.md +2 -41
- package/skills/draft-paper/SKILL.md.spec.ts +1 -50
- package/skills/extend-paper/SKILL.md +2 -33
- package/skills/extend-paper/SKILL.md.spec.ts +1 -42
- package/skills/find-venue/SKILL.md +2 -38
- package/skills/find-venue/SKILL.md.spec.ts +1 -47
- package/skills/grade-paper-writing/SKILL.md +3 -38
- package/skills/grade-paper-writing/SKILL.md.spec.ts +2 -47
- package/skills/grade-paper-writing/prose-lint.mjs +3 -4
- package/skills/grade-paper-writing/{prose-lint.test.mjs → prose-lint.test.ts} +3 -3
- package/skills/harden-paper/SKILL.md +1 -39
- package/skills/harden-paper/SKILL.md.spec.ts +0 -38
- package/skills/map-prior-work/SKILL.md +1 -35
- package/skills/map-prior-work/SKILL.md.spec.ts +0 -34
- package/skills/osf-artifact-upload/{osf-artifact-upload.harness.mjs → osf-artifact-upload.harness.ts} +3 -4
- package/skills/paper-adversarial-review/SKILL.md +2 -35
- package/skills/paper-adversarial-review/SKILL.md.spec.ts +1 -43
- package/skills/paper-pipeline/SKILL.md +2 -28
- package/skills/paper-pipeline/SKILL.md.spec.ts +1 -27
- package/skills/paper-pipeline/description-language.eval.mjs +1 -1
- package/skills/paper-pipeline/framing-vs-vocabulary.eval.mjs +1 -1
- package/skills/paper-pipeline/grade-paper-writing-ablation.eval.mjs +2 -2
- package/skills/paper-pipeline/paper-pipeline.harness.mjs +25 -40
- package/skills/paper-pipeline/pipeline-firing.eval.mjs +1 -1
- package/skills/paper-pipeline/pipeline-language.eval.mjs +1 -1
- package/skills/paper-pipeline/references/acceptance-gate.md +1 -6
- package/skills/paper-pipeline/references/pipeline-status-template.md +8 -35
- package/skills/paper-pipeline/scripts/README.md +30 -225
- package/skills/paper-pipeline/scripts/artifact-coverage.harness.mjs +4 -8
- package/skills/paper-pipeline/scripts/artifact-coverage.mjs +1 -1
- package/skills/paper-pipeline/scripts/{artifact-coverage.test.mjs → artifact-coverage.test.ts} +2 -2
- package/skills/paper-pipeline/scripts/consumer.harness.mjs +6 -104
- package/skills/paper-pipeline/scripts/consumer.mjs +24 -109
- package/skills/paper-pipeline/scripts/consumer.test.mjs +1 -1
- package/skills/paper-pipeline/scripts/extract-ref-facts.harness.mjs +1 -1
- package/skills/paper-pipeline/scripts/extract-ref-facts.mjs +1 -4
- package/skills/paper-pipeline/scripts/extract-ref-facts.test.mjs +1 -1
- package/skills/paper-pipeline/scripts/generated-code.harness.mjs +2 -3
- package/skills/paper-pipeline/scripts/{generated-code.test.mjs → generated-code.test.ts} +3 -3
- package/skills/paper-pipeline/scripts/population-map.harness.mjs +3 -3
- package/skills/paper-pipeline/scripts/population-map.mjs +1 -4
- package/skills/paper-pipeline/scripts/population-map.test.mjs +1 -1
- package/skills/paper-pipeline/scripts/{round-diff.harness.mjs → round-diff.harness.ts} +45 -18
- package/skills/paper-pipeline/scripts/round-diff.mjs +1 -1
- package/skills/paper-pipeline/scripts/round-diff.test.mjs +1 -1
- package/skills/paper-status/SKILL.md +2 -42
- package/skills/paper-status/SKILL.md.spec.ts +1 -41
- package/skills/pc-panel-review/SKILL.md +2 -46
- package/skills/pc-panel-review/SKILL.md.spec.ts +1 -45
- package/skills/plan-paper-timeline/SKILL.md +2 -36
- package/skills/plan-paper-timeline/SKILL.md.spec.ts +0 -36
- package/skills/plan-paper-timeline/fixtures/{fake-google-calendar.mjs → fake-google-calendar.ts} +101 -70
- package/skills/plan-paper-timeline/plan-paper-timeline.effects.harness.mjs +3 -3
- package/skills/render-paper/SKILL.md +1 -37
- package/skills/render-paper/SKILL.md.spec.ts +0 -36
- package/skills/render-paper/{extract-pdf-facts.harness.mjs → extract-pdf-facts.harness.ts} +34 -9
- package/skills/render-paper/render-paper.harness.mjs +2 -2
- package/skills/research-ideate/SKILL.md +2 -39
- package/skills/research-ideate/SKILL.md.spec.ts +1 -47
- package/skills/study-accepted-papers/SKILL.md +1 -34
- package/skills/study-accepted-papers/SKILL.md.spec.ts +0 -33
- package/skills/submit-paper/SKILL.md +1 -33
- package/skills/submit-paper/SKILL.md.spec.ts +0 -32
- package/skills/sweep-design-space/SKILL.md +1 -38
- package/skills/sweep-design-space/SKILL.md.spec.ts +0 -37
- package/skills/tighten-paper/SKILL.md +2 -39
- package/skills/tighten-paper/SKILL.md.spec.ts +1 -47
- package/skills/tighten-paper/structure.mjs +5 -12
- package/skills/tighten-paper/{structure.test.mjs → structure.test.ts} +4 -3
- package/skills/verify-citations/SKILL.md +2 -38
- package/skills/verify-citations/SKILL.md.spec.ts +1 -37
- package/skills/verify-citations/scripts/{bib-authors.cli.test.mjs → bib-authors.cli.test.ts} +14 -4
- package/skills/verify-citations/scripts/bib-authors.d.mts +63 -0
- package/skills/verify-citations/scripts/bib-authors.mjs +1 -4
- package/skills/verify-citations/scripts/{verify-cites.cli.test.mjs → verify-cites.cli.test.ts} +32 -9
- package/skills/verify-citations/scripts/verify-cites.d.mts +58 -0
- package/src/CLAUDE.md +1 -1
- package/src/adapters/banal/failure.ts +9 -10
- package/src/adapters/banal/index.test.ts +5 -8
- package/src/adapters/banal/index.ts +8 -7
- package/src/adapters/banal/install.ts +9 -4
- package/src/adapters/banal/invocation.test.ts +23 -9
- package/src/adapters/banal/invocation.ts +24 -9
- package/src/adapters/banal/locate.test.ts +2 -2
- package/src/adapters/banal/locate.ts +27 -21
- package/src/adapters/banal/output.test.ts +1 -1
- package/src/adapters/banal/run.test.ts +5 -5
- package/src/adapters/banal/run.ts +16 -10
- package/src/adapters/banal/settings.ts +2 -2
- package/src/adapters/banal/xml.test.ts +1 -1
- package/src/adapters/curl/download.test.ts +8 -6
- package/src/adapters/memory/index.ts +4 -3
- package/src/adapters/node/files.io.ts +2 -2
- package/src/adapters/node/files.test.ts +8 -4
- package/src/adapters/node/process.io.ts +13 -5
- package/src/adapters/node/process.test.ts +5 -5
- package/src/adapters/node/workspace.io.ts +9 -4
- package/src/adapters/node/workspace.test.ts +3 -1
- package/src/adapters/pdfjs/fill.test.ts +2 -2
- package/src/adapters/pdfjs/fill.ts +14 -7
- package/src/adapters/references/index.test.ts +31 -38
- package/src/adapters/references/index.ts +33 -60
- package/src/adapters/references/pool.ts +3 -5
- package/src/adapters/references/reach.io.ts +2 -1
- package/src/build-engine.harness.mjs +1 -1
- package/src/build-engine.test.ts +13 -8
- package/src/build-engine.ts +12 -7
- package/src/build.harness.mjs +2 -2
- package/src/build.test.ts +24 -24
- package/src/build.ts +34 -26
- package/src/caller-path.ts +13 -0
- package/src/cli.harness.mjs +6 -8
- package/src/cli.test.ts +31 -13
- package/src/cli.ts +117 -58
- package/src/doctor.harness.mjs +3 -3
- package/src/doctor.test.ts +1 -1
- package/src/doctor.ts +17 -7
- package/src/domain/lookup-cache.ts +21 -11
- package/src/domain/paths.test.ts +15 -0
- package/src/domain/paths.ts +20 -1
- package/src/domain/ready.ts +31 -0
- package/src/domain/record.test.ts +20 -0
- package/src/domain/record.ts +12 -0
- package/src/domain/result.test.ts +2 -2
- package/src/domain/sha256.ts +5 -3
- package/src/domain/text.test.ts +32 -0
- package/src/domain/text.ts +23 -0
- package/src/engine.harness.mjs +2 -2
- package/src/engine.ts +34 -5
- package/src/facts-file.test.ts +9 -7
- package/src/facts-file.ts +45 -29
- package/src/{hooks-settings.harness.mjs → hooks-settings.harness.ts} +56 -20
- package/src/hooks-settings.ts +48 -13
- package/src/init.test.ts +37 -14
- package/src/init.ts +48 -24
- package/src/{latex-log.harness.mjs → latex-log.harness.ts} +14 -14
- package/src/{latex-loop.harness.mjs → latex-loop.harness.ts} +64 -36
- package/src/latex-loop.ts +3 -3
- package/src/{link-skills.harness.mjs → link-skills.harness.ts} +19 -19
- package/src/link-skills.test.ts +3 -3
- package/src/link-skills.ts +5 -4
- package/src/lint-fix.test.ts +4 -6
- package/src/linted-set.test.ts +2 -2
- package/src/new-paper.harness.mjs +9 -25
- package/src/new-paper.test.ts +8 -10
- package/src/new-paper.ts +9 -5
- package/src/paper-files.test.ts +25 -24
- package/src/paper-files.ts +16 -27
- package/src/paper-settings-commands.test.ts +5 -4
- package/src/paper-settings.test.ts +7 -7
- package/src/paper-settings.ts +13 -14
- package/src/{pdf-facts.harness.mjs → pdf-facts.harness.ts} +9 -8
- package/src/pdf-facts.test.ts +25 -15
- package/src/pdf-facts.ts +81 -23
- package/src/{pdf-geometry.harness.mjs → pdf-geometry.harness.ts} +19 -12
- package/src/pdf-geometry.ts +8 -4
- package/src/ports/tool-installer.ts +2 -17
- package/src/presets.ts +31 -16
- package/src/references.test.ts +76 -62
- package/src/references.ts +18 -12
- package/src/{rules-config.harness.mjs → rules-config.harness.ts} +7 -13
- package/src/rules-config.ts +46 -14
- package/src/rules-off.test.ts +6 -4
- package/src/{structure.harness.mjs → structure.harness.ts} +26 -15
- package/src/structure.ts +1 -1
- package/src/{tex-requirements.harness.mjs → tex-requirements.harness.ts} +50 -22
- package/src/tex-requirements.test.ts +21 -0
- package/src/tex-requirements.ts +37 -11
- package/src/toolchain.harness.mjs +2 -2
- package/src/toolchain.test.ts +10 -6
- package/src/toolchain.ts +31 -17
- package/src/types.ts +5 -3
- package/src/venue-rules.test.ts +70 -68
- package/src/venue-rules.ts +22 -12
- package/tsconfig.json +6 -3
- package/tsconfig.pkg.json +10 -0
- package/lib/check.d.mts +0 -17
- package/lib/paper-config.d.mts +0 -31
- package/scripts/layer-legacy-frozen.d.mts +0 -36
- package/scripts/rules-are-content-only.harness.mjs +0 -105
- package/scripts/rules-are-content-only.mjs +0 -148
- package/scripts/rules-are-content-only.test.mjs +0 -61
- package/scripts/test.mjs +0 -44
- package/scripts/test.test.mjs +0 -52
- package/skills/paper-pipeline/scripts/announce.mjs +0 -67
- package/skills/paper-pipeline/scripts/announce.test.mjs +0 -102
- package/skills/paper-pipeline/scripts/fixtures/clean/PIPELINE-STATUS.md +0 -51
- package/skills/paper-pipeline/scripts/fixtures/dirty/PIPELINE-STATUS.md +0 -52
- package/skills/paper-pipeline/scripts/fixtures/dirty/paper.md +0 -6
- package/skills/paper-pipeline/scripts/fixtures/scorecard.mjs +0 -71
- package/skills/paper-pipeline/scripts/ledger.cli.test.mjs +0 -302
- package/skills/paper-pipeline/scripts/ledger.mjs +0 -623
- package/skills/paper-pipeline/scripts/ledger.test.mjs +0 -254
- package/skills/paper-pipeline/scripts/pipeline-check.cli.test.mjs +0 -474
- package/skills/paper-pipeline/scripts/pipeline-check.harness.mjs +0 -328
- package/skills/paper-pipeline/scripts/pipeline-check.mjs +0 -753
- package/skills/paper-pipeline/scripts/pipeline-edges.mjs +0 -169
- package/skills/paper-pipeline/scripts/pipeline-edges.test.mjs +0 -73
- package/skills/paper-pipeline/scripts/run-mechanical.mjs +0 -648
- package/skills/paper-pipeline/scripts/run-mechanical.test.mjs +0 -468
- package/skills/paper-pipeline/scripts/status.mjs +0 -295
- package/skills/paper-pipeline/scripts/status.test.mjs +0 -232
- /package/bin/{paperlint.test.mjs → paperlint.test.ts} +0 -0
- /package/lib/{skill-eval-fixture.mjs → skill-eval-fixture.ts} +0 -0
- /package/skills/grade-paper-writing/__snapshots__/{prose-lint.test.mjs.snap → prose-lint.test.ts.snap} +0 -0
- /package/skills/tighten-paper/__snapshots__/{structure.test.mjs.snap → structure.test.ts.snap} +0 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
let md = null;
|
|
2
|
+
try {
|
|
3
|
+
const { default: MarkdownIt } = await import("markdown-it");
|
|
4
|
+
md = new MarkdownIt();
|
|
5
|
+
}
|
|
6
|
+
catch {
|
|
7
|
+
md = null;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Whether the parser resolved. A linter must check this ITSELF and say out loud that
|
|
11
|
+
* its heading checks are off: with no parser `headings()` returns an empty list, and
|
|
12
|
+
* silent emptiness reads as "the document has no headings", that is, as a clean
|
|
13
|
+
* document. The nudge lives in the linters, because by contract (see the header) this
|
|
14
|
+
* file has no right to produce a single finding.
|
|
15
|
+
*/
|
|
16
|
+
export const MD_AVAILABLE = () => md !== null;
|
|
17
|
+
/** markdown-it's block tokens for `text`, or null when it did not resolve. A test passes its own. */
|
|
18
|
+
const defaultParse = () => {
|
|
19
|
+
const parser = md;
|
|
20
|
+
return parser === null ? null : (text) => parser.parse(text, {});
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* The frontmatter is BLANKED with spaces, not cut out: the offsets must stay the
|
|
24
|
+
* same, because the checks cut the document by offset. Blanking is necessary — inside
|
|
25
|
+
* a YAML block scalar a line indented by two spaces (` ## Foo`) is a real ATX
|
|
26
|
+
* heading to CommonMark, and without blanking the frontmatter starts supplying
|
|
27
|
+
* sections.
|
|
28
|
+
*/
|
|
29
|
+
const FRONTMATTER_RE = /^---[ \t]*\r?\n[\s\S]*?\r?\n---[ \t]*(?=\r?\n|$)/;
|
|
30
|
+
export function blankFrontmatter(text) {
|
|
31
|
+
const m = FRONTMATTER_RE.exec(text);
|
|
32
|
+
return m ? m[0].replace(/[^\n]/g, " ") + text.slice(m[0].length) : text;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The frontmatter body (between the fences), or `null` — if the file opens without one.
|
|
36
|
+
*
|
|
37
|
+
* Added 2026-08-20, when eight places in `.claude/**` cut the frontmatter with eight
|
|
38
|
+
* slightly different regexes: some knew about `\r\n`, some did not; some required a
|
|
39
|
+
* newline after the closing fence, some did not. The difference between them is not
|
|
40
|
+
* style, it is a different answer on one and the same file.
|
|
41
|
+
*
|
|
42
|
+
* ⚠️ This is NOT a parser and does not claim to be: `---` frontmatter is not markdown,
|
|
43
|
+
* no markdown parser models it (the analysis is in the root `CLAUDE.md`, "Considered
|
|
44
|
+
* and rejected: gray-matter"). The value here is one fence instead of eight, and the
|
|
45
|
+
* parsing of VALUES is done by `js-yaml` at the caller.
|
|
46
|
+
*/
|
|
47
|
+
export function frontmatterBlock(text) {
|
|
48
|
+
const m = FRONTMATTER_RE.exec(text);
|
|
49
|
+
if (!m)
|
|
50
|
+
return null;
|
|
51
|
+
const inner = m[0]
|
|
52
|
+
.replace(/^---[ \t]*\r?\n/, "")
|
|
53
|
+
.replace(/\r?\n---[ \t]*$/, "");
|
|
54
|
+
return inner;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The document WITHOUT the frontmatter — the block is cut out together with the
|
|
58
|
+
* newline after it.
|
|
59
|
+
*
|
|
60
|
+
* Differs from {@link blankFrontmatter} in that the offsets SHIFT. Both forms are
|
|
61
|
+
* needed and both have been used already: blanking — where character positions are
|
|
62
|
+
* later shown to the user; cutting — where the text is merely counted. Choose by what
|
|
63
|
+
* the caller does, not by taste.
|
|
64
|
+
*/
|
|
65
|
+
export function stripFrontmatter(text) {
|
|
66
|
+
const m = FRONTMATTER_RE.exec(text);
|
|
67
|
+
return m ? text.slice(m[0].length).replace(/^\r?\n/, "") : text;
|
|
68
|
+
}
|
|
69
|
+
/** Line-start offsets — so that `token.map` becomes a position in the source string. */
|
|
70
|
+
function lineStarts(text) {
|
|
71
|
+
const out = [0];
|
|
72
|
+
for (let i = 0; i < text.length; i++)
|
|
73
|
+
if (text[i] === "\n")
|
|
74
|
+
out.push(i + 1);
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* All the document's headings: `[{ depth, text, line, offset }]`, in order of occurrence.
|
|
79
|
+
*
|
|
80
|
+
* `offset` — the index of the start of the heading's line IN THE SAME text that was
|
|
81
|
+
* passed in, in `slice`/`indexOf` units (UTF-16), because those are exactly what the
|
|
82
|
+
* checks cut the document with. `line` — 0-based line number. `text` — without the
|
|
83
|
+
* hashes, trimmed at the edges.
|
|
84
|
+
*
|
|
85
|
+
* ⚠️ ATX ONLY (`## Heading`). Setext (`Heading\n---`) is deliberately NOT counted as a
|
|
86
|
+
* heading: in this knowledge base `---` is a prose separator, and a paragraph it stands
|
|
87
|
+
* under without a blank line would become a level-2 heading per CommonMark. The former
|
|
88
|
+
* regexps knew only ATX, so this preserves the contract rather than narrowing it.
|
|
89
|
+
*/
|
|
90
|
+
export function headings(text, { parse = defaultParse() } = {}) {
|
|
91
|
+
if (parse === null)
|
|
92
|
+
return [];
|
|
93
|
+
const toks = parse(blankFrontmatter(text));
|
|
94
|
+
const starts = lineStarts(text);
|
|
95
|
+
const out = [];
|
|
96
|
+
for (const [i, t] of toks.entries()) {
|
|
97
|
+
if (t.type !== "heading_open" || !t.map)
|
|
98
|
+
continue;
|
|
99
|
+
if (!t.markup || !t.markup.startsWith("#"))
|
|
100
|
+
continue; // setext — see the caveat above
|
|
101
|
+
// markdown-it follows `heading_open` with its `inline` token and maps blocks to lines of the
|
|
102
|
+
// parsed text; the fallbacks are for a token stream that does not (another parser version).
|
|
103
|
+
const inline = toks[i + 1];
|
|
104
|
+
out.push({
|
|
105
|
+
depth: Number(t.tag.slice(1)),
|
|
106
|
+
text: inline?.type === "inline" ? inline.content.trim() : "",
|
|
107
|
+
line: t.map[0],
|
|
108
|
+
offset: starts[t.map[0]] ?? 0,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Slicing the document into chunks "a heading + everything up to the next heading FROM
|
|
115
|
+
* THE SAME RANGE of levels". → `[{ heading, raw, body }]`.
|
|
116
|
+
*
|
|
117
|
+
* This is exactly what four scripts did as `split(/^(?=## )/m)` and
|
|
118
|
+
* `split(/^(?=#{2,3} )/m)`. The shape of the expression lied about the intent: "two or
|
|
119
|
+
* three hashes" is about CHARACTERS, while what is needed is the LEVEL, and `#{2,3}`
|
|
120
|
+
* also caught a hash inside a ```-block, that is, it cut a quotation from someone
|
|
121
|
+
* else's paper as a section of its own.
|
|
122
|
+
*
|
|
123
|
+
* `heading` — `null` on the zeroth element (the preamble before the first heading). It
|
|
124
|
+
* is ALWAYS there, including empty: the former `split` also always returned the chunk
|
|
125
|
+
* before the first separator as its zeroth element, and callers rely on that
|
|
126
|
+
* (`sub === chunk` in `artifact-coverage` meant "there are no subsections").
|
|
127
|
+
*
|
|
128
|
+
* `raw` — WITH the heading line (it is used to count `§` references and bold numbers,
|
|
129
|
+
* which occur in the heading itself too), `body` — without it (it is used to count words).
|
|
130
|
+
*
|
|
131
|
+
* 2026-08-11: moved here rather than copied into every script, because the chunk
|
|
132
|
+
* boundary is the one place where an off-by-one is easy, and such a mistake has already
|
|
133
|
+
* happened (`recordBlock` in `skill-corpus.mjs` returned a single "#" character for all
|
|
134
|
+
* 21 skills).
|
|
135
|
+
*/
|
|
136
|
+
export function splitSections(text, { min = 2, max = 6 } = {}) {
|
|
137
|
+
const hs = headings(text).filter((h) => h.depth >= min && h.depth <= max);
|
|
138
|
+
const out = [];
|
|
139
|
+
const [first] = hs;
|
|
140
|
+
const preEnd = first ? first.offset : text.length;
|
|
141
|
+
out.push({
|
|
142
|
+
heading: null,
|
|
143
|
+
raw: text.slice(0, preEnd),
|
|
144
|
+
body: text.slice(0, preEnd),
|
|
145
|
+
});
|
|
146
|
+
for (const [i, h] of hs.entries()) {
|
|
147
|
+
const next = hs[i + 1];
|
|
148
|
+
const end = next ? next.offset : text.length;
|
|
149
|
+
const nl = text.indexOf("\n", h.offset);
|
|
150
|
+
const bodyStart = nl === -1 || nl + 1 > end ? end : nl + 1;
|
|
151
|
+
out.push({
|
|
152
|
+
heading: h,
|
|
153
|
+
raw: text.slice(h.offset, end),
|
|
154
|
+
body: text.slice(bodyStart, end),
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return out;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* The text without the contents of ```-blocks (the fence lines themselves go too).
|
|
161
|
+
*
|
|
162
|
+
* Through the parser, not `/```[\s\S]*?```/g`: that pattern glues the end of one block
|
|
163
|
+
* to the start of the next when the number of fences is odd, knows nothing about `~~~`
|
|
164
|
+
* fences or indented fences, and silently eats the prose between blocks.
|
|
165
|
+
*
|
|
166
|
+
* `blank: true` — the block's lines are NOT deleted but REPLACED with empty ones. The
|
|
167
|
+
* difference is not cosmetic: deleting the lines GLUES the paragraph before the block to
|
|
168
|
+
* the paragraph after it, and a code block is a block boundary — on the other side a
|
|
169
|
+
* different paragraph starts. Measured 2026-08-11 on `<papers-root>/<paper>/README.md`:
|
|
170
|
+
* `prose-lint` counted 82 sentences there, and after the lines were deleted it counted
|
|
171
|
+
* 81 — the lead paragraph "**Reproduction commands:**" merged with the text AFTER the
|
|
172
|
+
* block into one sentence. That is exactly the failure against which `prose-lint` itself
|
|
173
|
+
* says "Paragraph and heading boundaries END a sentence", and it inflates the
|
|
174
|
+
* claims-per-sentence counter — the threshold at which the file emits findings. The
|
|
175
|
+
* former regex preserved the boundary (it left one newline on each side), so `blank` is
|
|
176
|
+
* also a preservation of the former behaviour where that behaviour was right.
|
|
177
|
+
*/
|
|
178
|
+
/**
|
|
179
|
+
* The CONTENTS of fenced blocks — the other side of `stripFences`.
|
|
180
|
+
*
|
|
181
|
+
* Added 2026-09-08 for the check "a path as a command argument inside a ```-block"
|
|
182
|
+
* (the sixth form of a reference). A private regex for the fence there would have been
|
|
183
|
+
* the seventh instance of the class this knowledge base has already paid for:
|
|
184
|
+
* `/^```[\s\S]*?^```/gm` knows nothing about nested fences or about `~~~`, and the
|
|
185
|
+
* parser does — the `fence` token has a `content`.
|
|
186
|
+
*
|
|
187
|
+
* No parser — returns an empty list, and the caller must survive that: for hooks
|
|
188
|
+
* degradation is acceptable (see the module comment), while a silent fallback to a
|
|
189
|
+
* regex would mean a working degraded version that nobody notices.
|
|
190
|
+
*/
|
|
191
|
+
export function fences(text) {
|
|
192
|
+
if (md === null)
|
|
193
|
+
return [];
|
|
194
|
+
const out = [];
|
|
195
|
+
for (const t of md.parse(blankFrontmatter(text), {}))
|
|
196
|
+
if (t.type === "fence" || t.type === "code_block")
|
|
197
|
+
out.push(t.content);
|
|
198
|
+
return out;
|
|
199
|
+
}
|
|
200
|
+
export function stripFences(text, { blank = false } = {}) {
|
|
201
|
+
if (md === null)
|
|
202
|
+
return text;
|
|
203
|
+
const lines = text.split("\n");
|
|
204
|
+
const drop = new Set();
|
|
205
|
+
for (const t of md.parse(blankFrontmatter(text), {}))
|
|
206
|
+
if ((t.type === "fence" || t.type === "code_block") && t.map)
|
|
207
|
+
for (let i = t.map[0]; i < t.map[1]; i++)
|
|
208
|
+
drop.add(i);
|
|
209
|
+
return blank
|
|
210
|
+
? lines.map((l, i) => (drop.has(i) ? "" : l)).join("\n")
|
|
211
|
+
: lines.filter((_, i) => !drop.has(i)).join("\n");
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* For SCRIPTS, not for hooks: fails if there is no parser.
|
|
215
|
+
*
|
|
216
|
+
* For a linter degradation is acceptable — it is advisory and can say so out loud. A
|
|
217
|
+
* skill script hands numbers to a pipeline gate, and an empty list of headings there is
|
|
218
|
+
* indistinguishable from "the paper has no sections". A confident zero has already been
|
|
219
|
+
* read as a finding four times in this repo; here it is inexpressible.
|
|
220
|
+
*/
|
|
221
|
+
export function requireMarkdown({ from = import.meta.url, } = {}) {
|
|
222
|
+
if (MD_AVAILABLE())
|
|
223
|
+
return;
|
|
224
|
+
// 🔴 THE CURE DEPENDS ON WHERE THIS COPY RUNS FROM. Measured 2026-09-19: a Claude Code plugin
|
|
225
|
+
// copy is installed without dependencies (`npm pack` strips `package-lock.json`, and the plugin
|
|
226
|
+
// cache runs `npm ci` only with a lockfile). The plugin channel was removed in #82, but a copy
|
|
227
|
+
// installed before then still runs from there, and "npm i at the repo root" would point its user
|
|
228
|
+
// at a repository they do not have. The location is readable from this file's own URL (`from`,
|
|
229
|
+
// a parameter only so a test can name a plugin-cache location without copying the file there).
|
|
230
|
+
const fromPluginCache = from.includes("/.claude/plugins/");
|
|
231
|
+
console.error("markdown-it does not resolve — this script parses markup with a parser and without it " +
|
|
232
|
+
"would produce a confident zero instead of an error.\n" +
|
|
233
|
+
(fromPluginCache
|
|
234
|
+
? " Running from a PLUGIN copy, which is installed without dependencies. Install the npm\n" +
|
|
235
|
+
" package in the project as well (`npm i paperlint`) and call it through\n" +
|
|
236
|
+
" `npx paperlint`, which resolves from the project's own tree."
|
|
237
|
+
: " Cured by `npm i` at the repo root."));
|
|
238
|
+
process.exit(2);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* GFM tables — rows, cells and the line range, WITH THE PARSER.
|
|
242
|
+
*
|
|
243
|
+
* The only consumer as of 2026-08-20 is `crosspost-article`, which needs to re-lay a
|
|
244
|
+
* table into a monospace block for a platform without tables (Medium). It lives here
|
|
245
|
+
* and not in the skill, by the rule "markup is parsed with a parser, and in one place":
|
|
246
|
+
* with a regex a table is told apart from a line of text with pipes only by its
|
|
247
|
+
* neighbours, and that is exactly the class that has already cost this repo 27 places.
|
|
248
|
+
*
|
|
249
|
+
* Returns `{ line, endLine, rows }`, where `rows[0]` is the header; the alignment row
|
|
250
|
+
* (`| --- |`) is thrown away, because in monospace output it has nothing to express.
|
|
251
|
+
*/
|
|
252
|
+
/**
|
|
253
|
+
* The document's paragraphs — `paragraph_open` line ranges, WITH THE PARSER.
|
|
254
|
+
* `[{ line, endLine }]`.
|
|
255
|
+
*
|
|
256
|
+
* The only consumer as of 2026-08-21 is `crosspost-article`: the blog's sources are
|
|
257
|
+
* hard-wrapped at a column (an editorial habit, not markdown), and the platforms render
|
|
258
|
+
* a single `\n` inside a paragraph DIFFERENTLY — dev.to (Redcarpet) keeps it as a
|
|
259
|
+
* literal line break, and the paragraph arrives torn into short lines exactly at the
|
|
260
|
+
* source file's boundaries. Medium has no such defect not because the platform is more
|
|
261
|
+
* honest, but because the paste goes through "Import a story" — the importer takes the
|
|
262
|
+
* ALREADY RENDERED page of the site (where the breaks were collapsed by the browser long
|
|
263
|
+
* ago), not the raw markdown.
|
|
264
|
+
*
|
|
265
|
+
* The range is EXACTLY the one `t.map` gives on `paragraph_open` — that is, a code
|
|
266
|
+
* fence, a heading, a table, a list (in a TIGHT list the item is not wrapped in a
|
|
267
|
+
* `paragraph_open` at all, it has no paragraph of its own) fall outside this function
|
|
268
|
+
* automatically, by the construction of the parser, and not by a separate line-type
|
|
269
|
+
* check.
|
|
270
|
+
*/
|
|
271
|
+
export function paragraphs(text) {
|
|
272
|
+
if (md === null)
|
|
273
|
+
return [];
|
|
274
|
+
return md
|
|
275
|
+
.parse(blankFrontmatter(text), {})
|
|
276
|
+
.flatMap((t) => t.type === "paragraph_open" && t.map
|
|
277
|
+
? [{ line: t.map[0], endLine: t.map[1] }]
|
|
278
|
+
: []);
|
|
279
|
+
}
|
|
280
|
+
export function tables(text) {
|
|
281
|
+
if (md === null)
|
|
282
|
+
return [];
|
|
283
|
+
const lines = blankFrontmatter(text).split("\n");
|
|
284
|
+
const out = [];
|
|
285
|
+
for (const t of md.parse(blankFrontmatter(text), {})) {
|
|
286
|
+
if (t.type !== "table_open" || !t.map)
|
|
287
|
+
continue;
|
|
288
|
+
const rows = [];
|
|
289
|
+
for (const raw of lines.slice(t.map[0], t.map[1])) {
|
|
290
|
+
if (/^\s*\|?[\s:|-]+\|?\s*$/.test(raw) && raw.includes("-"))
|
|
291
|
+
continue; // alignment
|
|
292
|
+
rows.push(raw
|
|
293
|
+
.replace(/^\s*\|/, "")
|
|
294
|
+
.replace(/\|\s*$/, "")
|
|
295
|
+
.split("|")
|
|
296
|
+
.map((c) => c.trim()));
|
|
297
|
+
}
|
|
298
|
+
out.push({ line: t.map[0], endLine: t.map[1], rows });
|
|
299
|
+
}
|
|
300
|
+
return out;
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../lib/markdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the consumer declares its settings — the ONE SOURCE for everything that is allowed to
|
|
3
|
+
* import it.
|
|
4
|
+
*
|
|
5
|
+
* 🔴 WHY THIS MODULE DOES NOT REMOVE THE DUPLICATION COMPLETELY, AND THAT IS NOT AN OVERSIGHT.
|
|
6
|
+
* The three hooks (`hooks/*.hook.mjs`) still have to keep their own copies of these values: a
|
|
7
|
+
* compiled hook is forbidden to import anything but `vigiles/hook`, and that ban is not
|
|
8
|
+
* arbitrary — a hook's capabilities equal its API surface, so allowing imports would mean
|
|
9
|
+
* allowing a reach into `child_process`. The restriction is wider than strictly necessary
|
|
10
|
+
* (importing plain constants adds no capability), and that is discussed in zernie/vigiles#245,
|
|
11
|
+
* but until it is relaxed the hooks duplicate, and drift is caught by the cross-check in
|
|
12
|
+
* `hooks/hooks.harness.ts`.
|
|
13
|
+
*
|
|
14
|
+
* 🔴 BUT THE REST WERE DUPLICATING FOR NO REASON AT ALL. `eslint-rules/papers.mjs` and
|
|
15
|
+
* `skills/paper-pipeline/scripts/consumer.mjs` are not hooks, carry no import restriction, and
|
|
16
|
+
* could always have taken the value from here. Worse, their copies were not covered by the
|
|
17
|
+
* cross-check at all — it compared the three hooks against each other, while these two lived
|
|
18
|
+
* next door and could drift apart silently. Found 2026-09-18 by grepping AFTER the cross-check
|
|
19
|
+
* itself had already been fixed — i.e. the check's wording was fixed, but nobody measured its
|
|
20
|
+
* COVERAGE.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* The tool's name. Its settings file is named after it (`CONFIG_FILE`), its messages start with it,
|
|
24
|
+
* and the hooks resolve their scripts through it. It equals the package name, and
|
|
25
|
+
* `lib/paper-config.harness.mjs` checks that.
|
|
26
|
+
*/
|
|
27
|
+
export declare const CONFIG_KEY: string;
|
|
28
|
+
/**
|
|
29
|
+
* THE SETTINGS FILE, ONE NAME AT TWO LEVELS, ONE SCHEMA (`SETTINGS_KEYS`):
|
|
30
|
+
*
|
|
31
|
+
* paperlint.json optional, at the project root: where the papers are, the
|
|
32
|
+
* project's rules, and defaults for every paper
|
|
33
|
+
* <papersDir>/<paper>/paperlint.json one paper: its venue preset, its kind, its own rules
|
|
34
|
+
*
|
|
35
|
+
* A paper's file merges over the root's: its `extends`, `kind` and `pdf` win, and its `rules` are
|
|
36
|
+
* applied after the root's. A venue preset (`paperlint:<name>`, or the project's own `./x.jsonc`)
|
|
37
|
+
* is the third level, below both.
|
|
38
|
+
*/
|
|
39
|
+
export declare const CONFIG_FILE: string;
|
|
40
|
+
/**
|
|
41
|
+
* The files that make a directory a PAPER. A `paperlint.json` beside one of them is that paper's,
|
|
42
|
+
* never the project's — so walking up from inside a paper does not stop at the paper's own file.
|
|
43
|
+
*/
|
|
44
|
+
export declare const PAPER_MARKERS: readonly string[];
|
|
45
|
+
/**
|
|
46
|
+
* The project root: the nearest directory, walking up from `startDir`, that holds a root
|
|
47
|
+
* `paperlint.json` (one not beside a paper's files); else the nearest directory holding a
|
|
48
|
+
* `package.json`; else `startDir` itself. The same walk eslint, prettier and tsc use for theirs.
|
|
49
|
+
*
|
|
50
|
+
* @param isFile whether a path exists — `existsSync` by default; `src/` passes its Files port.
|
|
51
|
+
*/
|
|
52
|
+
export declare function findProjectRoot(startDir: string, isFile?: (path: string) => boolean): string;
|
|
53
|
+
/**
|
|
54
|
+
* The project's settings: the object in `<root>/paperlint.json`, or undefined when there is no
|
|
55
|
+
* such file, or it does not parse, or it is not an object. For readers that only need one key and
|
|
56
|
+
* fall back to its default; `paperlint lint` parses the file strictly and names what is wrong.
|
|
57
|
+
*/
|
|
58
|
+
export declare function settingsOf(root: string): Readonly<Record<string, unknown>> | undefined;
|
|
59
|
+
/** The default papers directory, used when the root `paperlint.json` declares none (or there is none). */
|
|
60
|
+
export declare const DEFAULT_PAPERS_ROOT: string;
|
|
61
|
+
/**
|
|
62
|
+
* The field that names the papers directory: `{ "papersDir": "papers" }` in the root
|
|
63
|
+
* `paperlint.json`. Optional; absent means `DEFAULT_PAPERS_ROOT`.
|
|
64
|
+
*
|
|
65
|
+
* This is the one place the name is spelled. Code reads the field as
|
|
66
|
+
* `settings[PAPERS_DIR_FIELD]`, never by a literal, so renaming it again is a one-line change
|
|
67
|
+
* here. The three hooks cannot import this module, so they keep their own copy, and
|
|
68
|
+
* `lib/paper-config.harness.mjs` checks that every copy matches this one.
|
|
69
|
+
*/
|
|
70
|
+
export declare const PAPERS_DIR_FIELD: string;
|
|
71
|
+
/**
|
|
72
|
+
* Every key a `paperlint.json` may hold — the root's and a paper's, ONE schema — with who reads it.
|
|
73
|
+
* A key not listed here is REFUSED with its name, because a typo in a key otherwise reads as "not
|
|
74
|
+
* set". The keys in `ROOT_ONLY_KEYS` describe the whole project and are refused in a paper's file.
|
|
75
|
+
*
|
|
76
|
+
* 🔴 ONE LIST, AND IT IS CHECKED AGAINST THE READERS, NOT TRUSTED. `lib/paper-config.harness.mjs`
|
|
77
|
+
* walks the package's source, finds every `settingsOf(…)?.<key>` read and every field of
|
|
78
|
+
* `PaperlintConfig`, and requires each to be here — so a new reader that forgets this list turns
|
|
79
|
+
* the harness red before a consumer's config does.
|
|
80
|
+
*/
|
|
81
|
+
export declare const SETTINGS_KEYS: Readonly<Record<string, string>>;
|
|
82
|
+
/** The keys that only mean something for the whole project: refused in a paper's `paperlint.json`. */
|
|
83
|
+
export declare const ROOT_ONLY_KEYS: readonly string[];
|
|
84
|
+
//# sourceMappingURL=paper-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paper-config.d.ts","sourceRoot":"","sources":["../../lib/paper-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAKH;;;;GAIG;AACH,eAAO,MAAM,UAAU,EAAE,MAAoB,CAAC;AAE9C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,WAAW,EAAE,MAAyB,CAAC;AAEpD;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,MAAM,EAKzC,CAAC;AAEH;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAoB,GAC7C,MAAM,CAmBR;AAKD;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,GACX,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAQ/C;AAED,0GAA0G;AAC1G,eAAO,MAAM,mBAAmB,EAAE,MAAiB,CAAC;AAEpD;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAoB,CAAC;AAEpD;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAezD,CAAC;AAEH,sGAAsG;AACtG,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EAO1C,CAAC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the consumer declares its settings — the ONE SOURCE for everything that is allowed to
|
|
3
|
+
* import it.
|
|
4
|
+
*
|
|
5
|
+
* 🔴 WHY THIS MODULE DOES NOT REMOVE THE DUPLICATION COMPLETELY, AND THAT IS NOT AN OVERSIGHT.
|
|
6
|
+
* The three hooks (`hooks/*.hook.mjs`) still have to keep their own copies of these values: a
|
|
7
|
+
* compiled hook is forbidden to import anything but `vigiles/hook`, and that ban is not
|
|
8
|
+
* arbitrary — a hook's capabilities equal its API surface, so allowing imports would mean
|
|
9
|
+
* allowing a reach into `child_process`. The restriction is wider than strictly necessary
|
|
10
|
+
* (importing plain constants adds no capability), and that is discussed in zernie/vigiles#245,
|
|
11
|
+
* but until it is relaxed the hooks duplicate, and drift is caught by the cross-check in
|
|
12
|
+
* `hooks/hooks.harness.ts`.
|
|
13
|
+
*
|
|
14
|
+
* 🔴 BUT THE REST WERE DUPLICATING FOR NO REASON AT ALL. `eslint-rules/papers.mjs` and
|
|
15
|
+
* `skills/paper-pipeline/scripts/consumer.mjs` are not hooks, carry no import restriction, and
|
|
16
|
+
* could always have taken the value from here. Worse, their copies were not covered by the
|
|
17
|
+
* cross-check at all — it compared the three hooks against each other, while these two lived
|
|
18
|
+
* next door and could drift apart silently. Found 2026-09-18 by grepping AFTER the cross-check
|
|
19
|
+
* itself had already been fixed — i.e. the check's wording was fixed, but nobody measured its
|
|
20
|
+
* COVERAGE.
|
|
21
|
+
*/
|
|
22
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
23
|
+
import { dirname, join, resolve } from "node:path";
|
|
24
|
+
/**
|
|
25
|
+
* The tool's name. Its settings file is named after it (`CONFIG_FILE`), its messages start with it,
|
|
26
|
+
* and the hooks resolve their scripts through it. It equals the package name, and
|
|
27
|
+
* `lib/paper-config.harness.mjs` checks that.
|
|
28
|
+
*/
|
|
29
|
+
export const CONFIG_KEY = "paperlint";
|
|
30
|
+
/**
|
|
31
|
+
* THE SETTINGS FILE, ONE NAME AT TWO LEVELS, ONE SCHEMA (`SETTINGS_KEYS`):
|
|
32
|
+
*
|
|
33
|
+
* paperlint.json optional, at the project root: where the papers are, the
|
|
34
|
+
* project's rules, and defaults for every paper
|
|
35
|
+
* <papersDir>/<paper>/paperlint.json one paper: its venue preset, its kind, its own rules
|
|
36
|
+
*
|
|
37
|
+
* A paper's file merges over the root's: its `extends`, `kind` and `pdf` win, and its `rules` are
|
|
38
|
+
* applied after the root's. A venue preset (`paperlint:<name>`, or the project's own `./x.jsonc`)
|
|
39
|
+
* is the third level, below both.
|
|
40
|
+
*/
|
|
41
|
+
export const CONFIG_FILE = "paperlint.json";
|
|
42
|
+
/**
|
|
43
|
+
* The files that make a directory a PAPER. A `paperlint.json` beside one of them is that paper's,
|
|
44
|
+
* never the project's — so walking up from inside a paper does not stop at the paper's own file.
|
|
45
|
+
*/
|
|
46
|
+
export const PAPER_MARKERS = Object.freeze([
|
|
47
|
+
"paper.tex",
|
|
48
|
+
"paper.md",
|
|
49
|
+
"draft.md",
|
|
50
|
+
"PIPELINE-STATUS.md",
|
|
51
|
+
]);
|
|
52
|
+
/**
|
|
53
|
+
* The project root: the nearest directory, walking up from `startDir`, that holds a root
|
|
54
|
+
* `paperlint.json` (one not beside a paper's files); else the nearest directory holding a
|
|
55
|
+
* `package.json`; else `startDir` itself. The same walk eslint, prettier and tsc use for theirs.
|
|
56
|
+
*
|
|
57
|
+
* @param isFile whether a path exists — `existsSync` by default; `src/` passes its Files port.
|
|
58
|
+
*/
|
|
59
|
+
export function findProjectRoot(startDir, isFile = existsSync) {
|
|
60
|
+
const start = resolve(startDir);
|
|
61
|
+
const isPaper = (d) => PAPER_MARKERS.some((m) => isFile(join(d, m)));
|
|
62
|
+
// Up from `start` to the first directory `found` accepts; null past the filesystem root. A
|
|
63
|
+
// loop with an exit condition rather than `for (;;)`: the code after an endless loop is a block
|
|
64
|
+
// that can never run, and coverage counts it as one that did not.
|
|
65
|
+
const walk = (found) => {
|
|
66
|
+
let d = start;
|
|
67
|
+
while (!found(d)) {
|
|
68
|
+
if (dirname(d) === d)
|
|
69
|
+
return null;
|
|
70
|
+
d = dirname(d);
|
|
71
|
+
}
|
|
72
|
+
return d;
|
|
73
|
+
};
|
|
74
|
+
return (walk((d) => isFile(join(d, CONFIG_FILE)) && !isPaper(d)) ??
|
|
75
|
+
walk((d) => isFile(join(d, "package.json"))) ??
|
|
76
|
+
start);
|
|
77
|
+
}
|
|
78
|
+
const isObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
79
|
+
/**
|
|
80
|
+
* The project's settings: the object in `<root>/paperlint.json`, or undefined when there is no
|
|
81
|
+
* such file, or it does not parse, or it is not an object. For readers that only need one key and
|
|
82
|
+
* fall back to its default; `paperlint lint` parses the file strictly and names what is wrong.
|
|
83
|
+
*/
|
|
84
|
+
export function settingsOf(root) {
|
|
85
|
+
let v;
|
|
86
|
+
try {
|
|
87
|
+
v = JSON.parse(readFileSync(join(root, CONFIG_FILE), "utf8"));
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
return isObject(v) ? v : undefined;
|
|
93
|
+
}
|
|
94
|
+
/** The default papers directory, used when the root `paperlint.json` declares none (or there is none). */
|
|
95
|
+
export const DEFAULT_PAPERS_ROOT = "papers";
|
|
96
|
+
/**
|
|
97
|
+
* The field that names the papers directory: `{ "papersDir": "papers" }` in the root
|
|
98
|
+
* `paperlint.json`. Optional; absent means `DEFAULT_PAPERS_ROOT`.
|
|
99
|
+
*
|
|
100
|
+
* This is the one place the name is spelled. Code reads the field as
|
|
101
|
+
* `settings[PAPERS_DIR_FIELD]`, never by a literal, so renaming it again is a one-line change
|
|
102
|
+
* here. The three hooks cannot import this module, so they keep their own copy, and
|
|
103
|
+
* `lib/paper-config.harness.mjs` checks that every copy matches this one.
|
|
104
|
+
*/
|
|
105
|
+
export const PAPERS_DIR_FIELD = "papersDir";
|
|
106
|
+
/**
|
|
107
|
+
* Every key a `paperlint.json` may hold — the root's and a paper's, ONE schema — with who reads it.
|
|
108
|
+
* A key not listed here is REFUSED with its name, because a typo in a key otherwise reads as "not
|
|
109
|
+
* set". The keys in `ROOT_ONLY_KEYS` describe the whole project and are refused in a paper's file.
|
|
110
|
+
*
|
|
111
|
+
* 🔴 ONE LIST, AND IT IS CHECKED AGAINST THE READERS, NOT TRUSTED. `lib/paper-config.harness.mjs`
|
|
112
|
+
* walks the package's source, finds every `settingsOf(…)?.<key>` read and every field of
|
|
113
|
+
* `PaperlintConfig`, and requires each to be here — so a new reader that forgets this list turns
|
|
114
|
+
* the harness red before a consumer's config does.
|
|
115
|
+
*/
|
|
116
|
+
export const SETTINGS_KEYS = Object.freeze({
|
|
117
|
+
papersDir: `the papers directory, default "papers" — every command, the hooks`,
|
|
118
|
+
structure: "which files a paper directory must hold — paperlint lint",
|
|
119
|
+
rules: "rule overrides: { id: severity } for every paper in scope, or ESLint blocks (files, ignores, rules) — paperlint lint",
|
|
120
|
+
extends: "the venue preset: paperlint:<name> or ./path.jsonc — the pdf/ venue rules, paperlint build",
|
|
121
|
+
kind: "the kind of paper, whose page limit applies — pdf/limits",
|
|
122
|
+
pdf: "where the built PDF is, relative to the paper, when it is not paper.pdf — the facts",
|
|
123
|
+
scripts: "how skill prose names the scripts — consumer.mjs",
|
|
124
|
+
timezone: "the zone deadline anchors are written in — consumer.mjs",
|
|
125
|
+
contactEmail: "the polite-pool address for citation lookups — consumer.mjs",
|
|
126
|
+
triggerCases: "the consumer's own skill trigger cases — lib/skill-trigger-cases.mjs",
|
|
127
|
+
$comment: "a note for humans (JSON Schema's own comment keyword); ignored",
|
|
128
|
+
});
|
|
129
|
+
/** The keys that only mean something for the whole project: refused in a paper's `paperlint.json`. */
|
|
130
|
+
export const ROOT_ONLY_KEYS = Object.freeze([
|
|
131
|
+
"papersDir",
|
|
132
|
+
"structure",
|
|
133
|
+
"scripts",
|
|
134
|
+
"timezone",
|
|
135
|
+
"contactEmail",
|
|
136
|
+
"triggerCases",
|
|
137
|
+
]);
|
|
138
|
+
//# sourceMappingURL=paper-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paper-config.js","sourceRoot":"","sources":["../../lib/paper-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skill-eval-fixture.mjs — the throwaway working directory every trigger run sees.
|
|
3
|
+
*
|
|
4
|
+
* 🔴 WHY A FIXTURE IS NOT OPTIONAL, learned by getting it wrong (2026-08-11).
|
|
5
|
+
* A trigger run executes in a FRESH EMPTY cwd. Ask "grade the writing on this
|
|
6
|
+
* paper" in a directory containing no paper and the model reasonably does not
|
|
7
|
+
* reach for a skill — there is nothing to grade. Measured: without this fixture,
|
|
8
|
+
* `grade-paper-writing`, `harden-paper`, `map-prior-work` and
|
|
9
|
+
* `paper-adversarial-review` all scored 0% on prompts that had previously fired,
|
|
10
|
+
* and the zero was an artifact of the empty directory, not a fact about the skill.
|
|
11
|
+
*
|
|
12
|
+
* Extracted from `paper-pipeline/pipeline-firing.eval.mjs`, which had it right
|
|
13
|
+
* from the start, so the two runners cannot drift apart on what the model sees.
|
|
14
|
+
*
|
|
15
|
+
* ⚠️ AND THE PRICE, so this file is not a one-sided story (measured 2026-08-12).
|
|
16
|
+
* With a fixture present the model OPENS THE PAPER and looks around, so the number
|
|
17
|
+
* stops being "did the DESCRIPTION fire" and becomes "did the model go investigate
|
|
18
|
+
* and then fire". A different quantity, and a costlier one: ~590k → ~780k tokens
|
|
19
|
+
* per skill (+190k) and 67s → 84s, while this whole fixture is 1,537 characters
|
|
20
|
+
* ≈ 384 tokens. The growth is reading, not input size (`cache` 470k → 652k).
|
|
21
|
+
* Cite the trigger numbers with that caveat attached — it is written out in
|
|
22
|
+
* `vigiles/repro/skill-trigger-2026-08-11/README.md` under "How to read".
|
|
23
|
+
*/
|
|
24
|
+
export declare const FIXTURE: {
|
|
25
|
+
"paper/paper.md": string;
|
|
26
|
+
"paper/repro/README.md": string;
|
|
27
|
+
"paper/PIPELINE-STATUS.md": string;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=skill-eval-fixture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-eval-fixture.d.ts","sourceRoot":"","sources":["../../lib/skill-eval-fixture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,OAAO;;;;CAuCnB,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skill-eval-fixture.mjs — the throwaway working directory every trigger run sees.
|
|
3
|
+
*
|
|
4
|
+
* 🔴 WHY A FIXTURE IS NOT OPTIONAL, learned by getting it wrong (2026-08-11).
|
|
5
|
+
* A trigger run executes in a FRESH EMPTY cwd. Ask "grade the writing on this
|
|
6
|
+
* paper" in a directory containing no paper and the model reasonably does not
|
|
7
|
+
* reach for a skill — there is nothing to grade. Measured: without this fixture,
|
|
8
|
+
* `grade-paper-writing`, `harden-paper`, `map-prior-work` and
|
|
9
|
+
* `paper-adversarial-review` all scored 0% on prompts that had previously fired,
|
|
10
|
+
* and the zero was an artifact of the empty directory, not a fact about the skill.
|
|
11
|
+
*
|
|
12
|
+
* Extracted from `paper-pipeline/pipeline-firing.eval.mjs`, which had it right
|
|
13
|
+
* from the start, so the two runners cannot drift apart on what the model sees.
|
|
14
|
+
*
|
|
15
|
+
* ⚠️ AND THE PRICE, so this file is not a one-sided story (measured 2026-08-12).
|
|
16
|
+
* With a fixture present the model OPENS THE PAPER and looks around, so the number
|
|
17
|
+
* stops being "did the DESCRIPTION fire" and becomes "did the model go investigate
|
|
18
|
+
* and then fire". A different quantity, and a costlier one: ~590k → ~780k tokens
|
|
19
|
+
* per skill (+190k) and 67s → 84s, while this whole fixture is 1,537 characters
|
|
20
|
+
* ≈ 384 tokens. The growth is reading, not input size (`cache` 470k → 652k).
|
|
21
|
+
* Cite the trigger numbers with that caveat attached — it is written out in
|
|
22
|
+
* `vigiles/repro/skill-trigger-2026-08-11/README.md` under "How to read".
|
|
23
|
+
*/
|
|
24
|
+
export const FIXTURE = {
|
|
25
|
+
"paper/paper.md": [
|
|
26
|
+
"# Prose Isn't Policy: Measuring Whether Agent-Config Rules Are Enforceable",
|
|
27
|
+
"",
|
|
28
|
+
"## Abstract",
|
|
29
|
+
"Agent configuration files state rules in prose and assume the model obeys them. We compile a",
|
|
30
|
+
"corpus of real rules and measure what fraction can be mechanically enforced. We find that 84%",
|
|
31
|
+
"of rules in our corpus are enforceable, and that LLM-authored checkers for the remainder leak",
|
|
32
|
+
"silently in 84-96% of adversarial cases \\cite{greshake2023}.",
|
|
33
|
+
"",
|
|
34
|
+
"## 1 Introduction",
|
|
35
|
+
"Every agent harness ships a natural-language rulebook. Nothing checks it. This is the same",
|
|
36
|
+
"mistake as a code comment that claims an invariant no test enforces \\cite{thompson1984}.",
|
|
37
|
+
"",
|
|
38
|
+
"## 2 Method",
|
|
39
|
+
"We gather rules from public repositories, classify each by enforceability, and build a",
|
|
40
|
+
"two-stage adversarial gate that validates a synthesized rule against a blind gold set.",
|
|
41
|
+
"",
|
|
42
|
+
"## 3 Results",
|
|
43
|
+
"See Table 1. The headline number is 84%.",
|
|
44
|
+
"",
|
|
45
|
+
"## 4 Discussion",
|
|
46
|
+
"The result generalizes beyond our corpus in the sense that the mechanism is not corpus-specific,",
|
|
47
|
+
"though of course the specific percentages are, and it is important to note in this context that",
|
|
48
|
+
"the framing itself may be what carries, rather than the measurement.",
|
|
49
|
+
"",
|
|
50
|
+
"## 5 Threats to Validity",
|
|
51
|
+
"Our corpus is drawn from public repositories and may not represent private configurations.",
|
|
52
|
+
"",
|
|
53
|
+
"## 6 Related Work",
|
|
54
|
+
"TODO",
|
|
55
|
+
"",
|
|
56
|
+
"## 7 Conclusion",
|
|
57
|
+
"Prose is not policy.",
|
|
58
|
+
].join("\n"),
|
|
59
|
+
"paper/repro/README.md": "# Reproduction artifact\n\n`python3 paper_numbers.py` recomputes every bolded figure in paper.md.\n",
|
|
60
|
+
"paper/PIPELINE-STATUS.md": "# Pipeline status\n\n| gate | state |\n|---|---|\n| numbers | pass |\n| structure | not run |\n| citations | not run |\n",
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=skill-eval-fixture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-eval-fixture.js","sourceRoot":"","sources":["../../lib/skill-eval-fixture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,gBAAgB,EAAE;QAChB,4EAA4E;QAC5E,EAAE;QACF,aAAa;QACb,8FAA8F;QAC9F,+FAA+F;QAC/F,+FAA+F;QAC/F,+DAA+D;QAC/D,EAAE;QACF,mBAAmB;QACnB,4FAA4F;QAC5F,2FAA2F;QAC3F,EAAE;QACF,aAAa;QACb,wFAAwF;QACxF,wFAAwF;QACxF,EAAE;QACF,cAAc;QACd,0CAA0C;QAC1C,EAAE;QACF,iBAAiB;QACjB,kGAAkG;QAClG,iGAAiG;QACjG,sEAAsE;QACtE,EAAE;QACF,0BAA0B;QAC1B,4FAA4F;QAC5F,EAAE;QACF,mBAAmB;QACnB,MAAM;QACN,EAAE;QACF,iBAAiB;QACjB,sBAAsB;KACvB,CAAC,IAAI,CAAC,IAAI,CAAC;IACZ,uBAAuB,EACrB,qGAAqG;IACvG,0BAA0B,EACxB,0HAA0H;CAC7H,CAAC"}
|