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.
Files changed (527) hide show
  1. package/.github/workflows/ci.yml +12 -7
  2. package/CLAUDE.md +5 -5
  3. package/CONTRIBUTING.md +34 -5
  4. package/dist/adapters/banal/failure.d.ts +1 -7
  5. package/dist/adapters/banal/failure.d.ts.map +1 -1
  6. package/dist/adapters/banal/failure.js +5 -7
  7. package/dist/adapters/banal/failure.js.map +1 -1
  8. package/dist/adapters/banal/index.d.ts.map +1 -1
  9. package/dist/adapters/banal/index.js +4 -3
  10. package/dist/adapters/banal/index.js.map +1 -1
  11. package/dist/adapters/banal/install.d.ts.map +1 -1
  12. package/dist/adapters/banal/install.js +4 -3
  13. package/dist/adapters/banal/install.js.map +1 -1
  14. package/dist/adapters/banal/invocation.d.ts +10 -5
  15. package/dist/adapters/banal/invocation.d.ts.map +1 -1
  16. package/dist/adapters/banal/invocation.js +13 -1
  17. package/dist/adapters/banal/invocation.js.map +1 -1
  18. package/dist/adapters/banal/locate.d.ts +12 -9
  19. package/dist/adapters/banal/locate.d.ts.map +1 -1
  20. package/dist/adapters/banal/locate.js +19 -12
  21. package/dist/adapters/banal/locate.js.map +1 -1
  22. package/dist/adapters/banal/run.d.ts +10 -1
  23. package/dist/adapters/banal/run.d.ts.map +1 -1
  24. package/dist/adapters/banal/run.js +8 -4
  25. package/dist/adapters/banal/run.js.map +1 -1
  26. package/dist/adapters/banal/settings.d.ts +1 -1
  27. package/dist/adapters/banal/settings.d.ts.map +1 -1
  28. package/dist/adapters/banal/settings.js +2 -1
  29. package/dist/adapters/banal/settings.js.map +1 -1
  30. package/dist/adapters/memory/index.d.ts.map +1 -1
  31. package/dist/adapters/memory/index.js +8 -2
  32. package/dist/adapters/memory/index.js.map +1 -1
  33. package/dist/adapters/node/files.io.d.ts.map +1 -1
  34. package/dist/adapters/node/files.io.js +2 -1
  35. package/dist/adapters/node/files.io.js.map +1 -1
  36. package/dist/adapters/node/process.io.d.ts +5 -7
  37. package/dist/adapters/node/process.io.d.ts.map +1 -1
  38. package/dist/adapters/node/process.io.js +4 -3
  39. package/dist/adapters/node/process.io.js.map +1 -1
  40. package/dist/adapters/node/workspace.io.d.ts.map +1 -1
  41. package/dist/adapters/node/workspace.io.js +4 -2
  42. package/dist/adapters/node/workspace.io.js.map +1 -1
  43. package/dist/adapters/pdfjs/fill.d.ts.map +1 -1
  44. package/dist/adapters/pdfjs/fill.js +13 -7
  45. package/dist/adapters/pdfjs/fill.js.map +1 -1
  46. package/dist/adapters/references/index.d.ts.map +1 -1
  47. package/dist/adapters/references/index.js +8 -7
  48. package/dist/adapters/references/index.js.map +1 -1
  49. package/dist/adapters/references/pool.d.ts.map +1 -1
  50. package/dist/adapters/references/pool.js +4 -5
  51. package/dist/adapters/references/pool.js.map +1 -1
  52. package/dist/adapters/references/reach.io.d.ts.map +1 -1
  53. package/dist/adapters/references/reach.io.js +2 -1
  54. package/dist/adapters/references/reach.io.js.map +1 -1
  55. package/dist/build-engine.d.ts +1 -1
  56. package/dist/build-engine.d.ts.map +1 -1
  57. package/dist/build-engine.js +10 -3
  58. package/dist/build-engine.js.map +1 -1
  59. package/dist/build.d.ts +2 -3
  60. package/dist/build.d.ts.map +1 -1
  61. package/dist/build.js +19 -17
  62. package/dist/build.js.map +1 -1
  63. package/dist/caller-path.d.ts +3 -0
  64. package/dist/caller-path.d.ts.map +1 -0
  65. package/dist/caller-path.js +13 -0
  66. package/dist/caller-path.js.map +1 -0
  67. package/dist/cli.d.ts +10 -17
  68. package/dist/cli.d.ts.map +1 -1
  69. package/dist/cli.js +93 -46
  70. package/dist/cli.js.map +1 -1
  71. package/dist/doctor.d.ts +12 -3
  72. package/dist/doctor.d.ts.map +1 -1
  73. package/dist/doctor.js +5 -3
  74. package/dist/doctor.js.map +1 -1
  75. package/dist/domain/lookup-cache.d.ts.map +1 -1
  76. package/dist/domain/lookup-cache.js +10 -8
  77. package/dist/domain/lookup-cache.js.map +1 -1
  78. package/dist/domain/paths.d.ts +8 -2
  79. package/dist/domain/paths.d.ts.map +1 -1
  80. package/dist/domain/paths.js +12 -1
  81. package/dist/domain/paths.js.map +1 -1
  82. package/dist/domain/ready.d.ts +24 -0
  83. package/dist/domain/ready.d.ts.map +1 -0
  84. package/dist/domain/ready.js +11 -0
  85. package/dist/domain/ready.js.map +1 -0
  86. package/dist/domain/record.d.ts +8 -0
  87. package/dist/domain/record.d.ts.map +1 -0
  88. package/dist/domain/record.js +8 -0
  89. package/dist/domain/record.js.map +1 -0
  90. package/dist/domain/sha256.d.ts.map +1 -1
  91. package/dist/domain/sha256.js +4 -2
  92. package/dist/domain/sha256.js.map +1 -1
  93. package/dist/domain/text.d.ts +12 -0
  94. package/dist/domain/text.d.ts.map +1 -1
  95. package/dist/domain/text.js +17 -0
  96. package/dist/domain/text.js.map +1 -1
  97. package/dist/engine.d.ts +23 -22
  98. package/dist/engine.d.ts.map +1 -1
  99. package/dist/engine.js +4 -3
  100. package/dist/engine.js.map +1 -1
  101. package/dist/eslint-rules/bib-reachable-entry.d.ts +22 -0
  102. package/dist/eslint-rules/bib-reachable-entry.d.ts.map +1 -0
  103. package/dist/eslint-rules/bib-reachable-entry.js +75 -0
  104. package/dist/eslint-rules/bib-reachable-entry.js.map +1 -0
  105. package/dist/eslint-rules/install-path-literals.d.ts +80 -0
  106. package/dist/eslint-rules/install-path-literals.d.ts.map +1 -0
  107. package/dist/eslint-rules/install-path-literals.js +105 -0
  108. package/dist/eslint-rules/install-path-literals.js.map +1 -0
  109. package/dist/eslint-rules/latex-language.d.ts +136 -0
  110. package/dist/eslint-rules/latex-language.d.ts.map +1 -0
  111. package/dist/eslint-rules/latex-language.js +639 -0
  112. package/dist/eslint-rules/latex-language.js.map +1 -0
  113. package/dist/eslint-rules/paper-research-question.d.ts +31 -0
  114. package/dist/eslint-rules/paper-research-question.d.ts.map +1 -0
  115. package/dist/eslint-rules/paper-research-question.js +188 -0
  116. package/dist/eslint-rules/paper-research-question.js.map +1 -0
  117. package/dist/eslint-rules/paper-stages.d.ts +83 -0
  118. package/dist/eslint-rules/paper-stages.d.ts.map +1 -0
  119. package/dist/eslint-rules/paper-stages.js +358 -0
  120. package/dist/eslint-rules/paper-stages.js.map +1 -0
  121. package/dist/eslint-rules/paper-typography.d.ts +74 -0
  122. package/dist/eslint-rules/paper-typography.d.ts.map +1 -0
  123. package/dist/eslint-rules/paper-typography.js +404 -0
  124. package/dist/eslint-rules/paper-typography.js.map +1 -0
  125. package/dist/eslint-rules/papers.d.ts +42 -0
  126. package/dist/eslint-rules/papers.d.ts.map +1 -0
  127. package/dist/eslint-rules/papers.js +145 -0
  128. package/dist/eslint-rules/papers.js.map +1 -0
  129. package/dist/eslint-rules/pdf-last-page-balance.d.ts +72 -0
  130. package/dist/eslint-rules/pdf-last-page-balance.d.ts.map +1 -0
  131. package/dist/eslint-rules/pdf-last-page-balance.js +237 -0
  132. package/dist/eslint-rules/pdf-last-page-balance.js.map +1 -0
  133. package/dist/eslint-rules/review-frontmatter.d.ts +57 -0
  134. package/dist/eslint-rules/review-frontmatter.d.ts.map +1 -0
  135. package/dist/eslint-rules/review-frontmatter.js +126 -0
  136. package/dist/eslint-rules/review-frontmatter.js.map +1 -0
  137. package/dist/eslint-rules/review-frontmatter.schema.json +36 -0
  138. package/dist/eslint-rules/rule-context.d.ts +55 -0
  139. package/dist/eslint-rules/rule-context.d.ts.map +1 -0
  140. package/dist/eslint-rules/rule-context.js +9 -0
  141. package/dist/eslint-rules/rule-context.js.map +1 -0
  142. package/dist/eslint-rules/sibling-frontmatter.d.ts +25 -0
  143. package/dist/eslint-rules/sibling-frontmatter.d.ts.map +1 -0
  144. package/dist/eslint-rules/sibling-frontmatter.js +16 -0
  145. package/dist/eslint-rules/sibling-frontmatter.js.map +1 -0
  146. package/dist/eslint-rules/sibling-frontmatter.schema.json +14 -0
  147. package/dist/eslint-rules/temp-root-realpath.d.ts +71 -0
  148. package/dist/eslint-rules/temp-root-realpath.d.ts.map +1 -0
  149. package/dist/eslint-rules/temp-root-realpath.js +139 -0
  150. package/dist/eslint-rules/temp-root-realpath.js.map +1 -0
  151. package/dist/eslint-rules/tex-build.d.ts +35 -0
  152. package/dist/eslint-rules/tex-build.d.ts.map +1 -0
  153. package/dist/eslint-rules/tex-build.js +313 -0
  154. package/dist/eslint-rules/tex-build.js.map +1 -0
  155. package/dist/facts-file.d.ts.map +1 -1
  156. package/dist/facts-file.js +31 -27
  157. package/dist/facts-file.js.map +1 -1
  158. package/dist/hooks-settings.d.ts +1 -1
  159. package/dist/hooks-settings.d.ts.map +1 -1
  160. package/dist/hooks-settings.js +31 -11
  161. package/dist/hooks-settings.js.map +1 -1
  162. package/dist/init.d.ts +8 -9
  163. package/dist/init.d.ts.map +1 -1
  164. package/dist/init.js +33 -15
  165. package/dist/init.js.map +1 -1
  166. package/dist/latex-loop.d.ts +2 -2
  167. package/dist/latex-loop.d.ts.map +1 -1
  168. package/dist/latex-loop.js +2 -2
  169. package/dist/latex-loop.js.map +1 -1
  170. package/dist/lib/agent-cli-version.d.ts +65 -0
  171. package/dist/lib/agent-cli-version.d.ts.map +1 -0
  172. package/dist/lib/agent-cli-version.js +77 -0
  173. package/dist/lib/agent-cli-version.js.map +1 -0
  174. package/dist/lib/check.d.ts +19 -0
  175. package/dist/lib/check.d.ts.map +1 -0
  176. package/dist/lib/check.js +52 -0
  177. package/dist/lib/check.js.map +1 -0
  178. package/dist/lib/markdown.d.ts +180 -0
  179. package/dist/lib/markdown.d.ts.map +1 -0
  180. package/dist/lib/markdown.js +302 -0
  181. package/dist/lib/markdown.js.map +1 -0
  182. package/dist/lib/paper-config.d.ts +84 -0
  183. package/dist/lib/paper-config.d.ts.map +1 -0
  184. package/dist/lib/paper-config.js +138 -0
  185. package/dist/lib/paper-config.js.map +1 -0
  186. package/dist/lib/skill-eval-fixture.d.ts +29 -0
  187. package/dist/lib/skill-eval-fixture.d.ts.map +1 -0
  188. package/dist/lib/skill-eval-fixture.js +62 -0
  189. package/dist/lib/skill-eval-fixture.js.map +1 -0
  190. package/dist/link-skills.d.ts.map +1 -1
  191. package/dist/link-skills.js +5 -4
  192. package/dist/link-skills.js.map +1 -1
  193. package/dist/new-paper.d.ts.map +1 -1
  194. package/dist/new-paper.js +7 -3
  195. package/dist/new-paper.js.map +1 -1
  196. package/dist/paper-files.d.ts +4 -4
  197. package/dist/paper-files.d.ts.map +1 -1
  198. package/dist/paper-files.js +6 -6
  199. package/dist/paper-files.js.map +1 -1
  200. package/dist/paper-settings.d.ts.map +1 -1
  201. package/dist/paper-settings.js +8 -7
  202. package/dist/paper-settings.js.map +1 -1
  203. package/dist/pdf-facts.d.ts +51 -1
  204. package/dist/pdf-facts.d.ts.map +1 -1
  205. package/dist/pdf-facts.js +25 -16
  206. package/dist/pdf-facts.js.map +1 -1
  207. package/dist/pdf-geometry.d.ts.map +1 -1
  208. package/dist/pdf-geometry.js +3 -4
  209. package/dist/pdf-geometry.js.map +1 -1
  210. package/dist/ports/tool-installer.d.ts +2 -14
  211. package/dist/ports/tool-installer.d.ts.map +1 -1
  212. package/dist/presets.d.ts.map +1 -1
  213. package/dist/presets.js +19 -6
  214. package/dist/presets.js.map +1 -1
  215. package/dist/references.d.ts.map +1 -1
  216. package/dist/references.js +15 -10
  217. package/dist/references.js.map +1 -1
  218. package/dist/rules-config.d.ts +26 -1
  219. package/dist/rules-config.d.ts.map +1 -1
  220. package/dist/rules-config.js +15 -12
  221. package/dist/rules-config.js.map +1 -1
  222. package/dist/structure.js +1 -1
  223. package/dist/structure.js.map +1 -1
  224. package/dist/tex-requirements.d.ts +4 -0
  225. package/dist/tex-requirements.d.ts.map +1 -1
  226. package/dist/tex-requirements.js +22 -5
  227. package/dist/tex-requirements.js.map +1 -1
  228. package/dist/toolchain.d.ts.map +1 -1
  229. package/dist/toolchain.js +21 -16
  230. package/dist/toolchain.js.map +1 -1
  231. package/dist/types.d.ts +5 -3
  232. package/dist/types.d.ts.map +1 -1
  233. package/dist/venue-rules.d.ts.map +1 -1
  234. package/dist/venue-rules.js +21 -8
  235. package/dist/venue-rules.js.map +1 -1
  236. package/docs/configuration.md +2 -2
  237. package/docs/e2e.md +7 -7
  238. package/docs/install.md +1 -1
  239. package/docs/prior-art/README.md +1 -1
  240. package/docs/prior-art/package-location.md +5 -5
  241. package/docs/prior-art/repro/README.md +1 -1
  242. package/docs/prior-art/test-tooling.md +2 -2
  243. package/docs/testing.md +11 -8
  244. package/docs/toolchain.md +1 -1
  245. package/eslint-rules/{bib-reachable-entry.mjs → bib-reachable-entry.ts} +5 -4
  246. package/eslint-rules/install-path-literals.harness.mjs +1 -1
  247. package/eslint-rules/{install-path-literals.mjs → install-path-literals.ts} +18 -10
  248. package/eslint-rules/latex-language.harness.mjs +2 -2
  249. package/eslint-rules/latex-language.test.mjs +7 -1
  250. package/eslint-rules/{latex-language.mjs → latex-language.ts} +297 -109
  251. package/eslint-rules/paper-research-question.harness.mjs +3 -3
  252. package/eslint-rules/{paper-research-question.mjs → paper-research-question.ts} +35 -16
  253. package/eslint-rules/paper-stages.harness.mjs +2 -2
  254. package/eslint-rules/paper-stages.test.mjs +8 -2
  255. package/eslint-rules/{paper-stages.mjs → paper-stages.ts} +76 -31
  256. package/eslint-rules/paper-typography.test.mjs +3 -3
  257. package/eslint-rules/{paper-typography.mjs → paper-typography.ts} +134 -56
  258. package/eslint-rules/papers.harness.mjs +2 -2
  259. package/eslint-rules/{papers.mjs → papers.ts} +7 -4
  260. package/eslint-rules/pdf-last-page-balance.harness.mjs +3 -3
  261. package/eslint-rules/{pdf-last-page-balance.mjs → pdf-last-page-balance.ts} +89 -32
  262. package/eslint-rules/review-frontmatter.test.mjs +2 -2
  263. package/eslint-rules/{review-frontmatter.mjs → review-frontmatter.ts} +38 -16
  264. package/eslint-rules/rule-context.ts +62 -0
  265. package/eslint-rules/{sibling-frontmatter.mjs → sibling-frontmatter.ts} +1 -1
  266. package/eslint-rules/temp-root-realpath.harness.mjs +1 -1
  267. package/eslint-rules/{temp-root-realpath.mjs → temp-root-realpath.ts} +20 -7
  268. package/eslint-rules/tex-build.harness.mjs +2 -2
  269. package/eslint-rules/{tex-build.mjs → tex-build.ts} +6 -5
  270. package/eslint.config.mjs +146 -30
  271. package/fixtures/install-path-literals/clean.fixture.mjs +1 -1
  272. package/fixtures/install-path-literals/clean.md +2 -2
  273. package/fixtures/install-path-literals/defect.fixture.mjs +1 -1
  274. package/fixtures/install-path-literals/defect.md +2 -2
  275. package/fixtures/pdf-facts/README.md +2 -2
  276. package/fixtures/real-markdown-paper/{baseline.mjs → baseline.ts} +31 -10
  277. package/hooks/{hooks.harness.mjs → hooks.harness.ts} +51 -34
  278. package/hooks/paper-edit-guard.hook.mjs +1 -1
  279. package/hooks/{paper-edit-guard.test.mjs → paper-edit-guard.test.ts} +3 -7
  280. package/hooks/paper-skills-nudge.hook.mjs +1 -1
  281. package/hooks/{paper-skills-nudge.test.mjs → paper-skills-nudge.test.ts} +2 -6
  282. package/hooks/paper-status-gates.sh +9 -19
  283. package/hooks/{paper-status-gates.test.mjs → paper-status-gates.test.ts} +2 -6
  284. package/lib/agent-cli-version.harness.mjs +1 -1
  285. package/lib/{agent-cli-version.mjs → agent-cli-version.ts} +32 -18
  286. package/lib/check.test.ts +14 -9
  287. package/lib/{check.mjs → check.ts} +22 -9
  288. package/lib/markdown.test.mjs +7 -7
  289. package/lib/{markdown.mjs → markdown.ts} +68 -29
  290. package/lib/paper-config.harness.mjs +9 -9
  291. package/lib/{paper-config.mjs → paper-config.ts} +20 -19
  292. package/lib/skill-checks.mjs +24 -381
  293. package/lib/skill-checks.test.mjs +64 -116
  294. package/lib/skill-corpus.mjs +10 -251
  295. package/lib/skill-corpus.test.mjs +2 -13
  296. package/lib/skill-eval-kit.mjs +1 -1
  297. package/lib/skill-trigger-cases.mjs +1 -1
  298. package/package.json +42 -10
  299. package/scripts/{check.harness.mjs → check.harness.ts} +111 -10
  300. package/scripts/{check.test.mjs → check.test.ts} +13 -10
  301. package/scripts/{check.mjs → check.ts} +116 -42
  302. package/scripts/coverage-config.test.ts +80 -38
  303. package/scripts/eslint-report-guard.test.mjs +1 -1
  304. package/scripts/harness-api.frozen.json +14 -16
  305. package/scripts/harness-api.test.ts +8 -5
  306. package/scripts/layer-legacy-frozen.test.ts +17 -13
  307. package/scripts/{layer-legacy-frozen.mjs → layer-legacy-frozen.ts} +128 -39
  308. package/scripts/release-config.test.ts +12 -4
  309. package/scripts/rules-see-files.test.mjs +1 -1
  310. package/scripts/test.test.ts +78 -0
  311. package/scripts/test.ts +87 -0
  312. package/skills/analyze-sibling-paper/SKILL.md +1 -39
  313. package/skills/analyze-sibling-paper/SKILL.md.spec.ts +0 -38
  314. package/skills/argument-arc/SKILL.md +2 -36
  315. package/skills/argument-arc/SKILL.md.spec.ts +1 -43
  316. package/skills/build-benchmark/SKILL.md +1 -41
  317. package/skills/build-benchmark/SKILL.md.spec.ts +0 -40
  318. package/skills/camera-ready/SKILL.md +1 -34
  319. package/skills/camera-ready/SKILL.md.spec.ts +0 -33
  320. package/skills/cold-read-diff/SKILL.md +1 -35
  321. package/skills/cold-read-diff/SKILL.md.spec.ts +0 -34
  322. package/skills/draft-paper/SKILL.md +2 -41
  323. package/skills/draft-paper/SKILL.md.spec.ts +1 -50
  324. package/skills/extend-paper/SKILL.md +2 -33
  325. package/skills/extend-paper/SKILL.md.spec.ts +1 -42
  326. package/skills/find-venue/SKILL.md +2 -38
  327. package/skills/find-venue/SKILL.md.spec.ts +1 -47
  328. package/skills/grade-paper-writing/SKILL.md +3 -38
  329. package/skills/grade-paper-writing/SKILL.md.spec.ts +2 -47
  330. package/skills/grade-paper-writing/prose-lint.mjs +3 -4
  331. package/skills/grade-paper-writing/{prose-lint.test.mjs → prose-lint.test.ts} +3 -3
  332. package/skills/harden-paper/SKILL.md +1 -39
  333. package/skills/harden-paper/SKILL.md.spec.ts +0 -38
  334. package/skills/map-prior-work/SKILL.md +1 -35
  335. package/skills/map-prior-work/SKILL.md.spec.ts +0 -34
  336. package/skills/osf-artifact-upload/{osf-artifact-upload.harness.mjs → osf-artifact-upload.harness.ts} +3 -4
  337. package/skills/paper-adversarial-review/SKILL.md +2 -35
  338. package/skills/paper-adversarial-review/SKILL.md.spec.ts +1 -43
  339. package/skills/paper-pipeline/SKILL.md +2 -28
  340. package/skills/paper-pipeline/SKILL.md.spec.ts +1 -27
  341. package/skills/paper-pipeline/description-language.eval.mjs +1 -1
  342. package/skills/paper-pipeline/framing-vs-vocabulary.eval.mjs +1 -1
  343. package/skills/paper-pipeline/grade-paper-writing-ablation.eval.mjs +2 -2
  344. package/skills/paper-pipeline/paper-pipeline.harness.mjs +25 -40
  345. package/skills/paper-pipeline/pipeline-firing.eval.mjs +1 -1
  346. package/skills/paper-pipeline/pipeline-language.eval.mjs +1 -1
  347. package/skills/paper-pipeline/references/acceptance-gate.md +1 -6
  348. package/skills/paper-pipeline/references/pipeline-status-template.md +8 -35
  349. package/skills/paper-pipeline/scripts/README.md +30 -225
  350. package/skills/paper-pipeline/scripts/artifact-coverage.harness.mjs +4 -8
  351. package/skills/paper-pipeline/scripts/artifact-coverage.mjs +1 -1
  352. package/skills/paper-pipeline/scripts/{artifact-coverage.test.mjs → artifact-coverage.test.ts} +2 -2
  353. package/skills/paper-pipeline/scripts/consumer.harness.mjs +6 -104
  354. package/skills/paper-pipeline/scripts/consumer.mjs +24 -109
  355. package/skills/paper-pipeline/scripts/consumer.test.mjs +1 -1
  356. package/skills/paper-pipeline/scripts/extract-ref-facts.harness.mjs +1 -1
  357. package/skills/paper-pipeline/scripts/extract-ref-facts.mjs +1 -4
  358. package/skills/paper-pipeline/scripts/extract-ref-facts.test.mjs +1 -1
  359. package/skills/paper-pipeline/scripts/generated-code.harness.mjs +2 -3
  360. package/skills/paper-pipeline/scripts/{generated-code.test.mjs → generated-code.test.ts} +3 -3
  361. package/skills/paper-pipeline/scripts/population-map.harness.mjs +3 -3
  362. package/skills/paper-pipeline/scripts/population-map.mjs +1 -4
  363. package/skills/paper-pipeline/scripts/population-map.test.mjs +1 -1
  364. package/skills/paper-pipeline/scripts/{round-diff.harness.mjs → round-diff.harness.ts} +45 -18
  365. package/skills/paper-pipeline/scripts/round-diff.mjs +1 -1
  366. package/skills/paper-pipeline/scripts/round-diff.test.mjs +1 -1
  367. package/skills/paper-status/SKILL.md +2 -42
  368. package/skills/paper-status/SKILL.md.spec.ts +1 -41
  369. package/skills/pc-panel-review/SKILL.md +2 -46
  370. package/skills/pc-panel-review/SKILL.md.spec.ts +1 -45
  371. package/skills/plan-paper-timeline/SKILL.md +2 -36
  372. package/skills/plan-paper-timeline/SKILL.md.spec.ts +0 -36
  373. package/skills/plan-paper-timeline/fixtures/{fake-google-calendar.mjs → fake-google-calendar.ts} +101 -70
  374. package/skills/plan-paper-timeline/plan-paper-timeline.effects.harness.mjs +3 -3
  375. package/skills/render-paper/SKILL.md +1 -37
  376. package/skills/render-paper/SKILL.md.spec.ts +0 -36
  377. package/skills/render-paper/{extract-pdf-facts.harness.mjs → extract-pdf-facts.harness.ts} +34 -9
  378. package/skills/render-paper/render-paper.harness.mjs +2 -2
  379. package/skills/research-ideate/SKILL.md +2 -39
  380. package/skills/research-ideate/SKILL.md.spec.ts +1 -47
  381. package/skills/study-accepted-papers/SKILL.md +1 -34
  382. package/skills/study-accepted-papers/SKILL.md.spec.ts +0 -33
  383. package/skills/submit-paper/SKILL.md +1 -33
  384. package/skills/submit-paper/SKILL.md.spec.ts +0 -32
  385. package/skills/sweep-design-space/SKILL.md +1 -38
  386. package/skills/sweep-design-space/SKILL.md.spec.ts +0 -37
  387. package/skills/tighten-paper/SKILL.md +2 -39
  388. package/skills/tighten-paper/SKILL.md.spec.ts +1 -47
  389. package/skills/tighten-paper/structure.mjs +5 -12
  390. package/skills/tighten-paper/{structure.test.mjs → structure.test.ts} +4 -3
  391. package/skills/verify-citations/SKILL.md +2 -38
  392. package/skills/verify-citations/SKILL.md.spec.ts +1 -37
  393. package/skills/verify-citations/scripts/{bib-authors.cli.test.mjs → bib-authors.cli.test.ts} +14 -4
  394. package/skills/verify-citations/scripts/bib-authors.d.mts +63 -0
  395. package/skills/verify-citations/scripts/bib-authors.mjs +1 -4
  396. package/skills/verify-citations/scripts/{verify-cites.cli.test.mjs → verify-cites.cli.test.ts} +32 -9
  397. package/skills/verify-citations/scripts/verify-cites.d.mts +58 -0
  398. package/src/CLAUDE.md +1 -1
  399. package/src/adapters/banal/failure.ts +9 -10
  400. package/src/adapters/banal/index.test.ts +5 -8
  401. package/src/adapters/banal/index.ts +8 -7
  402. package/src/adapters/banal/install.ts +9 -4
  403. package/src/adapters/banal/invocation.test.ts +23 -9
  404. package/src/adapters/banal/invocation.ts +24 -9
  405. package/src/adapters/banal/locate.test.ts +2 -2
  406. package/src/adapters/banal/locate.ts +27 -21
  407. package/src/adapters/banal/output.test.ts +1 -1
  408. package/src/adapters/banal/run.test.ts +5 -5
  409. package/src/adapters/banal/run.ts +16 -10
  410. package/src/adapters/banal/settings.ts +2 -2
  411. package/src/adapters/banal/xml.test.ts +1 -1
  412. package/src/adapters/curl/download.test.ts +8 -6
  413. package/src/adapters/memory/index.ts +4 -3
  414. package/src/adapters/node/files.io.ts +2 -2
  415. package/src/adapters/node/files.test.ts +8 -4
  416. package/src/adapters/node/process.io.ts +13 -5
  417. package/src/adapters/node/process.test.ts +5 -5
  418. package/src/adapters/node/workspace.io.ts +9 -4
  419. package/src/adapters/node/workspace.test.ts +3 -1
  420. package/src/adapters/pdfjs/fill.test.ts +2 -2
  421. package/src/adapters/pdfjs/fill.ts +14 -7
  422. package/src/adapters/references/index.test.ts +31 -38
  423. package/src/adapters/references/index.ts +33 -60
  424. package/src/adapters/references/pool.ts +3 -5
  425. package/src/adapters/references/reach.io.ts +2 -1
  426. package/src/build-engine.harness.mjs +1 -1
  427. package/src/build-engine.test.ts +13 -8
  428. package/src/build-engine.ts +12 -7
  429. package/src/build.harness.mjs +2 -2
  430. package/src/build.test.ts +24 -24
  431. package/src/build.ts +34 -26
  432. package/src/caller-path.ts +13 -0
  433. package/src/cli.harness.mjs +6 -8
  434. package/src/cli.test.ts +31 -13
  435. package/src/cli.ts +117 -58
  436. package/src/doctor.harness.mjs +3 -3
  437. package/src/doctor.test.ts +1 -1
  438. package/src/doctor.ts +17 -7
  439. package/src/domain/lookup-cache.ts +21 -11
  440. package/src/domain/paths.test.ts +15 -0
  441. package/src/domain/paths.ts +20 -1
  442. package/src/domain/ready.ts +31 -0
  443. package/src/domain/record.test.ts +20 -0
  444. package/src/domain/record.ts +12 -0
  445. package/src/domain/result.test.ts +2 -2
  446. package/src/domain/sha256.ts +5 -3
  447. package/src/domain/text.test.ts +32 -0
  448. package/src/domain/text.ts +23 -0
  449. package/src/engine.harness.mjs +2 -2
  450. package/src/engine.ts +34 -5
  451. package/src/facts-file.test.ts +9 -7
  452. package/src/facts-file.ts +45 -29
  453. package/src/{hooks-settings.harness.mjs → hooks-settings.harness.ts} +56 -20
  454. package/src/hooks-settings.ts +48 -13
  455. package/src/init.test.ts +37 -14
  456. package/src/init.ts +48 -24
  457. package/src/{latex-log.harness.mjs → latex-log.harness.ts} +14 -14
  458. package/src/{latex-loop.harness.mjs → latex-loop.harness.ts} +64 -36
  459. package/src/latex-loop.ts +3 -3
  460. package/src/{link-skills.harness.mjs → link-skills.harness.ts} +19 -19
  461. package/src/link-skills.test.ts +3 -3
  462. package/src/link-skills.ts +5 -4
  463. package/src/lint-fix.test.ts +4 -6
  464. package/src/linted-set.test.ts +2 -2
  465. package/src/new-paper.harness.mjs +9 -25
  466. package/src/new-paper.test.ts +8 -10
  467. package/src/new-paper.ts +9 -5
  468. package/src/paper-files.test.ts +25 -24
  469. package/src/paper-files.ts +16 -27
  470. package/src/paper-settings-commands.test.ts +5 -4
  471. package/src/paper-settings.test.ts +7 -7
  472. package/src/paper-settings.ts +13 -14
  473. package/src/{pdf-facts.harness.mjs → pdf-facts.harness.ts} +9 -8
  474. package/src/pdf-facts.test.ts +25 -15
  475. package/src/pdf-facts.ts +81 -23
  476. package/src/{pdf-geometry.harness.mjs → pdf-geometry.harness.ts} +19 -12
  477. package/src/pdf-geometry.ts +8 -4
  478. package/src/ports/tool-installer.ts +2 -17
  479. package/src/presets.ts +31 -16
  480. package/src/references.test.ts +76 -62
  481. package/src/references.ts +18 -12
  482. package/src/{rules-config.harness.mjs → rules-config.harness.ts} +7 -13
  483. package/src/rules-config.ts +46 -14
  484. package/src/rules-off.test.ts +6 -4
  485. package/src/{structure.harness.mjs → structure.harness.ts} +26 -15
  486. package/src/structure.ts +1 -1
  487. package/src/{tex-requirements.harness.mjs → tex-requirements.harness.ts} +50 -22
  488. package/src/tex-requirements.test.ts +21 -0
  489. package/src/tex-requirements.ts +37 -11
  490. package/src/toolchain.harness.mjs +2 -2
  491. package/src/toolchain.test.ts +10 -6
  492. package/src/toolchain.ts +31 -17
  493. package/src/types.ts +5 -3
  494. package/src/venue-rules.test.ts +70 -68
  495. package/src/venue-rules.ts +22 -12
  496. package/tsconfig.json +6 -3
  497. package/tsconfig.pkg.json +10 -0
  498. package/lib/check.d.mts +0 -17
  499. package/lib/paper-config.d.mts +0 -31
  500. package/scripts/layer-legacy-frozen.d.mts +0 -36
  501. package/scripts/rules-are-content-only.harness.mjs +0 -105
  502. package/scripts/rules-are-content-only.mjs +0 -148
  503. package/scripts/rules-are-content-only.test.mjs +0 -61
  504. package/scripts/test.mjs +0 -44
  505. package/scripts/test.test.mjs +0 -52
  506. package/skills/paper-pipeline/scripts/announce.mjs +0 -67
  507. package/skills/paper-pipeline/scripts/announce.test.mjs +0 -102
  508. package/skills/paper-pipeline/scripts/fixtures/clean/PIPELINE-STATUS.md +0 -51
  509. package/skills/paper-pipeline/scripts/fixtures/dirty/PIPELINE-STATUS.md +0 -52
  510. package/skills/paper-pipeline/scripts/fixtures/dirty/paper.md +0 -6
  511. package/skills/paper-pipeline/scripts/fixtures/scorecard.mjs +0 -71
  512. package/skills/paper-pipeline/scripts/ledger.cli.test.mjs +0 -302
  513. package/skills/paper-pipeline/scripts/ledger.mjs +0 -623
  514. package/skills/paper-pipeline/scripts/ledger.test.mjs +0 -254
  515. package/skills/paper-pipeline/scripts/pipeline-check.cli.test.mjs +0 -474
  516. package/skills/paper-pipeline/scripts/pipeline-check.harness.mjs +0 -328
  517. package/skills/paper-pipeline/scripts/pipeline-check.mjs +0 -753
  518. package/skills/paper-pipeline/scripts/pipeline-edges.mjs +0 -169
  519. package/skills/paper-pipeline/scripts/pipeline-edges.test.mjs +0 -73
  520. package/skills/paper-pipeline/scripts/run-mechanical.mjs +0 -648
  521. package/skills/paper-pipeline/scripts/run-mechanical.test.mjs +0 -468
  522. package/skills/paper-pipeline/scripts/status.mjs +0 -295
  523. package/skills/paper-pipeline/scripts/status.test.mjs +0 -232
  524. /package/bin/{paperlint.test.mjs → paperlint.test.ts} +0 -0
  525. /package/lib/{skill-eval-fixture.mjs → skill-eval-fixture.ts} +0 -0
  526. /package/skills/grade-paper-writing/__snapshots__/{prose-lint.test.mjs.snap → prose-lint.test.ts.snap} +0 -0
  527. /package/skills/tighten-paper/__snapshots__/{structure.test.mjs.snap → structure.test.ts.snap} +0 -0
