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
|
@@ -7,11 +7,9 @@
|
|
|
7
7
|
*
|
|
8
8
|
* 1. where is the consumer's repository root, now that walking `..` from here lands in
|
|
9
9
|
* `node_modules/` instead;
|
|
10
|
-
* 2.
|
|
11
|
-
* `npm ci`;
|
|
12
|
-
* 3. was this file executed, or merely imported — a question whose usual answer stops
|
|
10
|
+
* 2. was this file executed, or merely imported — a question whose usual answer stops
|
|
13
11
|
* working the moment the file is reached through a symlink;
|
|
14
|
-
*
|
|
12
|
+
* 3. by what path a SKILL'S PROSE names these scripts, so that a checker can tell an
|
|
15
13
|
* instruction that runs them from one that runs something else. See the fourth-carrier
|
|
16
14
|
* section at the bottom of this file.
|
|
17
15
|
*
|
|
@@ -23,7 +21,7 @@
|
|
|
23
21
|
* paper-pipeline/scripts
|
|
24
22
|
*
|
|
25
23
|
* so every command a skill's prose already names — `node .claude/skills/paper-pipeline/scripts/
|
|
26
|
-
*
|
|
24
|
+
* <script>.mjs …` — keeps working unchanged. That is the whole reason the symlink exists: the
|
|
27
25
|
* first consumer names those paths 306 times across 129 files, almost all of it in the PROSE of
|
|
28
26
|
* skills, which no refactor can rewrite.
|
|
29
27
|
*
|
|
@@ -35,12 +33,11 @@
|
|
|
35
33
|
* process.cwd() /…/<the consumer repository root>
|
|
36
34
|
*
|
|
37
35
|
* Node resolves the entry point to its realpath (`--preserve-symlinks-main` is off by default)
|
|
38
|
-
* but leaves `argv[1]` as typed.
|
|
36
|
+
* but leaves `argv[1]` as typed. Two consequences, each one a function here:
|
|
39
37
|
*
|
|
40
38
|
* 🔴 `import.meta.url === \`file://${process.argv[1]}\`` — the main guard nine scripts in this
|
|
41
39
|
* directory used — is `false` through the symlink. NOT an error: the process exits 0 having
|
|
42
|
-
* done nothing
|
|
43
|
-
* silently announce nothing, and every caller would read success. `isMain()` compares
|
|
40
|
+
* done nothing, and every caller reads success. `isMain()` compares
|
|
44
41
|
* against the REALPATH of `argv[1]` instead, which is true through both routes.
|
|
45
42
|
*
|
|
46
43
|
* 🔴 `resolve(import.meta.dirname, "..", "..", "..", "..")` — the repository root, correct
|
|
@@ -48,30 +45,9 @@
|
|
|
48
45
|
* by `process.cwd()`, which is the consumer root because every one of those 306 invocations
|
|
49
46
|
* is `node .claude/skills/…` typed from the repository root. `consumerRoot()`.
|
|
50
47
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* `ledgerPath()` refuses to return that path at all.
|
|
55
|
-
*
|
|
56
|
-
* ── THE LEDGER, THREE RUNGS ─────────────────────────────────────────────────
|
|
57
|
-
* 1. `PIPELINE_LEDGER` in the environment — always wins. This is what test harnesses set to
|
|
58
|
-
* keep fixture rows out of real history, so it must outrank a declaration on disk.
|
|
59
|
-
* 2. `{ "ledger": "…" }` in the CONSUMER's root `paperlint.json`, read
|
|
60
|
-
* from `process.cwd()`, resolved relative to it.
|
|
61
|
-
* 3. `runs.jsonl` beside this file — ONLY when this file is not inside `node_modules`, i.e.
|
|
62
|
-
* when the package is being developed in its own checkout. Inside `node_modules` with
|
|
63
|
-
* nothing declared, this THROWS.
|
|
64
|
-
*
|
|
65
|
-
* 🔴 WHY RUNG 3 THROWS RATHER THAN GUESSING. Every other candidate default is worse in the same
|
|
66
|
-
* direction. Writing beside the file loses data at the next `npm ci`. Writing to
|
|
67
|
-
* `<cwd>/runs.jsonl` puts an append-only journal at the top of someone's repository without
|
|
68
|
-
* asking. Writing nowhere makes `record()` a no-op, which is the stored "nothing was wrong" this
|
|
69
|
-
* ledger exists to abolish. A throw is the only one of the four that cannot be mistaken for
|
|
70
|
-
* having worked — and it carries the cure, naming the key and the file to put it in.
|
|
71
|
-
*
|
|
72
|
-
* ⚠️ THE EXAMPLES HERE ARE DELIBERATELY GENERIC (`docs/pipeline-runs.jsonl`). The first
|
|
73
|
-
* consumer's own directory names are absent by the same rule `papers.harness.mjs` part IV
|
|
74
|
-
* enforces for `papers.mjs`: a package that spells out one user's private tree has one user.
|
|
48
|
+
* ⚠️ THE EXAMPLES HERE ARE DELIBERATELY GENERIC. The first consumer's own directory names are
|
|
49
|
+
* absent by the same rule `papers.harness.mjs` part IV enforces for `papers.mjs`: a package that
|
|
50
|
+
* spells out one user's private tree has one user.
|
|
75
51
|
*/
|
|
76
52
|
import {
|
|
77
53
|
existsSync,
|
|
@@ -85,11 +61,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
85
61
|
|
|
86
62
|
// Re-exported, not re-declared — see the note in `lib/paper-config.mjs`. This file is not a hook
|
|
87
63
|
// and never needed its own copy.
|
|
88
|
-
import {
|
|
89
|
-
CONFIG_FILE,
|
|
90
|
-
CONFIG_KEY,
|
|
91
|
-
settingsOf,
|
|
92
|
-
} from "../../../lib/paper-config.mjs";
|
|
64
|
+
import { CONFIG_FILE, CONFIG_KEY, settingsOf } from "#lib/paper-config";
|
|
93
65
|
export { CONFIG_KEY, settingsOf };
|
|
94
66
|
|
|
95
67
|
/**
|
|
@@ -250,68 +222,22 @@ function readlinkOr(entry, readlink) {
|
|
|
250
222
|
* True when `dir` lies inside a `node_modules` directory.
|
|
251
223
|
*
|
|
252
224
|
* Segment-wise, not `includes("node_modules")`: a repository legitimately named
|
|
253
|
-
* `my-node_modules-inspector` is not an installed package, and a substring test would refuse
|
|
254
|
-
*
|
|
225
|
+
* `my-node_modules-inspector` is not an installed package, and a substring test would refuse it.
|
|
226
|
+
* Cheap to get right, and the failure it prevents is a throw in someone's face.
|
|
255
227
|
*/
|
|
256
228
|
export function insideNodeModules(dir) {
|
|
257
229
|
return dir.split(sep).includes("node_modules");
|
|
258
230
|
}
|
|
259
231
|
|
|
260
|
-
/**
|
|
261
|
-
* Where the run ledger lives. Three rungs; see the docblock.
|
|
262
|
-
*
|
|
263
|
-
* @param hereDir the directory of the module that owns the ledger — pass `import.meta.dirname`.
|
|
264
|
-
* @returns an absolute path. Never a path inside `node_modules`.
|
|
265
|
-
*/
|
|
266
|
-
export function ledgerPath(
|
|
267
|
-
hereDir,
|
|
268
|
-
{ env = process.env, cwd = process.cwd() } = {},
|
|
269
|
-
) {
|
|
270
|
-
// Rung 1 — the environment. Deliberately first: harnesses redirect the ledger BEFORE importing
|
|
271
|
-
// it, and a declaration on disk that could override that would put fixture rows in real history.
|
|
272
|
-
if (env.PIPELINE_LEDGER) return resolve(env.PIPELINE_LEDGER);
|
|
273
|
-
|
|
274
|
-
// Rung 2 — the consumer's declaration.
|
|
275
|
-
const root = consumerRoot({ env, cwd });
|
|
276
|
-
const declared = settingsOf(consumerRoot({ env, cwd }))?.ledger;
|
|
277
|
-
// 🔴 `declared === undefined`, NOT `declared ?? default` — the same distinction `papersRoot()`
|
|
278
|
-
// makes and for the same reason: `"ledger": null` is a keystroke, not an absence, and reading
|
|
279
|
-
// it as "nothing was declared" would silently pick a different file than the one asked for.
|
|
280
|
-
if (declared !== undefined) {
|
|
281
|
-
if (typeof declared !== "string" || declared.length === 0)
|
|
282
|
-
throw new TypeError(
|
|
283
|
-
`${CONFIG_KEY}: "ledger" must be a non-empty string, got ${JSON.stringify(declared)}`,
|
|
284
|
-
);
|
|
285
|
-
return resolve(root, declared);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// Rung 3 — beside this file, but only in the package's own checkout.
|
|
289
|
-
if (insideNodeModules(hereDir))
|
|
290
|
-
throw new Error(
|
|
291
|
-
`${CONFIG_KEY}: no ledger location is declared, and the default (a file beside this ` +
|
|
292
|
-
`module) is inside node_modules, which \`npm ci\` deletes.\n` +
|
|
293
|
-
`Declare where the ledger lives, in ${join(root, CONFIG_FILE)}:\n` +
|
|
294
|
-
` { "ledger": "docs/pipeline-runs.jsonl" }\n` +
|
|
295
|
-
`or set PIPELINE_LEDGER for a single run.\n` +
|
|
296
|
-
`This is thrown rather than defaulted on purpose: appending to a path under ` +
|
|
297
|
-
`node_modules succeeds, so the rows would look recorded right up until the next ` +
|
|
298
|
-
`install removed them, with no error at any point.`,
|
|
299
|
-
);
|
|
300
|
-
return join(hereDir, "runs.jsonl");
|
|
301
|
-
}
|
|
302
|
-
|
|
303
232
|
// ═════════════════════════════════════════════════════════════════════════════════════════════
|
|
304
|
-
//
|
|
233
|
+
// WHERE A SKILL'S PROSE NAMES THESE SCRIPTS
|
|
305
234
|
//
|
|
306
|
-
// `papersRoot()` answers "where does the consumer keep its papers"
|
|
307
|
-
//
|
|
308
|
-
// are the consumer's own citation checkers". This answers the fourth: BY WHAT PATH does a skill
|
|
309
|
-
// instruct the model to run `announce.mjs` and `ledger.mjs`.
|
|
235
|
+
// `papersRoot()` answers "where does the consumer keep its papers". This answers: BY WHAT PATH
|
|
236
|
+
// does a skill instruct the model to run this package's scripts.
|
|
310
237
|
//
|
|
311
|
-
// 🔴 IT IS A DIFFERENT KIND OF PATH
|
|
312
|
-
//
|
|
313
|
-
//
|
|
314
|
-
// …` — so it must stay relative to the consumer root and spelled with `/`, exactly as the prose
|
|
238
|
+
// 🔴 IT IS A DIFFERENT KIND OF PATH, and the difference decides the API. `papersRoot()` is read by
|
|
239
|
+
// CODE and may be absolute. This one is compared against text a human wrote inside a SKILL.md —
|
|
240
|
+
// `node .claude/skills/paper-pipeline/scripts/<script>.mjs …` — so it must stay relative to the consumer root and spelled with `/`, exactly as the prose
|
|
315
241
|
// spells it. Returning an absolute path here would make every `startsWith` test false and every
|
|
316
242
|
// check that depends on it pass over an empty set.
|
|
317
243
|
//
|
|
@@ -350,7 +276,7 @@ export function scriptsRoot({ env = process.env, cwd = process.cwd() } = {}) {
|
|
|
350
276
|
const root = consumerRoot({ env, cwd });
|
|
351
277
|
const declared = settingsOf(consumerRoot({ env, cwd }))?.scripts;
|
|
352
278
|
// 🔴 `declared === undefined`, NOT `declared ?? DEFAULT` — the same distinction `papersRoot()`
|
|
353
|
-
//
|
|
279
|
+
// makes, for the same reason: `"scripts": null` is a keystroke, not an
|
|
354
280
|
// absence, and silently substituting the default for it hides a typo behind a working run.
|
|
355
281
|
const rel = declared === undefined ? DEFAULT_SCRIPTS_ROOT : declared;
|
|
356
282
|
if (typeof rel !== "string" || rel.length === 0)
|
|
@@ -389,12 +315,11 @@ export function scriptsRoot({ env = process.env, cwd = process.cwd() } = {}) {
|
|
|
389
315
|
}
|
|
390
316
|
|
|
391
317
|
// ═════════════════════════════════════════════════════════════════════════════════════════════
|
|
392
|
-
//
|
|
318
|
+
// WHICH WALL CLOCK THE CONSUMER SCHEDULES AGAINST
|
|
393
319
|
//
|
|
394
|
-
// `papersRoot()` answers "where are the papers", `
|
|
395
|
-
// `
|
|
396
|
-
//
|
|
397
|
-
// answers the sixth: IN WHAT TIME ZONE does a deadline anchor get written.
|
|
320
|
+
// `papersRoot()` answers "where are the papers", `scriptsRoot()` "by what path does prose name
|
|
321
|
+
// these scripts", `triggerCases` "where are the consumer's own trigger cases". This answers: IN
|
|
322
|
+
// WHAT TIME ZONE does a deadline anchor get written.
|
|
398
323
|
//
|
|
399
324
|
// 🔴 WHY IT IS A DECLARATION AND NOT A CONSTANT. A deadline is the one quantity in this pipeline
|
|
400
325
|
// that is meaningless without a zone, and the zone belongs to the PERSON, not to the pipeline —
|
|
@@ -450,7 +375,7 @@ export function consumerTimezone({
|
|
|
450
375
|
}
|
|
451
376
|
|
|
452
377
|
// ═════════════════════════════════════════════════════════════════════════════════════════════
|
|
453
|
-
//
|
|
378
|
+
// WHOM THE SCHOLARLY APIs SHOULD CONTACT
|
|
454
379
|
//
|
|
455
380
|
// Crossref and friends run a "polite pool": send a `mailto:` in the User-Agent and you get the
|
|
456
381
|
// faster, more reliable tier, plus a warning by email instead of a silent block if your usage
|
|
@@ -489,13 +414,7 @@ export function consumerContactEmail({
|
|
|
489
414
|
return declared;
|
|
490
415
|
}
|
|
491
416
|
|
|
492
|
-
/**
|
|
493
|
-
* The individual script paths, derived from one root.
|
|
494
|
-
*
|
|
495
|
-
* 🔴 THE NAMES LIVE HERE, NOT IN THE CONSUMER — the same half that keeps `paperFiles()` honest.
|
|
496
|
-
* `announce.mjs` and `ledger.mjs` are this package's contract; a consumer that spelled them out
|
|
497
|
-
* itself would keep its copy of the list in step by hand, and a hand-kept list rots silently.
|
|
498
|
-
*/
|
|
417
|
+
/** The prefix every prose path to this package's scripts starts with, derived from one root. */
|
|
499
418
|
export function pipelineScripts(root) {
|
|
500
419
|
// 🔴 ONE TRAILING SLASH, NOT THE ONE THAT WAS TYPED. `scriptsRoot()` returns the declaration
|
|
501
420
|
// verbatim — it must, the value is compared against prose — so `"scripts": "tools/pipeline/"`
|
|
@@ -508,9 +427,5 @@ export function pipelineScripts(root) {
|
|
|
508
427
|
return {
|
|
509
428
|
/** What every prose path under this root starts with. Trailing slash, for `startsWith`. */
|
|
510
429
|
prefix: `${base}/`,
|
|
511
|
-
/** Announces that a gate has started. */
|
|
512
|
-
announce: `${base}/announce.mjs`,
|
|
513
|
-
/** Appends the verdict row. */
|
|
514
|
-
ledger: `${base}/ledger.mjs`,
|
|
515
430
|
};
|
|
516
431
|
}
|
|
@@ -6,7 +6,7 @@ import assert from "node:assert/strict";
|
|
|
6
6
|
import { mkdirSync, symlinkSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { join } from "node:path";
|
|
8
8
|
import { afterEach, test } from "vitest";
|
|
9
|
-
import { useTempDir, writeTree } from "../../../test/support.
|
|
9
|
+
import { useTempDir, writeTree } from "../../../test/support.ts";
|
|
10
10
|
import {
|
|
11
11
|
consumerContactEmail,
|
|
12
12
|
consumerTimezone,
|
|
@@ -71,10 +71,7 @@ import {
|
|
|
71
71
|
} from "node:fs";
|
|
72
72
|
import { createHash } from "node:crypto";
|
|
73
73
|
import { join, resolve, dirname, basename } from "node:path";
|
|
74
|
-
import {
|
|
75
|
-
headings as mdHeadings,
|
|
76
|
-
requireMarkdown,
|
|
77
|
-
} from "../../../lib/markdown.mjs";
|
|
74
|
+
import { headings as mdHeadings, requireMarkdown } from "#lib/markdown";
|
|
78
75
|
import { isMain } from "./consumer.mjs";
|
|
79
76
|
|
|
80
77
|
// Markup is parsed with a parser (`CLAUDE.md`, 2026-08-11). We fail rather than degrade: without
|
|
@@ -8,7 +8,7 @@ import { readFileSync, writeFileSync } from "node:fs";
|
|
|
8
8
|
import { dirname, join } from "node:path";
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
|
10
10
|
import { test } from "vitest";
|
|
11
|
-
import { runNode, useTempDir, writeTree } from "../../../test/support.
|
|
11
|
+
import { runNode, useTempDir, writeTree } from "../../../test/support.ts";
|
|
12
12
|
import {
|
|
13
13
|
buildFacts,
|
|
14
14
|
extractIds,
|
|
@@ -317,9 +317,8 @@ function fixture({ scripts = {}, allow = null, bundle = {}, at = "repro" }) {
|
|
|
317
317
|
}
|
|
318
318
|
|
|
319
319
|
// ── 11. the ledger prints on a CLEAN run, and the header states the count ───────────────────────
|
|
320
|
-
// The count matters beyond tidiness:
|
|
321
|
-
//
|
|
322
|
-
// findings, so without the stated count a clean paper would be recorded as twenty findings.
|
|
320
|
+
// The count matters beyond tidiness: the ledger is ~20 lines that are not findings, so a caller
|
|
321
|
+
// counting output lines would read a clean paper as twenty findings.
|
|
323
322
|
{
|
|
324
323
|
const r = run(
|
|
325
324
|
fixture({
|
|
@@ -8,14 +8,14 @@ import { symlinkSync } from "node:fs";
|
|
|
8
8
|
import { dirname, join } from "node:path";
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
|
10
10
|
import { test } from "vitest";
|
|
11
|
-
import { runNode, useTempDir, writeTree } from "../../../test/support.
|
|
11
|
+
import { runNode, useTempDir, writeTree } from "../../../test/support.ts";
|
|
12
12
|
|
|
13
13
|
const SCRIPT = join(
|
|
14
14
|
dirname(fileURLToPath(import.meta.url)),
|
|
15
15
|
"generated-code.mjs",
|
|
16
16
|
);
|
|
17
17
|
const root = useTempDir("generated-code-");
|
|
18
|
-
const run = (...args) => runNode(SCRIPT, args);
|
|
18
|
+
const run = (...args: string[]) => runNode(SCRIPT, args);
|
|
19
19
|
|
|
20
20
|
test("no argument prints the usage; a directory that does not exist scanned nothing, and says so", () => {
|
|
21
21
|
assert.deepEqual(run(), {
|
|
@@ -41,7 +41,7 @@ test("repro/: a dangling link is passed over; skipped trees are named, more than
|
|
|
41
41
|
const dir = writeTree(join(root, "paper"), {
|
|
42
42
|
...deep,
|
|
43
43
|
"repro/.cache/x.py": "",
|
|
44
|
-
//
|
|
44
|
+
// A fixture directory the scan must skip, not an install location.
|
|
45
45
|
"repro/node_modules/x.js": "",
|
|
46
46
|
"repro/__pycache__/x.py": "",
|
|
47
47
|
// Draws randomness unseeded: a NO_SEED finding, which the reasonless row below waves through.
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* The findings themselves are planted in `population-map.test.mjs` (vitest; until #52 a
|
|
12
12
|
* self-test script this harness spawned). This file keeps what only the command shows: finding
|
|
13
13
|
* paper.md and repro/populations.tsv, and `--flags-only` staying silent on a clean paper — the
|
|
14
|
-
* wiring the CI step
|
|
14
|
+
* wiring the CI step actually invokes.
|
|
15
15
|
*/
|
|
16
16
|
import assert from "node:assert/strict";
|
|
17
17
|
import { execFileSync } from "node:child_process";
|
|
@@ -107,8 +107,8 @@ const REG = [
|
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
// ── 4. KNOWN GAP, asserted so it stays visible ─────────────────────────────────────────
|
|
110
|
-
// 🔴 A paper with NO repro/populations.tsv exits 0 in silence,
|
|
111
|
-
//
|
|
110
|
+
// 🔴 A paper with NO repro/populations.tsv exits 0 in silence, which reads as a pass for
|
|
111
|
+
// draft-paper. So a paper that never declared its populations scores
|
|
112
112
|
// identically to one that declared them and tied every one. Absence is invisible again — the same
|
|
113
113
|
// shape artifact-coverage.mjs was written to close for the released bundle.
|
|
114
114
|
//
|
|
@@ -48,10 +48,7 @@
|
|
|
48
48
|
*/
|
|
49
49
|
import { readFileSync, existsSync } from "node:fs";
|
|
50
50
|
import { join } from "node:path";
|
|
51
|
-
import {
|
|
52
|
-
headings as mdHeadings,
|
|
53
|
-
requireMarkdown,
|
|
54
|
-
} from "../../../lib/markdown.mjs";
|
|
51
|
+
import { headings as mdHeadings, requireMarkdown } from "#lib/markdown";
|
|
55
52
|
import { isMain } from "./consumer.mjs";
|
|
56
53
|
|
|
57
54
|
// Markup is parsed with a parser (`CLAUDE.md`, 2026-08-11). We fail rather than degrade: without
|
|
@@ -11,7 +11,7 @@ import assert from "node:assert/strict";
|
|
|
11
11
|
import { dirname, join } from "node:path";
|
|
12
12
|
import { fileURLToPath } from "node:url";
|
|
13
13
|
import { test } from "vitest";
|
|
14
|
-
import { runNode, useTempDir, writeTree } from "../../../test/support.
|
|
14
|
+
import { runNode, useTempDir, writeTree } from "../../../test/support.ts";
|
|
15
15
|
import { bodyOf, findings } from "./population-map.mjs";
|
|
16
16
|
|
|
17
17
|
const SCRIPT = join(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* round-diff.harness.
|
|
2
|
+
* round-diff.harness.ts — plant the defect each check in `round-diff.mjs` claims to catch, assert
|
|
3
3
|
* it says no with the RIGHT WORDS, and assert it stays silent on the clean case. `npx vigiles test`.
|
|
4
4
|
*
|
|
5
5
|
* WHAT IS UNDER TEST. `.claude/skills/paper-pipeline/scripts/round-diff.mjs`: a review round may only
|
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
import { tmpdir } from "node:os";
|
|
50
50
|
import { join, dirname } from "node:path";
|
|
51
51
|
import { fileURLToPath } from "node:url";
|
|
52
|
+
import { z } from "zod";
|
|
52
53
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
53
54
|
|
|
54
55
|
const SCRIPT = join(HERE, "round-diff.mjs");
|
|
@@ -60,7 +61,9 @@ const tmp = realpathSync(mkdtempSync(join(tmpdir(), "round-diff-harness-")));
|
|
|
60
61
|
// numbered body, a `## References` boundary and an appendix after it. The boundary is load-bearing
|
|
61
62
|
// — the ratchet must not charge for words moved into an appendix.
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
type Section =
|
|
65
|
+
"abstract" | "s1" | "s2" | "s21" | "s3" | "lim" | "refs" | "appendix";
|
|
66
|
+
const P = (o: Partial<Record<Section, string>> = {}) => `---
|
|
64
67
|
title: "A fixture"
|
|
65
68
|
---
|
|
66
69
|
|
|
@@ -108,10 +111,16 @@ function fixture({
|
|
|
108
111
|
now = null,
|
|
109
112
|
rounds = {},
|
|
110
113
|
commitRounds = false,
|
|
114
|
+
}: {
|
|
115
|
+
base?: string;
|
|
116
|
+
now?: string | null;
|
|
117
|
+
rounds?: Record<string, string>;
|
|
118
|
+
commitRounds?: boolean;
|
|
111
119
|
} = {}) {
|
|
112
|
-
const dir = join(tmp, `f${++n}`, "paper-x");
|
|
120
|
+
const dir = join(tmp, `f${String(++n)}`, "paper-x");
|
|
113
121
|
mkdirSync(dir, { recursive: true });
|
|
114
|
-
const g = (...a) =>
|
|
122
|
+
const g = (...a: string[]) =>
|
|
123
|
+
spawnSync("git", a, { cwd: dir, encoding: "utf8" });
|
|
115
124
|
g("init", "-q", "-b", "main");
|
|
116
125
|
g("config", "user.email", "h@example.com");
|
|
117
126
|
g("config", "user.name", "harness");
|
|
@@ -150,18 +159,34 @@ const M = ({
|
|
|
150
159
|
hedge,
|
|
151
160
|
closed,
|
|
152
161
|
base = "__BASE__",
|
|
162
|
+
}: {
|
|
163
|
+
round?: number;
|
|
164
|
+
touches?: readonly string[];
|
|
165
|
+
allows?: readonly string[];
|
|
166
|
+
budget?: number;
|
|
167
|
+
hedge?: number;
|
|
168
|
+
closed?: string;
|
|
169
|
+
base?: string;
|
|
153
170
|
} = {}) =>
|
|
154
171
|
`---
|
|
155
|
-
round: ${round}
|
|
172
|
+
round: ${String(round)}
|
|
156
173
|
opened: 2026-08-10
|
|
157
174
|
base: ${base}
|
|
158
175
|
touches: [${touches.map((t) => `"${t}"`).join(", ")}]
|
|
159
|
-
${allows ? `allows: [${allows.join(", ")}]\n` : ""}${budget !== undefined ? `budget: ${budget}\n` : ""}${hedge !== undefined ? `hedge-budget: ${hedge}\n` : ""}${closed ? `closed: ${closed}\n` : ""}---
|
|
176
|
+
${allows ? `allows: [${allows.join(", ")}]\n` : ""}${budget !== undefined ? `budget: ${String(budget)}\n` : ""}${hedge !== undefined ? `hedge-budget: ${String(hedge)}\n` : ""}${closed ? `closed: ${closed}\n` : ""}---
|
|
160
177
|
|
|
161
|
-
Round ${round}.
|
|
178
|
+
Round ${String(round)}.
|
|
162
179
|
`;
|
|
163
180
|
|
|
164
|
-
|
|
181
|
+
/** One finding of the gate's `--json` output, with the two fields these checks read. */
|
|
182
|
+
const Findings = z.array(z.looseObject({ kind: z.string(), msg: z.string() }));
|
|
183
|
+
type Run = {
|
|
184
|
+
findings: z.infer<typeof Findings>;
|
|
185
|
+
kinds: string[];
|
|
186
|
+
text: string;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
function run(dir: string, ...args: string[]): Run {
|
|
165
190
|
const json = spawnSync("node", [SCRIPT, dir, "--json", ...args], {
|
|
166
191
|
encoding: "utf8",
|
|
167
192
|
});
|
|
@@ -169,11 +194,11 @@ function run(dir, ...args) {
|
|
|
169
194
|
assert.equal(
|
|
170
195
|
json.status,
|
|
171
196
|
0,
|
|
172
|
-
`the gate must always exit 0 (advisory); it exited ${json.status}:\n${json.stderr}`,
|
|
197
|
+
`the gate must always exit 0 (advisory); it exited ${String(json.status)}:\n${json.stderr}`,
|
|
173
198
|
);
|
|
174
|
-
let findings
|
|
199
|
+
let findings: z.infer<typeof Findings>;
|
|
175
200
|
try {
|
|
176
|
-
findings = JSON.parse(json.stdout);
|
|
201
|
+
findings = Findings.parse(JSON.parse(json.stdout));
|
|
177
202
|
} catch {
|
|
178
203
|
throw new Error(
|
|
179
204
|
`--json did not produce JSON.\nstdout:\n${json.stdout}\nstderr:\n${json.stderr}`,
|
|
@@ -187,15 +212,16 @@ function run(dir, ...args) {
|
|
|
187
212
|
}
|
|
188
213
|
|
|
189
214
|
/** Exactly these kinds, in any order — never `.includes`, which is how a deleted check stays green. */
|
|
190
|
-
const only = (r, expected, why) =>
|
|
215
|
+
const only = (r: Run, expected: readonly string[], why: string) => {
|
|
191
216
|
assert.deepEqual(
|
|
192
217
|
[...r.kinds].sort(),
|
|
193
218
|
[...expected].sort(),
|
|
194
219
|
`${why}\n got: ${JSON.stringify(r.findings, null, 2)}`,
|
|
195
220
|
);
|
|
221
|
+
};
|
|
196
222
|
|
|
197
223
|
/** The finding of this kind must say this. A kind alone does not prove which branch produced it. */
|
|
198
|
-
const msg = (r, kind, needle, why) => {
|
|
224
|
+
const msg = (r: Run, kind: string, needle: string, why: string) => {
|
|
199
225
|
const f = r.findings.find((x) => x.kind === kind);
|
|
200
226
|
assert.ok(
|
|
201
227
|
f,
|
|
@@ -452,7 +478,7 @@ const msg = (r, kind, needle, why) => {
|
|
|
452
478
|
// paid it back — which is exactly the failure the cumulative check exists for, and exactly what a
|
|
453
479
|
// per-round gate forgets the moment the round is closed.
|
|
454
480
|
{
|
|
455
|
-
const grow = (k) =>
|
|
481
|
+
const grow = (k: number) =>
|
|
456
482
|
P({
|
|
457
483
|
s3:
|
|
458
484
|
"The direction holds across all four rules. " +
|
|
@@ -460,7 +486,8 @@ const msg = (r, kind, needle, why) => {
|
|
|
460
486
|
});
|
|
461
487
|
const dir = join(tmp, "cumulative", "paper-x");
|
|
462
488
|
mkdirSync(dir, { recursive: true });
|
|
463
|
-
const g = (...a) =>
|
|
489
|
+
const g = (...a: string[]) =>
|
|
490
|
+
spawnSync("git", a, { cwd: dir, encoding: "utf8" });
|
|
464
491
|
g("init", "-q", "-b", "main");
|
|
465
492
|
g("config", "user.email", "h@e.com");
|
|
466
493
|
g("config", "user.name", "h");
|
|
@@ -468,20 +495,20 @@ const msg = (r, kind, needle, why) => {
|
|
|
468
495
|
for (const k of [0, 10, 16]) {
|
|
469
496
|
writeFileSync(join(dir, "paper.md"), grow(k));
|
|
470
497
|
g("add", "-A");
|
|
471
|
-
g("commit", "-qm", `r${k}`);
|
|
498
|
+
g("commit", "-qm", `r${String(k)}`);
|
|
472
499
|
shas.push(g("rev-parse", "HEAD").stdout.trim());
|
|
473
500
|
}
|
|
474
501
|
writeFileSync(join(dir, "paper.md"), grow(22));
|
|
475
502
|
mkdirSync(join(dir, "rounds"), { recursive: true });
|
|
476
503
|
for (const [i, sha] of shas.entries()) {
|
|
477
504
|
writeFileSync(
|
|
478
|
-
join(dir, "rounds", `0${i + 1}.md`),
|
|
505
|
+
join(dir, "rounds", `0${String(i + 1)}.md`),
|
|
479
506
|
M({
|
|
480
507
|
round: i + 1,
|
|
481
508
|
touches: ["3"],
|
|
482
509
|
budget: 20,
|
|
483
510
|
base: sha,
|
|
484
|
-
|
|
511
|
+
...(i < 2 ? { closed: `2026-08-1${String(i)}` } : {}),
|
|
485
512
|
}),
|
|
486
513
|
);
|
|
487
514
|
}
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
import { readFileSync, existsSync, readdirSync } from "node:fs";
|
|
67
67
|
import { spawnSync } from "node:child_process";
|
|
68
68
|
import { basename, join, resolve, relative } from "node:path";
|
|
69
|
-
import { stripFrontmatter, frontmatterBlock } from "
|
|
69
|
+
import { stripFrontmatter, frontmatterBlock } from "#lib/markdown";
|
|
70
70
|
import { isMain } from "./consumer.mjs";
|
|
71
71
|
|
|
72
72
|
// ── the lexicon ──────────────────────────────────────────────────────────────────────────────
|
|
@@ -10,7 +10,7 @@ import { chmodSync } from "node:fs";
|
|
|
10
10
|
import { dirname, join } from "node:path";
|
|
11
11
|
import { fileURLToPath } from "node:url";
|
|
12
12
|
import { test } from "vitest";
|
|
13
|
-
import { runNode, useTempDir, writeTree } from "../../../test/support.
|
|
13
|
+
import { runNode, useTempDir, writeTree } from "../../../test/support.ts";
|
|
14
14
|
import { census, check, covers, parseManifest } from "./round-diff.mjs";
|
|
15
15
|
|
|
16
16
|
const SCRIPT = join(dirname(fileURLToPath(import.meta.url)), "round-diff.mjs");
|
|
@@ -4,21 +4,10 @@ description: Answer "what's the status of the paper?" in one pass — MEASURE wh
|
|
|
4
4
|
allowed-tools: [Bash, Read, Grep, Glob]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
<!-- vigiles:sha256:
|
|
7
|
+
<!-- vigiles:sha256:cdf5e1fcefdb916d compiled from skills/paper-status/SKILL.md.spec.ts -->
|
|
8
8
|
|
|
9
9
|
# paper-status — state, measured before it is narrated
|
|
10
10
|
|
|
11
|
-
## Run me
|
|
12
|
-
|
|
13
|
-
🔴 FIRST, before any other step:
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
node .claude/skills/paper-pipeline/scripts/announce.mjs paper-status <paper-dir>
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
An advisory pass cannot be observed failing — silence is both its error state and its normal
|
|
20
|
-
state — so starting is an event, and events get written down.
|
|
21
|
-
|
|
22
11
|
The author asks "what's the status there?" constantly, and the answer keeps coming from the wrong place: my
|
|
23
12
|
memory of the session, which drifts, or a 200-line scorecard he cannot skim. Both fail the same way —
|
|
24
13
|
**they narrate state instead of measuring it.**
|
|
@@ -49,18 +38,13 @@ So on any turn that touched a paper, the reply ends with **three lines, unprompt
|
|
|
49
38
|
Three failures make this a rule rather than a preference, all in one session:
|
|
50
39
|
- I finished a page-fit cut and stopped, so he asked what the status was;
|
|
51
40
|
- I left artifact hosting on his side of the split for a day and a half while the credential to clear
|
|
52
|
-
it sat in the environment
|
|
41
|
+
it sat in the environment;
|
|
53
42
|
- three consecutive panels returned Weak Accept and the ceiling they named was never the next task,
|
|
54
43
|
because nothing turned "here is the score" into "here is what to do about it".
|
|
55
44
|
|
|
56
45
|
**Never end a paper turn on a completed sub-task alone.** "Fits in 8 pages" is a measurement, not a
|
|
57
46
|
status; the status is what that measurement makes possible next.
|
|
58
47
|
|
|
59
|
-
**Enforcement leg.** `pipeline-check.mjs` prints its banner **unconditionally**, including when it has
|
|
60
|
-
zero findings — deadline countdown, verdict row, and `➡️ NEXT`. It runs from `paper-status-gates.sh`
|
|
61
|
-
on every edit to a paper source, so the state arrives without anyone pulling it. If that banner and
|
|
62
|
-
this section ever disagree, the banner is a measurement and this is prose: believe the banner.
|
|
63
|
-
|
|
64
48
|
## How to run it
|
|
65
49
|
|
|
66
50
|
### 1. Measure (no reading yet)
|
|
@@ -90,8 +74,6 @@ gate's verdict **does not describe the current paper** — say so explicitly, an
|
|
|
90
74
|
An accept-probability from a superseded draft is not evidence about this one; carrying it forward is
|
|
91
75
|
the single most common way a status report lies.
|
|
92
76
|
|
|
93
|
-
If the project ships a checker (`.claude/skills/paper-pipeline/scripts/pipeline-check.mjs`), run it.
|
|
94
|
-
|
|
95
77
|
### 3. Read the judgement rows — from BOTH checklists, they answer different questions
|
|
96
78
|
|
|
97
79
|
The project already carries the checklists this skill should report against. Do not invent a new list
|
|
@@ -126,28 +108,6 @@ Short. He is asking because he wants to decide what to do next, not to read a re
|
|
|
126
108
|
5. **What moved since he last asked**, three lines maximum.
|
|
127
109
|
6. **The deadline, in his timezone**, and what is on the critical path to it.
|
|
128
110
|
|
|
129
|
-
## Record the verdict
|
|
130
|
-
|
|
131
|
-
🔴 LAST step, once the deliverable exists:
|
|
132
|
-
|
|
133
|
-
```
|
|
134
|
-
node .claude/skills/paper-pipeline/scripts/ledger.mjs record paper-status <paper-dir> FINDING <count> <report-path>
|
|
135
|
-
node .claude/skills/paper-pipeline/scripts/ledger.mjs record paper-status <paper-dir> ABSTAINED <reason> "<one line>"
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
This skill reports state and does not judge the paper, so what it records is about the **status run**:
|
|
139
|
-
**FINDING** — `<count>` blockers printed, `<report-path>` the status output.
|
|
140
|
-
**ABSTAINED** — `no-witness`: the status run measured everything it can and printed zero blockers.
|
|
141
|
-
`crashed`: the build did not run, so nothing was measured.
|
|
142
|
-
|
|
143
|
-
🔴 `crashed` is the one outcome that must never be narrated as a status. This skill exists because
|
|
144
|
-
state was being narrated instead of measured; a status report built on a build that did not happen
|
|
145
|
-
is that same failure with a fresh timestamp on it. Under the old vocabulary this was `ERROR`, which
|
|
146
|
-
sat in the same column as a verdict about the paper — it does not any more.
|
|
147
|
-
|
|
148
|
-
🔴 **There is no PASS**, so "zero blockers" cannot be stored. Print it, and let the reader draw the
|
|
149
|
-
conclusion from an empty blocker list they can see.
|
|
150
|
-
|
|
151
111
|
## Rules
|
|
152
112
|
|
|
153
113
|
- **Never report a gate as run because I intended to run it.** Predicting a background agent's result,
|