@@ -1,148 +0,0 @@
1
- /**
2
- * A RULE MAY NOT ASK GIT.
3
- *
4
- * 🔴 The defect it exists for, measured 2026-09-16. `paper/source` bound a paper's stage to a
5
- * commit sha and verified it with `git cat-file -e`. Of four shas recorded in the consumer's
6
- * front matter, ONE still resolved ninety minutes later: a squash-merge had orphaned the branch
7
- * commits and `gc` collected them. A recorded sha is a pointer to a pointer, and both hops are
8
- * removed by ROUTINE maintenance — squash, rebase, gc, force-push, filter-repo. Nobody is at
9
- * fault, so nobody is on the hook to fix it; the rule simply turns red and gets switched off.
10
- *
11
- * ── THE STRONGER LEG, AND THE REASON THIS IS A FLOOR CHECK ──────────────────
12
- * `actions/checkout` defaults to `fetch-depth: 1` — exactly one commit. Measured in the
13
- * consumer the same day: six checkouts, not one override. So a git-reading rule does not
14
- * resolve even a LIVE sha under CI, which is the one place it has to hold. Locally it stays
15
- * green, so the failure is one-directional and in the flattering direction.
16
- *
17
- * ── WHAT IT CHECKS, AND WHY NOT A GREP ──────────────────────────────────────
18
- * A `child_process` spawner called with `git` as the program, read from the AST. Parsed, not
19
- * grepped, so the words `git cat-file` in this very comment are not a finding — a text guard
20
- * would have to exempt itself, which is the failure mode that makes text guards unmaintainable.
21
- *
22
- * ⚠️ THE BOUND, stated so the check is not mistaken for more than it is. Two things pass: a
23
- * rule that opens `.git/` with `fs` (indistinguishable at this level from reading a data file),
24
- * and a rule that assembles the program name at runtime. Both accepted deliberately — see the
25
- * note on `SPAWNERS` for the false positive that forced the predicate this narrow.
26
- *
27
- * Run: `node scripts/rules-are-content-only.mjs` (exit 1 and a named rule on a finding)
28
- * Tested by: `scripts/rules-are-content-only.harness.mjs` — quiet on the real corpus, firing on
29
- * a planted rule.
30
- */
31
- import { existsSync, readdirSync, readFileSync } from "node:fs";
32
- import { join } from "node:path";
33
- import { parse } from "espree";
34
- import { isMain } from "../skills/paper-pipeline/scripts/consumer.mjs";
35
-
36
- /**
37
- * 🔴 THE PREDICATE IS "RUNS GIT", NOT "SPAWNS A PROCESS", and the narrowing was forced by a
38
- * FALSE POSITIVE on the consumer's corpus the hour this check shipped: `paper-texcount.mjs`
39
- * shells out to `texcount` to count words in a .tex, which is a measuring tool, not history.
40
- * A false positive on an `error` gate is worse than a miss — the gate that cannot be cleared
41
- * gets switched off, and this one would have been switched off on its first run.
42
- *
43
- * ⚠️ THE COST OF NARROWING, stated rather than hidden: a rule that builds the program name at
44
- * runtime (`const g = "gi" + "t"`) passes. That is accepted. The defect has taken exactly one
45
- * form — a literal `git` handed to a `child_process` function — and a check that also caught
46
- * the contrived form would have to claim every spawn, which is the false positive above.
47
- */
48
- const SPAWNERS = new Set([
49
- "exec",
50
- "execSync",
51
- "execFile",
52
- "execFileSync",
53
- "spawn",
54
- "spawnSync",
55
- "fork",
56
- ]);
57
-
58
- /** `"git"` as the program, or `"git …"` as the head of a shell line handed to `exec`. */
59
- const isGit = (v) =>
60
- typeof v === "string" && (v === "git" || v.startsWith("git "));
61
-
62
- /** Rule sources only: a harness plants defects on purpose and asserts about them. */
63
- const isRuleSource = (f) => f.endsWith(".mjs") && !f.endsWith(".harness.mjs");
64
-
65
- /** @param {string} src @returns {string[]} the git invocations this source makes */
66
- export function processImports(src) {
67
- const ast = parse(src, {
68
- ecmaVersion: "latest",
69
- sourceType: "module",
70
- range: false,
71
- });
72
- const found = [];
73
- const walk = (n) => {
74
- if (n === null || typeof n !== "object") return;
75
- if (Array.isArray(n)) return n.forEach(walk);
76
- // Both spellings of the callee: `execFileSync(…)` after a named import, and
77
- // `cp.execFileSync(…)` after a namespace import. Listed, not described — the node types a
78
- // check walks are the only honest statement of its coverage.
79
- if (n.type === "CallExpression") {
80
- const name =
81
- n.callee?.type === "MemberExpression"
82
- ? n.callee.property?.name
83
- : n.callee?.name;
84
- if (SPAWNERS.has(String(name)) && isGit(n.arguments?.[0]?.value))
85
- found.push(String(n.arguments[0].value));
86
- }
87
- for (const k of Object.keys(n)) if (k !== "parent") walk(n[k]);
88
- };
89
- walk(ast);
90
- return found;
91
- }
92
-
93
- /** @param {{cwd: string}} options */
94
- export function rulesAreContentOnly({ cwd }) {
95
- const dir = join(cwd, "eslint-rules");
96
- const checked = [];
97
- const findings = [];
98
- // A repository with no `eslint-rules/` has no rule sources: `checked` stays empty and the gate
99
- // says so by name. `readdirSync` would throw ENOENT instead — a stack trace, not the refusal.
100
- const names = existsSync(dir) ? readdirSync(dir) : [];
101
- for (const f of names.filter(isRuleSource)) {
102
- const hits = processImports(readFileSync(join(dir, f), "utf8"));
103
- // 🔴 The counter increments WITH the verdict, not before it: a `checked` that keeps
104
- // counting while the verdict stops being reached is the failure recorded in the consumer's
105
- // rules as "a counter that counts what it ignores".
106
- checked.push(f);
107
- for (const h of hits) findings.push({ file: f, specifier: h });
108
- }
109
- return { checked, findings };
110
- }
111
-
112
- /**
113
- * The gate over `cwd`'s `eslint-rules/`: exit 1 on no rule sources (a silent zero would read as
114
- * clean) or on any rule asking git; 0 otherwise.
115
- *
116
- * 🔴 `cwd` is `process.cwd()`, NOT the package root. A consumer installs this package and runs the
117
- * script from its own repository, where the rules that matter are ITS `eslint-rules/` — the
118
- * package's own are already checked by the package's own gate. Anchored to the package root the
119
- * consumer's gate would re-check the same eight files and report a confident zero about rules it
120
- * never opened: a counter that counts what it ignores.
121
- */
122
- export function main({
123
- cwd = process.cwd(),
124
- log = console.log,
125
- err = console.error,
126
- } = {}) {
127
- const { checked, findings } = rulesAreContentOnly({ cwd });
128
- if (checked.length === 0) {
129
- err(
130
- `${join(cwd, "eslint-rules")}: no rule sources. Either this is not a repository with ` +
131
- `ESLint rules, or the directory moved — a silent zero here would read as a clean run.`,
132
- );
133
- return 1;
134
- }
135
- for (const { file, specifier } of findings) {
136
- err(
137
- `${file}: imports \`${specifier}\`. A rule may not ask git: history is rewritten by ` +
138
- `routine maintenance and CI clones one commit deep, so the fact does not survive where ` +
139
- `the rule has to hold. Put the fact on disk and check it by bytes.`,
140
- );
141
- }
142
- log(
143
- `rules-are-content-only: ${checked.length} rule sources under ${cwd}, ${findings.length} findings`,
144
- );
145
- return findings.length === 0 ? 0 : 1;
146
- }
147
-
148
- if (isMain(import.meta.url)) process.exit(main());
@@ -1,61 +0,0 @@
1
- /**
2
- * rules-are-content-only's gate over a consumer's `eslint-rules/`: temp trees with planted rules.
3
- */
4
- import assert from "node:assert/strict";
5
- import { fileURLToPath } from "node:url";
6
- import { spawnSync } from "node:child_process";
7
- import { test } from "vitest";
8
- import { useTempDir, writeTree } from "../test/support.mjs";
9
- import { main as contentMain } from "./rules-are-content-only.mjs";
10
-
11
- const capture = () => {
12
- const out = [];
13
- const io = { log: (s) => out.push(s), err: (s) => out.push(`E ${s}`) };
14
- return { out, io };
15
- };
16
-
17
- const root = useTempDir("content-only-");
18
-
19
- test("rules-are-content-only: no rules is a failure, a rule asking git is a finding, clean rules pass", () => {
20
- writeTree(root, {
21
- "empty/.keep": "",
22
- "dirty/eslint-rules/asks-git.mjs":
23
- 'import { execFileSync } from "node:child_process";\nexecFileSync("git", ["log"]);\n',
24
- "dirty/eslint-rules/clean.mjs": "export default {};\n",
25
- "clean/eslint-rules/clean.mjs": "export default {};\n",
26
- });
27
- const runs = ["empty", "dirty", "clean"].map((d) => {
28
- const { out, io } = capture();
29
- return [
30
- contentMain({ cwd: `${root}/${d}`, ...io }),
31
- out.map((l) => l.replace(root, "<root>").split(". ")[0]),
32
- ];
33
- });
34
- assert.deepEqual(runs, [
35
- [1, ["E <root>/empty/eslint-rules: no rule sources"]],
36
- [
37
- 1,
38
- [
39
- "E asks-git.mjs: imports `git`",
40
- "rules-are-content-only: 2 rule sources under <root>/dirty, 1 findings",
41
- ],
42
- ],
43
- [
44
- 0,
45
- ["rules-are-content-only: 1 rule sources under <root>/clean, 0 findings"],
46
- ],
47
- ]);
48
- });
49
-
50
- test("run as a program over this repository: every rule source is content-only, exit 0", () => {
51
- const r = spawnSync(
52
- process.execPath,
53
- [fileURLToPath(new URL("./rules-are-content-only.mjs", import.meta.url))],
54
- { cwd: fileURLToPath(new URL("..", import.meta.url)), encoding: "utf8" },
55
- );
56
- assert.equal(r.status, 0, r.stderr);
57
- assert.match(
58
- r.stdout,
59
- /^rules-are-content-only: \d+ rule sources under .*, 0 findings\n$/,
60
- );
61
- });
package/scripts/test.mjs DELETED
@@ -1,44 +0,0 @@
1
- /**
2
- * `npm test`: the unit tests (vitest), then the harnesses (`vigiles test`). BOTH always run.
3
- *
4
- * Until #52 this was `vitest run && vigiles test --min=1`. Under `npm run coverage` a single
5
- * failing vitest test then skipped every harness, and what the run printed last was c8's summary:
6
- * lines, branches and functions each some six points below the floor. The one failing test sat
7
- * above that, looking like a consequence rather than the cause. Running both suites keeps the
8
- * coverage report whole, so a failing test is reported as itself and the coverage figures still
9
- * mean what they say.
10
- *
11
- * Arguments are the harness runner's (`npm test -- --no-skip`), as they were before.
12
- */
13
- import { spawnSync } from "node:child_process";
14
- import { isMain } from "../skills/paper-pipeline/scripts/consumer.mjs";
15
-
16
- /** The two suites, in order: what a failure is named as, and the command. */
17
- export const SUITES = [
18
- { name: "vitest", command: ["vitest", "run"] },
19
- { name: "harnesses", command: ["vigiles", "test", "--min=1"] },
20
- ];
21
-
22
- /**
23
- * Run every suite, whatever the one before it returned, and name the ones that failed.
24
- * @returns 0 when every suite passed; otherwise the first failing suite's exit code (1 for a signal).
25
- */
26
- export function runSuites(
27
- args,
28
- { spawn = spawnSync, err = console.error, suites = SUITES } = {},
29
- ) {
30
- const failed = suites.flatMap(({ name, command }) => {
31
- const [file, ...rest] = command;
32
- const r = spawn(file, [...rest, ...(name === "harnesses" ? args : [])], {
33
- stdio: "inherit",
34
- });
35
- return r.status === 0 ? [] : [{ name, code: r.status ?? 1 }];
36
- });
37
- for (const f of failed)
38
- err(
39
- `✗ ${f.name} failed (exit ${String(f.code)}) — its own report is above`,
40
- );
41
- return failed.length === 0 ? 0 : failed[0].code;
42
- }
43
-
44
- if (isMain(import.meta.url)) process.exit(runSuites(process.argv.slice(2)));
@@ -1,52 +0,0 @@
1
- /**
2
- * `npm test`'s runner: both suites run whatever the first returned, each failure is named, and
3
- * the harness arguments reach the harness runner only.
4
- */
5
- import assert from "node:assert/strict";
6
- import { test } from "vitest";
7
- import { runSuites, SUITES } from "./test.mjs";
8
-
9
- const fake = (status) => {
10
- const calls = [];
11
- return {
12
- calls,
13
- spawn: (file, args) => {
14
- calls.push([file, ...args]);
15
- return { status: status[file] };
16
- },
17
- };
18
- };
19
-
20
- test("a failing vitest does not skip the harnesses, and is named as the failure", () => {
21
- const { calls, spawn } = fake({ vitest: 1, vigiles: 0 });
22
- const said = [];
23
- assert.equal(
24
- runSuites(["--no-skip"], { spawn, err: (s) => said.push(s) }),
25
- 1,
26
- );
27
- assert.deepEqual(calls, [
28
- ["vitest", "run"],
29
- ["vigiles", "test", "--min=1", "--no-skip"],
30
- ]);
31
- assert.deepEqual(said, [
32
- "✗ vitest failed (exit 1) — its own report is above",
33
- ]);
34
- });
35
-
36
- test("both passing is 0 and silent; a harness killed by a signal is exit 1, named", () => {
37
- const ok = fake({ vitest: 0, vigiles: 0 });
38
- assert.equal(runSuites([], { spawn: ok.spawn, err: assert.fail }), 0);
39
- const killed = fake({ vitest: 0, vigiles: null });
40
- const said = [];
41
- assert.equal(
42
- runSuites([], { spawn: killed.spawn, err: (s) => said.push(s) }),
43
- 1,
44
- );
45
- assert.deepEqual(said, [
46
- "✗ harnesses failed (exit 1) — its own report is above",
47
- ]);
48
- assert.deepEqual(
49
- SUITES.map((s) => s.name),
50
- ["vitest", "harnesses"],
51
- );
52
- });
@@ -1,67 +0,0 @@
1
- // announce.mjs — a skill says out loud that it started, and the ledger remembers that it did.
2
- //
3
- // vigiles:local-by-design — takes a skill name as an argument and so names none itself, which reads
4
- // generic; it is not. It writes THIS repo's ledger row format, consumed by `status.mjs`'s gate table
5
- // and `ledger.mjs`'s verdict vocabulary, both of which are conventions of this knowledge base rather
6
- // than of any product. Moving it would export a schema nobody else has.
7
- //
8
- // WHY. Repository owner's request, 2026-08-07: "lack observability into pipeline status and whether
9
- // skills are actually being called — let's ensure each skill outputs something when activated".
10
- //
11
- // The failure behind that sentence is specific and it has happened three times in this repo. An
12
- // advisory check CANNOT BE SEEN FAILING: silence is both its error state and its normal state.
13
- // `paper-skills-nudge.sh` was dead for twelve days and was found only because it writes a throttle
14
- // stamp whose mtime had frozen. Two inline hooks were dead for their entire existence and nobody
15
- // noticed at all. And on 2026-08-06 a whole session of paper work ran with no skill invoked once.
16
- //
17
- // So: starting is an EVENT, and events get written down. A skill that announces leaves two traces —
18
- // one the human sees immediately, one the ledger keeps. Their disagreement is itself information:
19
- //
20
- // announced, never recorded → the skill started and died, or the author abandoned it midway
21
- // recorded, never announced → someone wrote a verdict without running the gate
22
- // neither → it did not run, whatever any status file claims
23
- //
24
- // This is the "no trace means it did not work" rule the project already applies to hooks, made
25
- // available to skills, which had no equivalent.
26
-
27
- import { record, skillHash, inputHash } from "./ledger.mjs";
28
- import { existsSync } from "node:fs";
29
- import { resolve, basename } from "node:path";
30
- import { isMain } from "./consumer.mjs";
31
-
32
- export function announce(skill, paperDir) {
33
- const dir = resolve(paperDir || ".");
34
- const has = existsSync(dir);
35
- const input = has ? inputHash(dir) : null;
36
-
37
- const lines = [
38
- `▶ ${skill} — ${has ? basename(dir) : "no paper dir"}`,
39
- ` paper ${input ? input.slice(0, 8) : "(none)"} · skill ${(skillHash(skill) || "????????").slice(0, 8)}`,
40
- ];
41
- // stderr, not stdout: the skill's own output is the product, and a banner that pollutes a pipe
42
- // is a banner someone will remove.
43
- console.error(lines.join("\n"));
44
-
45
- // An abstention with reason `started`, not an ERROR row. Before 2026-08-10 this wrote `ERROR`,
46
- // which meant "the check errored" — so every announce looked like a crash until its terminal row
47
- // landed, and `started` and `crashed` were the same word. Both are abstentions and neither is a
48
- // judgement about the paper; the reason is what tells them apart.
49
- record({
50
- skill,
51
- check: skill,
52
- paper: dir,
53
- kind: "ABSTAINED",
54
- reason: "started",
55
- note: "no verdict recorded yet",
56
- });
57
- return { skill, paper: basename(dir), input };
58
- }
59
-
60
- if (isMain(import.meta.url)) {
61
- const [skill, paperDir] = process.argv.slice(2);
62
- if (!skill) {
63
- console.error("usage: announce.mjs <skill-name> [paper-dir]");
64
- process.exit(2);
65
- }
66
- announce(skill, paperDir);
67
- }
@@ -1,102 +0,0 @@
1
- /**
2
- * announce.mjs — the first line of every wired skill's `## Run me` block: a banner on stderr naming
3
- * the paper and skill versions, and a `started` abstention in the ledger. Run as the skills run it,
4
- * against a temp consumer and a temp ledger.
5
- */
6
- import assert from "node:assert/strict";
7
- import { cpSync, readFileSync, rmSync } from "node:fs";
8
- import { dirname, join } from "node:path";
9
- import { fileURLToPath } from "node:url";
10
- import { afterEach, test } from "vitest";
11
- import { runNode, useTempDir, writeTree } from "../../../test/support.mjs";
12
-
13
- const HERE = dirname(fileURLToPath(import.meta.url));
14
- const SCRIPT = join(HERE, "announce.mjs");
15
- const root = useTempDir("announce-");
16
- const consumer = join(root, "consumer");
17
- const LEDGER = join(root, "runs.jsonl");
18
- writeTree(root, { "consumer/papers/p/paper.md": "# P\n\ntext\n" });
19
- cpSync(
20
- join(HERE, "..", "..", "cold-read-diff"),
21
- join(consumer, ".claude", "skills", "cold-read-diff"),
22
- {
23
- recursive: true,
24
- verbatimSymlinks: true,
25
- },
26
- );
27
- const env = { CLAUDE_PROJECT_DIR: consumer, PIPELINE_LEDGER: LEDGER };
28
- process.env.CLAUDE_PROJECT_DIR = consumer;
29
- process.env.PIPELINE_LEDGER = LEDGER;
30
- const { inputHash, skillHash } = await import("./ledger.mjs");
31
-
32
- const rows = () =>
33
- readFileSync(LEDGER, "utf8")
34
- .trim()
35
- .split("\n")
36
- .map((l) => JSON.parse(l))
37
- .map(({ skill, check, paper, kind, reason, note }) => ({
38
- skill,
39
- check,
40
- paper,
41
- kind,
42
- reason,
43
- note,
44
- }));
45
- afterEach(() => rmSync(LEDGER, { force: true }));
46
-
47
- test("no skill name: the usage line, exit 2, nothing recorded", () => {
48
- assert.deepEqual(runNode(SCRIPT, [], { env }), {
49
- status: 2,
50
- stdout: "",
51
- stderr: "usage: announce.mjs <skill-name> [paper-dir]\n",
52
- });
53
- });
54
-
55
- test("a skill on a paper: the banner names both versions, and a `started` row is recorded", () => {
56
- const paper = join(consumer, "papers", "p");
57
- const r = runNode(SCRIPT, ["cold-read-diff", paper], { env });
58
- assert.deepEqual(
59
- { ...r, rows: rows() },
60
- {
61
- status: 0,
62
- stdout: "",
63
- stderr:
64
- "▶ cold-read-diff — p\n" +
65
- ` paper ${inputHash(paper).slice(0, 8)} · skill ${skillHash("cold-read-diff").slice(0, 8)}\n`,
66
- rows: [
67
- {
68
- skill: "cold-read-diff",
69
- check: "cold-read-diff",
70
- paper: "p",
71
- kind: "ABSTAINED",
72
- reason: "started",
73
- note: "no verdict recorded yet",
74
- },
75
- ],
76
- },
77
- );
78
- });
79
-
80
- test("no paper directory and an unknown skill still announce, with placeholders", () => {
81
- const r = runNode(SCRIPT, ["no-such-skill", join(root, "nowhere")], { env });
82
- assert.deepEqual(
83
- { status: r.status, stderr: r.stderr, kind: rows()[0].kind },
84
- {
85
- status: 0,
86
- stderr:
87
- "▶ no-such-skill — no paper dir\n paper (none) · skill ????????\n",
88
- kind: "ABSTAINED",
89
- },
90
- );
91
- });
92
-
93
- test("no paper argument means the current directory", () => {
94
- const r = runNode(SCRIPT, ["cold-read-diff"], {
95
- env,
96
- cwd: join(consumer, "papers", "p"),
97
- });
98
- assert.deepEqual(
99
- { status: r.status, firstLine: r.stderr.split("\n")[0] },
100
- { status: 0, firstLine: "▶ cold-read-diff — p" },
101
- );
102
- });
@@ -1,51 +0,0 @@
1
- # PIPELINE-STATUS — fixture: nothing to report
2
- Venue: Fixture Workshop · Deadline: 2027-12-31 · Blind: double · State: drafting
3
- Updated: 2026-08-03
4
-
5
- **Readiness verdict:** Submit-ready — every gate green, artifact reproduces clean, nothing blocking.
6
-
7
- This fixture deliberately carries NO paper source file, so `newestSourceDate` is null and the
8
- staleness comparison has nothing to compare against. That keeps the clean case deterministic
9
- regardless of when the repo was checked out — the staleness rule is exercised by `dirty/`.
10
-
11
- ### SETUP
12
- | id | Work | Skill | Status | Date | Result | Open |
13
- |----|------|-------|--------|------|--------|------|
14
- | idea | Validate idea | research-ideate | ☑ | 2026-08-01 | go. judge: opus, judge: author | — |
15
- | priorwork | Map competitors | map-prior-work | ☑ | 2026-08-01 | 6 siblings. judge: sonnet, judge: author | siblings/ |
16
- | venue | Pick venue | find-venue | ☑ | 2026-08-01 | fixture. judge: sonnet, judge: author | — |
17
- | venuebar | Venue bar / levers | study-accepted-papers | ☑ | 2026-08-01 | 34 measured. judge: sonnet, judge: author | — |
18
- | **access** | 🔴 **Can you physically submit?** | plan-paper-timeline | ☑ | 2026-08-01 | profile ACTIVE since 2026-08-01. judge: author, judge: author | — |
19
- | schedule | Schedule + calendar | plan-paper-timeline | ☑ | 2026-08-01 | —. judge: author, judge: author | — |
20
- | **frame** | **Claim stated before the runs** | argument-arc (frame) | ☑ | 2026-07-20 | one paragraph filed | — |
21
-
22
- ### LOOP
23
- | id | Work | Skill | Status | Date | Result | Open |
24
- |----|------|-------|--------|------|--------|------|
25
- | study | Study + artifact | build-benchmark | ☑ | 2026-08-01 | ran | — |
26
- | draft | Draft | draft-paper | ☑ | 2026-08-01 | — | — |
27
- | arc | Argument arc | argument-arc | ☑ | 2026-08-01 | holds. judge: opus, judge: author | — |
28
-
29
- ### CONTINUOUS
30
- | id | Trigger | Skill | Status | Date | Result | Open |
31
- |----|---------|-------|--------|------|--------|------|
32
- | cites | any cite added/moved | verify-citations | ☑ | 2026-08-02 | clean | — |
33
- | siblings | a sibling surfaces | analyze-sibling-paper | ☑ | 2026-08-02 | 6 read. judge: opus, judge: author | siblings/ |
34
- | priordelta | framing moved | map-prior-work (delta) | ☑ | 2026-08-02 | no new | — |
35
- | render | any source edit | render-paper + page count | ☑ | 2026-08-02 | 8 pages / limit 8 | — |
36
-
37
- ### GATES
38
- | id | Gate | Skill | Requires | Status | Date | Result | Open |
39
- |----|------|-------|----------|--------|------|--------|------|
40
- | structure | Structure | tighten-paper | render, arc | ☑ | 2026-08-02 | cut plan applied. judge: opus, judge: author | — |
41
- | writing | Writing craft | grade-paper-writing | draft, arc, structure | ☑ | 2026-08-02 | 44/60. judge: sonnet, judge: author | — |
42
- | panel | Review decision | pc-panel-review | structure, writing | ☑ | 2026-08-03 | accept; judge: opus, judge: author | — |
43
- | claims | Claim preservation | Fable diff | draft, writing | ☑ | 2026-08-03 | clean | — |
44
- | harden | Harden (all axes) | harden-paper | panel, structure, writing, cites, priordelta | ☑ | 2026-08-03 | all axes green ; judge: opus, judge: author | — |
45
- | submit | Submit | submit-paper | harden, access | ☑ | 2026-08-03 | uploaded | — |
46
-
47
- ### AFTER
48
- | id | Work | Skill | Status | Date | Result | Open |
49
- |----|------|-------|--------|------|--------|------|
50
- | cameraready | Camera-ready | camera-ready | n/a | — | pre-acceptance | — |
51
- | extend | Extend | extend-paper | n/a | — | post-acceptance | — |
@@ -1,52 +0,0 @@
1
- # PIPELINE-STATUS — fixture: every failure this checker exists for
2
- Venue: Fixture Workshop · Deadline: 2026-08-06 · Blind: double · State: drafting
3
- Updated: 2026-01-01
4
-
5
- **Readiness verdict:** 88% accept probability, looking good.
6
-
7
- The `structure` row is missing `arc` from its Requires cell **on purpose** — that is the planted
8
- `undeclared-input`, copied from a defect found live on a real paper in August 2026. Every
9
- other gate cell here is the canonical set from `../../pipeline-edges.mjs`, so exactly one edge is
10
- undeclared and the finding cannot come from somewhere else.
11
-
12
- ### SETUP
13
- | id | Work | Skill | Status | Date | Result | Open |
14
- |----|------|-------|--------|------|--------|------|
15
- | idea | Validate idea | research-ideate | ☑ | 2026-01-01 | go | — |
16
- | priorwork | Map competitors | map-prior-work | ☑ | 2026-01-01 | 6 siblings | siblings/ |
17
- | venue | Pick venue | find-venue | ☑ | 2026-01-01 | fixture | — |
18
- | venuebar | Venue bar / levers | study-accepted-papers | ☐ | — | — | — |
19
- | **access** | 🔴 **Can you physically submit?** | plan-paper-timeline | ☐ | — | profile pending moderation | — |
20
- | schedule | Schedule + calendar | plan-paper-timeline | ☑ | 2026-01-01 | — | — |
21
- | **frame** | **Claim stated before the runs** | argument-arc (frame) | ☐ | — | — | — |
22
-
23
- ### LOOP
24
- | id | Work | Skill | Status | Date | Result | Open |
25
- |----|------|-------|--------|------|--------|------|
26
- | study | Study + artifact | build-benchmark | ☑ | 2026-01-01 | ran | — |
27
- | draft | Draft | draft-paper | ☑ | 2026-01-01 | — | — |
28
- | arc | Argument arc | argument-arc | ☐ | — | — | — |
29
-
30
- ### CONTINUOUS
31
- | id | Trigger | Skill | Status | Date | Result | Open |
32
- |----|---------|-------|--------|------|--------|------|
33
- | cites | any cite added/moved | verify-citations | ☑ | 2026-01-01 | clean | — |
34
- | siblings | a sibling surfaces | analyze-sibling-paper | ☑ | — | done | siblings/ |
35
- | priordelta | framing moved | map-prior-work (delta) | ☐ | — | — | — |
36
- | render | any source edit | render-paper + page count | ☑ | 2026-01-01 | 8 pages / limit 8 | — |
37
-
38
- ### GATES
39
- | id | Gate | Skill | Requires | Status | Date | Result | Open |
40
- |----|------|-------|----------|--------|------|--------|------|
41
- | structure | Structure | tighten-paper | render | ☑ | 2026-01-01 | cut plan | — |
42
- | writing | Writing craft | grade-paper-writing | draft, arc, structure | ☐ | — | — | — |
43
- | panel | Review decision | pc-panel-review | structure, writing | ☑ | 2026-01-01 | borderline | — |
44
- | claims | Claim preservation | Fable diff | draft, writing | ☐ | — | — | — |
45
- | harden | Harden (all axes) | harden-paper | panel, structure, writing, cites, priordelta | ☐ | — | — | — |
46
- | submit | Submit | submit-paper | harden, access | ☐ | — | — | — |
47
-
48
- ### AFTER
49
- | id | Work | Skill | Status | Date | Result | Open |
50
- |----|------|-------|--------|------|--------|------|
51
- | cameraready | Camera-ready | camera-ready | n/a | — | pre-acceptance | — |
52
- | extend | Extend | extend-paper | n/a | — | post-acceptance | — |
@@ -1,6 +0,0 @@
1
- # Fixture paper source
2
-
3
- This file exists only so `newestSourceDate` finds something. Its mtime is whenever the
4
- repo was checked out, which is always later than the 2026-01-01 dates in the fixture's
5
- CONTINUOUS rows — so the `stale-continuous` check fires deterministically without the
6
- test having to touch mtimes.
@@ -1,71 +0,0 @@
1
- /**
2
- * A PIPELINE-STATUS.md fixture shared by the pipeline-check harness and its CLI test: the four
3
- * template sections, every row green and dated `today`, so a test plants exactly one defect.
4
- */
5
- export const FAR = "2027-12-31";
6
-
7
- /**
8
- * A scorecard with the four sections the template requires, all green. `over` replaces individual
9
- * cells: `{ cites: { date: "2020-01-01" } }`, `{ verdict: "…" }`, `{ deadline: "2026-08-18" }`,
10
- * `{ tail: "…" }` for anything appended after the last section, `{ preamble: "…" }` for anything
11
- * inserted BEFORE the first heading (the only way to plant a row under no heading at all).
12
- */
13
- export function scorecard(
14
- over = {},
15
- today = new Date().toISOString().slice(0, 10),
16
- ) {
17
- const r = (id, status = "☑", date = today) => ({
18
- id,
19
- status,
20
- date,
21
- ...(over[id] ?? {}),
22
- });
23
- const row = (o, ...mid) =>
24
- `| ${o.id} | work | ${o.skill ?? "skill"} | ${mid.length ? mid.join(" | ") + " | " : ""}${o.status} | ${o.date} | ${o.result ?? "result"} | — |`;
25
- // The GATES `Requires` cell, canonical by default so the baseline is silent — `{ structure: {
26
- // requires: "render" } }` plants a dropped edge. `harden` deliberately declares four of its five
27
- // canonical inputs: the fifth (`priordelta`) has no row in this fixture, and the clean case asserts that the checker stays
28
- // quiet about an edge there is nowhere to point at.
29
- const req = (id, dflt) => over[id]?.requires ?? dflt;
30
- const verdict =
31
- over.verdict ??
32
- "Submit-ready — every gate green, artifact reproduces clean, nothing blocking.";
33
- return [
34
- "# PIPELINE-STATUS — harness fixture",
35
- `Venue: Fixture Workshop · Deadline: ${over.deadline ?? FAR} · Blind: double · State: drafting`,
36
- "",
37
- `**Readiness verdict:** ${verdict}`,
38
- "",
39
- over.preamble ?? "",
40
- "",
41
- "### SETUP",
42
- "| id | Work | Skill | Status | Date | Result | Open |",
43
- "|----|------|-------|--------|------|--------|------|",
44
- row(r("idea")),
45
- row(r("access")),
46
- row(r("frame")),
47
- "",
48
- "### LOOP",
49
- "| id | Work | Skill | Status | Date | Result | Open |",
50
- "|----|------|-------|--------|------|--------|------|",
51
- row(r("study")),
52
- row(r("draft")),
53
- row(r("arc")),
54
- "",
55
- "### CONTINUOUS",
56
- "| id | Trigger | Skill | Status | Date | Result | Open |",
57
- "|----|---------|-------|--------|------|--------|------|",
58
- row(r("cites")),
59
- row(r("render")),
60
- "",
61
- "### GATES",
62
- "| id | Gate | Skill | Requires | Status | Date | Result | Open |",
63
- "|----|------|-------|----------|--------|------|--------|------|",
64
- row(r("structure"), req("structure", "render, arc")),
65
- row(r("writing"), req("writing", "draft, arc, structure")),
66
- row(r("panel"), req("panel", "structure, writing")),
67
- row(r("harden"), req("harden", "panel, structure, writing, cites")),
68
- "",
69
- over.tail ?? "",
70
- ].join("\n");
71
- }