dsh-aris-panel 0.1.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/LICENSE +21 -0
- package/README.md +98 -0
- package/README_CN.md +87 -0
- package/dsh/checkout.patch.yml +38 -0
- package/dsh/client.js +634 -0
- package/dsh/cordis.patch.yml +44 -0
- package/dsh/index.mjs +76 -0
- package/dsh/run-status.mjs +182 -0
- package/dsh/scope-limits.mjs +50 -0
- package/dsh/workbench.mjs +291 -0
- package/mcp-servers/claude-review/README.md +93 -0
- package/mcp-servers/claude-review/run_with_claude_aws.sh +49 -0
- package/mcp-servers/claude-review/server.py +718 -0
- package/mcp-servers/codex-image2/README.md +65 -0
- package/mcp-servers/codex-image2/server.py +893 -0
- package/mcp-servers/feishu-bridge/requirements.txt +1 -0
- package/mcp-servers/feishu-bridge/server.py +240 -0
- package/mcp-servers/gemini-review/README.md +171 -0
- package/mcp-servers/gemini-review/server.py +1856 -0
- package/mcp-servers/llm-chat/requirements.txt +1 -0
- package/mcp-servers/llm-chat/server.py +664 -0
- package/mcp-servers/manual-review/README.md +133 -0
- package/mcp-servers/manual-review/server.py +910 -0
- package/mcp-servers/manual-review/ui.html +279 -0
- package/mcp-servers/minimax-chat/requirements.txt +1 -0
- package/mcp-servers/minimax-chat/server.py +381 -0
- package/package.json +51 -0
- package/skills/ablation-planner/SKILL.md +123 -0
- package/skills/alphaxiv/SKILL.md +196 -0
- package/skills/analyze-results/SKILL.md +46 -0
- package/skills/arxiv/SKILL.md +248 -0
- package/skills/auto-paper-improvement-loop/SKILL.md +651 -0
- package/skills/auto-review-loop/SKILL.md +1137 -0
- package/skills/auto-review-loop-llm/SKILL.md +259 -0
- package/skills/auto-review-loop-minimax/SKILL.md +302 -0
- package/skills/citation-audit/SKILL.md +502 -0
- package/skills/claims-drafting/SKILL.md +227 -0
- package/skills/comm-lit-review/SKILL.md +297 -0
- package/skills/deepxiv/SKILL.md +263 -0
- package/skills/dse-loop/SKILL.md +296 -0
- package/skills/embodiment-description/SKILL.md +129 -0
- package/skills/exa-search/SKILL.md +205 -0
- package/skills/experiment-audit/SKILL.md +311 -0
- package/skills/experiment-bridge/SKILL.md +376 -0
- package/skills/experiment-plan/SKILL.md +249 -0
- package/skills/experiment-queue/SKILL.md +431 -0
- package/skills/experiment-queue/scripts/build_manifest.py +142 -0
- package/skills/experiment-queue/scripts/queue_manager.py +433 -0
- package/skills/feishu-notify/SKILL.md +156 -0
- package/skills/figure-description/SKILL.md +138 -0
- package/skills/figure-spec/SKILL.md +262 -0
- package/skills/figure-spec/scripts/figure_renderer.py +799 -0
- package/skills/formula-derivation/SKILL.md +280 -0
- package/skills/gemini-search/SKILL.md +231 -0
- package/skills/grant-proposal/SKILL.md +698 -0
- package/skills/idea-creator/SKILL.md +542 -0
- package/skills/idea-discovery/SKILL.md +521 -0
- package/skills/idea-discovery-robot/SKILL.md +363 -0
- package/skills/integrity-forensics/SKILL.md +284 -0
- package/skills/interview-cheatsheet/SKILL.md +245 -0
- package/skills/invention-structuring/SKILL.md +188 -0
- package/skills/jurisdiction-format/SKILL.md +192 -0
- package/skills/kill-argument/SKILL.md +437 -0
- package/skills/mermaid-diagram/SKILL.md +419 -0
- package/skills/meta-apply/SKILL.md +141 -0
- package/skills/meta-optimize/SKILL.md +437 -0
- package/skills/monitor-experiment/SKILL.md +140 -0
- package/skills/novelty-check/SKILL.md +101 -0
- package/skills/openalex/SKILL.md +237 -0
- package/skills/overleaf-sync/SKILL.md +220 -0
- package/skills/paper-claim-audit/SKILL.md +348 -0
- package/skills/paper-compile/SKILL.md +266 -0
- package/skills/paper-figure/SKILL.md +312 -0
- package/skills/paper-illustration/SKILL.md +736 -0
- package/skills/paper-illustration-image2/SKILL.md +391 -0
- package/skills/paper-illustration-image2/scripts/paper_illustration_image2.py +255 -0
- package/skills/paper-plan/SKILL.md +386 -0
- package/skills/paper-poster/SKILL.md +19 -0
- package/skills/paper-poster-html/DESIGN_FINAL.md +176 -0
- package/skills/paper-poster-html/IMPLEMENTATION_CONVENTIONS.md +161 -0
- package/skills/paper-poster-html/LICENSES/posterly-MIT.txt +21 -0
- package/skills/paper-poster-html/NOTICE.md +57 -0
- package/skills/paper-poster-html/SKILL.md +323 -0
- package/skills/paper-poster-html/scripts/_posterly/__init__.py +0 -0
- package/skills/paper-poster-html/scripts/_posterly/canvas.py +200 -0
- package/skills/paper-poster-html/scripts/_posterly/measure.py +588 -0
- package/skills/paper-poster-html/scripts/_posterly/polish.py +498 -0
- package/skills/paper-poster-html/scripts/_posterly/preflight.py +489 -0
- package/skills/paper-poster-html/scripts/_posterly/render.py +215 -0
- package/skills/paper-poster-html/scripts/_posterly/textutil.py +16 -0
- package/skills/paper-poster-html/scripts/_posterly/verify_final.py +171 -0
- package/skills/paper-poster-html/scripts/asset_check.py +897 -0
- package/skills/paper-poster-html/scripts/extract_pdf_figures.py +666 -0
- package/skills/paper-poster-html/scripts/poster_check.py +251 -0
- package/skills/paper-poster-html/scripts/preprocess_figures.py +238 -0
- package/skills/paper-poster-html/scripts/render_preview.py +217 -0
- package/skills/paper-poster-html/scripts/run_gates.py +556 -0
- package/skills/paper-poster-html/scripts/style_check.py +1324 -0
- package/skills/paper-poster-html/templates/COMPONENTS.md +462 -0
- package/skills/paper-poster-html/templates/README.md +170 -0
- package/skills/paper-poster-html/templates/landscape_4col.html +1032 -0
- package/skills/paper-poster-html/templates/landscape_hero.html +1046 -0
- package/skills/paper-poster-html/templates/portrait_2col.html +947 -0
- package/skills/paper-poster-html/templates/tokens/acl.json +9 -0
- package/skills/paper-poster-html/templates/tokens/cvpr.json +9 -0
- package/skills/paper-poster-html/templates/tokens/generic.json +9 -0
- package/skills/paper-poster-html/templates/tokens/iclr.json +9 -0
- package/skills/paper-poster-html/templates/tokens/icml.json +9 -0
- package/skills/paper-poster-html/templates/tokens/neurips.json +9 -0
- package/skills/paper-slides/SKILL.md +635 -0
- package/skills/paper-talk/SKILL.md +381 -0
- package/skills/paper-write/SKILL.md +604 -0
- package/skills/paper-write/templates/IEEEtran.bst +2409 -0
- package/skills/paper-write/templates/IEEEtran.cls +6347 -0
- package/skills/paper-write/templates/iclr2026.tex +84 -0
- package/skills/paper-write/templates/icml2025.tex +87 -0
- package/skills/paper-write/templates/ieee_conference.tex +89 -0
- package/skills/paper-write/templates/ieee_journal.tex +93 -0
- package/skills/paper-write/templates/math_commands.tex +48 -0
- package/skills/paper-write/templates/neurips2025.tex +80 -0
- package/skills/paper-writing/SKILL.md +916 -0
- package/skills/patent-novelty-check/SKILL.md +153 -0
- package/skills/patent-pipeline/SKILL.md +344 -0
- package/skills/patent-review/SKILL.md +203 -0
- package/skills/pixel-art/SKILL.md +137 -0
- package/skills/prior-art-search/SKILL.md +146 -0
- package/skills/proof-checker/SKILL.md +866 -0
- package/skills/proof-orchestrator/NOTICE.md +24 -0
- package/skills/proof-orchestrator/SKILL.md +254 -0
- package/skills/proof-orchestrator/references/audit-output-contract.md +126 -0
- package/skills/proof-orchestrator/references/deepseek-routing.md +74 -0
- package/skills/proof-orchestrator/references/dispatch-prompts.md +227 -0
- package/skills/proof-orchestrator/references/notation-audit.md +135 -0
- package/skills/proof-orchestrator/references/proof-audit-rubric.md +70 -0
- package/skills/proof-orchestrator/references/stress-tests.md +38 -0
- package/skills/proof-writer/SKILL.md +223 -0
- package/skills/qzcli/SKILL.md +324 -0
- package/skills/rebuttal/SKILL.md +376 -0
- package/skills/render-html/SKILL.md +316 -0
- package/skills/render-html/scripts/render_html.py +1006 -0
- package/skills/render-html/scripts/templates/academic.html +703 -0
- package/skills/render-html/scripts/templates/dashboard.html +333 -0
- package/skills/research-lit/SKILL.md +756 -0
- package/skills/research-pipeline/SKILL.md +384 -0
- package/skills/research-refine/SKILL.md +770 -0
- package/skills/research-refine-pipeline/SKILL.md +186 -0
- package/skills/research-review/SKILL.md +198 -0
- package/skills/research-wiki/SKILL.md +461 -0
- package/skills/resubmit-pipeline/SKILL.md +447 -0
- package/skills/result-to-claim/SKILL.md +311 -0
- package/skills/run-experiment/SKILL.md +313 -0
- package/skills/semantic-scholar/SKILL.md +236 -0
- package/skills/serverless-modal/SKILL.md +335 -0
- package/skills/shared-references/acceptance-gate.md +324 -0
- package/skills/shared-references/assurance-contract.md +248 -0
- package/skills/shared-references/capture-antipatterns.md +78 -0
- package/skills/shared-references/citation-discipline.md +583 -0
- package/skills/shared-references/compute-env-contract.md +163 -0
- package/skills/shared-references/effort-contract.md +183 -0
- package/skills/shared-references/evidence-precheck.md +65 -0
- package/skills/shared-references/experiment-integrity.md +49 -0
- package/skills/shared-references/external-cadence.md +326 -0
- package/skills/shared-references/fan-out-pattern.md +366 -0
- package/skills/shared-references/injection-hygiene.md +127 -0
- package/skills/shared-references/integration-contract.md +461 -0
- package/skills/shared-references/output-composition.md +93 -0
- package/skills/shared-references/output-language.md +45 -0
- package/skills/shared-references/output-manifest.md +49 -0
- package/skills/shared-references/output-versioning.md +111 -0
- package/skills/shared-references/patent-format-cn.md +199 -0
- package/skills/shared-references/patent-format-ep.md +173 -0
- package/skills/shared-references/patent-format-us.md +161 -0
- package/skills/shared-references/patent-writing-principles.md +197 -0
- package/skills/shared-references/prior-art-databases.md +141 -0
- package/skills/shared-references/resumable-runs.md +109 -0
- package/skills/shared-references/review-scope-limits.md +81 -0
- package/skills/shared-references/review-tracing.md +391 -0
- package/skills/shared-references/reviewer-independence.md +79 -0
- package/skills/shared-references/reviewer-routing.md +852 -0
- package/skills/shared-references/skill-governance.md +104 -0
- package/skills/shared-references/taste-calibration.md +85 -0
- package/skills/shared-references/venue-checklists.md +114 -0
- package/skills/shared-references/wiki-helper-resolution.md +134 -0
- package/skills/shared-references/writing-principles.md +525 -0
- package/skills/skills-codex/README.md +102 -0
- package/skills/skills-codex/README_CN.md +100 -0
- package/skills/skills-codex/ablation-planner/SKILL.md +126 -0
- package/skills/skills-codex/alphaxiv/SKILL.md +186 -0
- package/skills/skills-codex/analyze-results/SKILL.md +45 -0
- package/skills/skills-codex/arxiv/SKILL.md +210 -0
- package/skills/skills-codex/auto-paper-improvement-loop/SKILL.md +574 -0
- package/skills/skills-codex/auto-review-loop/SKILL.md +500 -0
- package/skills/skills-codex/auto-review-loop-llm/SKILL.md +247 -0
- package/skills/skills-codex/auto-review-loop-minimax/SKILL.md +290 -0
- package/skills/skills-codex/citation-audit/SKILL.md +504 -0
- package/skills/skills-codex/claims-drafting/SKILL.md +239 -0
- package/skills/skills-codex/comm-lit-review/SKILL.md +299 -0
- package/skills/skills-codex/comm-lit-review/references/domain-taxonomy.md +57 -0
- package/skills/skills-codex/comm-lit-review/references/output-template.md +37 -0
- package/skills/skills-codex/comm-lit-review/references/source-policy.md +99 -0
- package/skills/skills-codex/comm-lit-review/references/venue-tiering.md +112 -0
- package/skills/skills-codex/deepxiv/SKILL.md +142 -0
- package/skills/skills-codex/dse-loop/SKILL.md +285 -0
- package/skills/skills-codex/embodiment-description/SKILL.md +129 -0
- package/skills/skills-codex/exa-search/SKILL.md +192 -0
- package/skills/skills-codex/experiment-audit/SKILL.md +286 -0
- package/skills/skills-codex/experiment-bridge/SKILL.md +356 -0
- package/skills/skills-codex/experiment-plan/SKILL.md +249 -0
- package/skills/skills-codex/experiment-queue/SKILL.md +401 -0
- package/skills/skills-codex/feishu-notify/SKILL.md +155 -0
- package/skills/skills-codex/figure-description/SKILL.md +138 -0
- package/skills/skills-codex/figure-spec/SKILL.md +252 -0
- package/skills/skills-codex/formula-derivation/SKILL.md +280 -0
- package/skills/skills-codex/gemini-search/SKILL.md +205 -0
- package/skills/skills-codex/grant-proposal/SKILL.md +626 -0
- package/skills/skills-codex/idea-creator/SKILL.md +405 -0
- package/skills/skills-codex/idea-discovery/SKILL.md +475 -0
- package/skills/skills-codex/idea-discovery-robot/SKILL.md +362 -0
- package/skills/skills-codex/integrity-forensics/SKILL.md +106 -0
- package/skills/skills-codex/interview-cheatsheet/SKILL.md +245 -0
- package/skills/skills-codex/invention-structuring/SKILL.md +188 -0
- package/skills/skills-codex/jurisdiction-format/SKILL.md +192 -0
- package/skills/skills-codex/kill-argument/SKILL.md +403 -0
- package/skills/skills-codex/mermaid-diagram/SKILL.md +379 -0
- package/skills/skills-codex/meta-apply/SKILL.md +154 -0
- package/skills/skills-codex/meta-optimize/SKILL.md +348 -0
- package/skills/skills-codex/monitor-experiment/SKILL.md +98 -0
- package/skills/skills-codex/novelty-check/SKILL.md +89 -0
- package/skills/skills-codex/openalex/SKILL.md +228 -0
- package/skills/skills-codex/overleaf-sync/SKILL.md +220 -0
- package/skills/skills-codex/paper-claim-audit/SKILL.md +350 -0
- package/skills/skills-codex/paper-compile/SKILL.md +253 -0
- package/skills/skills-codex/paper-figure/SKILL.md +311 -0
- package/skills/skills-codex/paper-illustration/SKILL.md +690 -0
- package/skills/skills-codex/paper-illustration-image2/SKILL.md +383 -0
- package/skills/skills-codex/paper-illustration-image2/scripts/paper_illustration_image2.py +255 -0
- package/skills/skills-codex/paper-plan/SKILL.md +278 -0
- package/skills/skills-codex/paper-poster/SKILL.md +19 -0
- package/skills/skills-codex/paper-poster-html/SKILL.md +377 -0
- package/skills/skills-codex/paper-slides/SKILL.md +571 -0
- package/skills/skills-codex/paper-talk/SKILL.md +381 -0
- package/skills/skills-codex/paper-write/SKILL.md +411 -0
- package/skills/skills-codex/paper-write/templates/IEEEtran.bst +2409 -0
- package/skills/skills-codex/paper-write/templates/IEEEtran.cls +6347 -0
- package/skills/skills-codex/paper-write/templates/aaai2026.bst +1493 -0
- package/skills/skills-codex/paper-write/templates/aaai2026.sty +315 -0
- package/skills/skills-codex/paper-write/templates/aaai2026.tex +952 -0
- package/skills/skills-codex/paper-write/templates/acl.sty +312 -0
- package/skills/skills-codex/paper-write/templates/acl2026.tex +377 -0
- package/skills/skills-codex/paper-write/templates/acl_natbib.bst +1940 -0
- package/skills/skills-codex/paper-write/templates/acm.bst +3081 -0
- package/skills/skills-codex/paper-write/templates/acm_mm2026.tex +204 -0
- package/skills/skills-codex/paper-write/templates/acmart.cls +3520 -0
- package/skills/skills-codex/paper-write/templates/cvpr.bst +1448 -0
- package/skills/skills-codex/paper-write/templates/cvpr.sty +508 -0
- package/skills/skills-codex/paper-write/templates/cvpr2026.tex +63 -0
- package/skills/skills-codex/paper-write/templates/iclr2026.tex +84 -0
- package/skills/skills-codex/paper-write/templates/iclr2026_conference.bst +1440 -0
- package/skills/skills-codex/paper-write/templates/iclr2026_conference.sty +246 -0
- package/skills/skills-codex/paper-write/templates/icml2026.sty +767 -0
- package/skills/skills-codex/paper-write/templates/icml2026.tex +662 -0
- package/skills/skills-codex/paper-write/templates/ieee_conference.tex +89 -0
- package/skills/skills-codex/paper-write/templates/ieee_journal.tex +93 -0
- package/skills/skills-codex/paper-write/templates/math_commands.tex +48 -0
- package/skills/skills-codex/paper-write/templates/neurips2026.tex +493 -0
- package/skills/skills-codex/paper-write/templates/neurips_2026.sty +437 -0
- package/skills/skills-codex/paper-writing/SKILL.md +731 -0
- package/skills/skills-codex/patent-novelty-check/SKILL.md +153 -0
- package/skills/skills-codex/patent-pipeline/SKILL.md +344 -0
- package/skills/skills-codex/patent-review/SKILL.md +202 -0
- package/skills/skills-codex/pixel-art/SKILL.md +139 -0
- package/skills/skills-codex/prior-art-search/SKILL.md +146 -0
- package/skills/skills-codex/proof-checker/SKILL.md +554 -0
- package/skills/skills-codex/proof-orchestrator/SKILL.md +260 -0
- package/skills/skills-codex/proof-orchestrator/references/audit-output-contract.md +126 -0
- package/skills/skills-codex/proof-orchestrator/references/deepseek-routing.md +76 -0
- package/skills/skills-codex/proof-orchestrator/references/dispatch-prompts.md +227 -0
- package/skills/skills-codex/proof-orchestrator/references/notation-audit.md +135 -0
- package/skills/skills-codex/proof-orchestrator/references/proof-audit-rubric.md +70 -0
- package/skills/skills-codex/proof-orchestrator/references/stress-tests.md +38 -0
- package/skills/skills-codex/proof-writer/SKILL.md +222 -0
- package/skills/skills-codex/qzcli/SKILL.md +324 -0
- package/skills/skills-codex/rebuttal/SKILL.md +305 -0
- package/skills/skills-codex/render-html/SKILL.md +305 -0
- package/skills/skills-codex/render-html/scripts/__pycache__/render_html.cpython-314.pyc +0 -0
- package/skills/skills-codex/render-html/scripts/render_html.py +909 -0
- package/skills/skills-codex/render-html/scripts/templates/academic.html +342 -0
- package/skills/skills-codex/render-html/scripts/templates/dashboard.html +333 -0
- package/skills/skills-codex/research-lit/SKILL.md +464 -0
- package/skills/skills-codex/research-pipeline/SKILL.md +340 -0
- package/skills/skills-codex/research-refine/SKILL.md +721 -0
- package/skills/skills-codex/research-refine-pipeline/SKILL.md +186 -0
- package/skills/skills-codex/research-review/SKILL.md +135 -0
- package/skills/skills-codex/research-wiki/SKILL.md +421 -0
- package/skills/skills-codex/resubmit-pipeline/SKILL.md +444 -0
- package/skills/skills-codex/result-to-claim/SKILL.md +246 -0
- package/skills/skills-codex/run-experiment/SKILL.md +236 -0
- package/skills/skills-codex/semantic-scholar/SKILL.md +219 -0
- package/skills/skills-codex/serverless-modal/SKILL.md +335 -0
- package/skills/skills-codex/shared-references/acceptance-gate.md +336 -0
- package/skills/skills-codex/shared-references/assurance-contract.md +139 -0
- package/skills/skills-codex/shared-references/capture-antipatterns.md +84 -0
- package/skills/skills-codex/shared-references/citation-discipline.md +452 -0
- package/skills/skills-codex/shared-references/compute-env-contract.md +163 -0
- package/skills/skills-codex/shared-references/effort-contract.md +143 -0
- package/skills/skills-codex/shared-references/evidence-precheck.md +73 -0
- package/skills/skills-codex/shared-references/experiment-integrity.md +49 -0
- package/skills/skills-codex/shared-references/external-cadence.md +334 -0
- package/skills/skills-codex/shared-references/fan-out-pattern.md +375 -0
- package/skills/skills-codex/shared-references/injection-hygiene.md +132 -0
- package/skills/skills-codex/shared-references/integration-contract.md +372 -0
- package/skills/skills-codex/shared-references/output-composition.md +98 -0
- package/skills/skills-codex/shared-references/output-language.md +45 -0
- package/skills/skills-codex/shared-references/output-manifest.md +40 -0
- package/skills/skills-codex/shared-references/output-versioning.md +111 -0
- package/skills/skills-codex/shared-references/patent-format-cn.md +199 -0
- package/skills/skills-codex/shared-references/patent-format-ep.md +173 -0
- package/skills/skills-codex/shared-references/patent-format-us.md +161 -0
- package/skills/skills-codex/shared-references/patent-writing-principles.md +197 -0
- package/skills/skills-codex/shared-references/prior-art-databases.md +141 -0
- package/skills/skills-codex/shared-references/resumable-runs.md +125 -0
- package/skills/skills-codex/shared-references/review-scope-limits.md +81 -0
- package/skills/skills-codex/shared-references/review-tracing.md +144 -0
- package/skills/skills-codex/shared-references/reviewer-independence.md +66 -0
- package/skills/skills-codex/shared-references/reviewer-routing.md +128 -0
- package/skills/skills-codex/shared-references/skill-governance.md +119 -0
- package/skills/skills-codex/shared-references/taste-calibration.md +90 -0
- package/skills/skills-codex/shared-references/venue-checklists.md +73 -0
- package/skills/skills-codex/shared-references/wiki-helper-resolution.md +69 -0
- package/skills/skills-codex/shared-references/writing-principles.md +525 -0
- package/skills/skills-codex/slides-polish/SKILL.md +563 -0
- package/skills/skills-codex/specification-writing/SKILL.md +211 -0
- package/skills/skills-codex/system-profile/SKILL.md +103 -0
- package/skills/skills-codex/training-check/SKILL.md +83 -0
- package/skills/skills-codex/vast-gpu/SKILL.md +394 -0
- package/skills/skills-codex/web-debug-search/SKILL.md +334 -0
- package/skills/skills-codex/wiki-enrich/SKILL.md +255 -0
- package/skills/skills-codex/writing-systems-papers/SKILL.md +184 -0
- package/skills/skills-codex-claude-review/README.md +79 -0
- package/skills/skills-codex-claude-review/README_CN.md +78 -0
- package/skills/skills-codex-claude-review/auto-paper-improvement-loop/SKILL.md +581 -0
- package/skills/skills-codex-claude-review/auto-review-loop/SKILL.md +510 -0
- package/skills/skills-codex-claude-review/novelty-check/SKILL.md +102 -0
- package/skills/skills-codex-claude-review/paper-figure/SKILL.md +319 -0
- package/skills/skills-codex-claude-review/paper-plan/SKILL.md +287 -0
- package/skills/skills-codex-claude-review/paper-write/SKILL.md +420 -0
- package/skills/skills-codex-claude-review/research-refine/SKILL.md +732 -0
- package/skills/skills-codex-claude-review/research-review/SKILL.md +149 -0
- package/skills/skills-codex-gemini-review/README.md +176 -0
- package/skills/skills-codex-gemini-review/README_CN.md +175 -0
- package/skills/skills-codex-gemini-review/auto-paper-improvement-loop/SKILL.md +331 -0
- package/skills/skills-codex-gemini-review/auto-review-loop/SKILL.md +304 -0
- package/skills/skills-codex-gemini-review/grant-proposal/SKILL.md +630 -0
- package/skills/skills-codex-gemini-review/idea-creator/SKILL.md +263 -0
- package/skills/skills-codex-gemini-review/idea-discovery/SKILL.md +275 -0
- package/skills/skills-codex-gemini-review/idea-discovery-robot/SKILL.md +365 -0
- package/skills/skills-codex-gemini-review/novelty-check/SKILL.md +92 -0
- package/skills/skills-codex-gemini-review/paper-figure/SKILL.md +289 -0
- package/skills/skills-codex-gemini-review/paper-plan/SKILL.md +265 -0
- package/skills/skills-codex-gemini-review/paper-poster-html/SKILL.md +102 -0
- package/skills/skills-codex-gemini-review/paper-slides/SKILL.md +582 -0
- package/skills/skills-codex-gemini-review/paper-write/SKILL.md +346 -0
- package/skills/skills-codex-gemini-review/paper-writing/SKILL.md +312 -0
- package/skills/skills-codex-gemini-review/research-refine/SKILL.md +674 -0
- package/skills/skills-codex-gemini-review/research-review/SKILL.md +112 -0
- package/skills/slides-polish/SKILL.md +565 -0
- package/skills/specification-writing/SKILL.md +211 -0
- package/skills/system-profile/SKILL.md +103 -0
- package/skills/training-check/SKILL.md +132 -0
- package/skills/vast-gpu/SKILL.md +394 -0
- package/skills/web-debug-search/SKILL.md +334 -0
- package/skills/wiki-enrich/SKILL.md +257 -0
- package/skills/writing-systems-papers/SKILL.md +184 -0
- package/templates/CLAUDE_MD_TEMPLATE.md +29 -0
- package/templates/EXPERIMENT_LOG_TEMPLATE.md +47 -0
- package/templates/EXPERIMENT_PLAN_TEMPLATE.md +51 -0
- package/templates/EXPERIMENT_PLAN_TEMPLATE_CN.md +53 -0
- package/templates/FINDINGS_TEMPLATE.md +52 -0
- package/templates/IDEA_CANDIDATES_TEMPLATE.md +47 -0
- package/templates/IDEA_CANDIDATES_TEMPLATE_CN.md +47 -0
- package/templates/INVENTION_BRIEF_TEMPLATE.md +87 -0
- package/templates/MANIFEST_TEMPLATE.md +7 -0
- package/templates/NARRATIVE_REPORT_TEMPLATE.md +49 -0
- package/templates/PAPER_PLAN_TEMPLATE.md +47 -0
- package/templates/PATENT_CLAIMS_TEMPLATE.md +78 -0
- package/templates/PATENT_SPECIFICATION_TEMPLATE.md +68 -0
- package/templates/README.md +57 -0
- package/templates/RESEARCH_BRIEF_TEMPLATE.md +35 -0
- package/templates/RESEARCH_BRIEF_TEMPLATE_CN.md +41 -0
- package/templates/RESEARCH_CONTRACT_TEMPLATE.md +60 -0
- package/templates/claude-hooks/corpus_write_guard.json +16 -0
- package/templates/claude-hooks/corpus_write_guard.py +85 -0
- package/templates/claude-hooks/meta_logging.json +74 -0
- package/templates/gitignore-trace.txt +3 -0
- package/tools/__pycache__/check_skills_inventory.cpython-314.pyc +0 -0
- package/tools/arxiv_fetch.py +311 -0
- package/tools/capture_filter.py +126 -0
- package/tools/check_skills_inventory.py +273 -0
- package/tools/convert_skills_to_llm_chat.py +282 -0
- package/tools/copilot_native_evidence.py +818 -0
- package/tools/deepxiv_fetch.py +213 -0
- package/tools/evidence_check.py +212 -0
- package/tools/exa_search.py +425 -0
- package/tools/experiment_queue/README.md +118 -0
- package/tools/experiment_queue/build_manifest.py +44 -0
- package/tools/experiment_queue/queue_manager.py +44 -0
- package/tools/extract_paper_style.py +560 -0
- package/tools/figure_renderer.py +69 -0
- package/tools/forensics_gate.py +669 -0
- package/tools/generate_codex_claude_review_overrides.py +299 -0
- package/tools/idea_discovery_gate.py +256 -0
- package/tools/install_aris.ps1 +1372 -0
- package/tools/install_aris.sh +1370 -0
- package/tools/install_aris_codex.sh +1023 -0
- package/tools/install_aris_copilot.sh +1052 -0
- package/tools/iteration_log.py +143 -0
- package/tools/lint_skills_helpers.sh +84 -0
- package/tools/meta_opt/check_ready.sh +80 -0
- package/tools/meta_opt/log_event.sh +91 -0
- package/tools/meta_opt/trigger_eval.py +280 -0
- package/tools/meta_opt/trigger_evals.sample.json +28 -0
- package/tools/openalex_fetch.py +326 -0
- package/tools/overleaf_audit.sh +104 -0
- package/tools/overleaf_setup.sh +150 -0
- package/tools/paper_illustration_image2.py +62 -0
- package/tools/provenance.py +294 -0
- package/tools/research_wiki.py +1720 -0
- package/tools/review_gate.py +502 -0
- package/tools/run_state.py +399 -0
- package/tools/save_trace.sh +477 -0
- package/tools/semantic_scholar_fetch.py +438 -0
- package/tools/skill-groups.tsv +116 -0
- package/tools/skill_picker.py +238 -0
- package/tools/smart_update.ps1 +521 -0
- package/tools/smart_update.sh +591 -0
- package/tools/smart_update_codex.sh +419 -0
- package/tools/smart_update_copilot.sh +605 -0
- package/tools/threat_scan.py +222 -0
- package/tools/verify_paper_audits.sh +487 -0
- package/tools/verify_papers.py +613 -0
- package/tools/verify_wiki_coverage.sh +176 -0
- package/tools/watchdog.py +485 -0
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
"""Alignment + gap-to-strip measurement — the HARD gate.
|
|
2
|
+
|
|
3
|
+
This is the only gate that decides whether columns visually align. It
|
|
4
|
+
print-emulates the HTML in headless Chromium, reads the geometry of
|
|
5
|
+
every ``[data-measure-role]`` element, and reports two numbers:
|
|
6
|
+
|
|
7
|
+
- **spread**: max−min of last-card-bottoms across all columns
|
|
8
|
+
(plus any hero panel). Aim < 3 px; default fail threshold 5 px.
|
|
9
|
+
- **gap → footer-strip/footer**: distance from the last card's
|
|
10
|
+
bottom to the next horizontal strip. Aim [30, 50] px so card
|
|
11
|
+
shadows clear but cards don't visually float.
|
|
12
|
+
|
|
13
|
+
Non-negotiables built in: an empty column hard-fails (fallback to
|
|
14
|
+
column.bottom is risky); missing footer-strip/footer hard-fails; a
|
|
15
|
+
MathJax typeset error / timeout / silent CDN block hard-fails.
|
|
16
|
+
"""
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import argparse
|
|
20
|
+
import json
|
|
21
|
+
import sys
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import Any
|
|
24
|
+
|
|
25
|
+
from . import canvas as _canvas
|
|
26
|
+
from . import render as _render
|
|
27
|
+
from .textutil import ascii_safe
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _eprint(*args: Any, **kw: Any) -> None:
|
|
31
|
+
print(*args, file=sys.stderr, **kw)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
#: Hard ceiling for the whitespace between consecutive stacked cards in a
|
|
35
|
+
#: column. Same ceiling as the footer gap: anything wider reads as a void
|
|
36
|
+
#: in print. Shared by the CLI default in poster_check.py and the getattr
|
|
37
|
+
#: fallback in cmd_measure.
|
|
38
|
+
DEFAULT_MAX_INTERCARD_GAP = 50.0
|
|
39
|
+
|
|
40
|
+
#: Hard floor for the same gap. The shipped card shadow is
|
|
41
|
+
#: ``0 2u 6u`` (offset ~7.6 px + blur ~22.7 px at print scale, u = 1mm);
|
|
42
|
+
#: a gap under ~12 px buries the shadow core under the next card, so the
|
|
43
|
+
#: stack reads as one fused slab instead of separate cards. Floor sits
|
|
44
|
+
#: well under the shipped 6u (~22.7 px) design gap; tune (or 0 to
|
|
45
|
+
#: disable) for shadowless custom themes.
|
|
46
|
+
DEFAULT_MIN_INTERCARD_GAP = 12.0
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def intercard_gaps(cards: list[dict]) -> list[float]:
|
|
50
|
+
"""Vertical gaps between consecutive *rows* of cards in one column.
|
|
51
|
+
|
|
52
|
+
Cards are grouped into rows by vertical-overlap chaining (sorted by
|
|
53
|
+
top; a card whose top sits above the current row's bottom joins that
|
|
54
|
+
row), so two half-width cards sitting side by side count as ONE row
|
|
55
|
+
and don't produce a bogus negative/huge "gap". Returns one gap per
|
|
56
|
+
consecutive row pair. Pure function so the grouping rule is
|
|
57
|
+
unit-testable without Chromium.
|
|
58
|
+
"""
|
|
59
|
+
if len(cards) < 2:
|
|
60
|
+
return []
|
|
61
|
+
rows: list[list[float]] = [] # [top, bottom] per row
|
|
62
|
+
for c in sorted(cards, key=lambda c: c["y"]):
|
|
63
|
+
if rows and c["y"] < rows[-1][1]:
|
|
64
|
+
rows[-1][1] = max(rows[-1][1], c["bottom"])
|
|
65
|
+
else:
|
|
66
|
+
rows.append([c["y"], c["bottom"]])
|
|
67
|
+
return [rows[i][0] - rows[i - 1][1] for i in range(1, len(rows))]
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
_MEASURE_JS = r"""
|
|
71
|
+
() => {
|
|
72
|
+
const nodes = Array.from(document.querySelectorAll('[data-measure-role]'));
|
|
73
|
+
return nodes.map(n => {
|
|
74
|
+
const r = n.getBoundingClientRect();
|
|
75
|
+
const cs = window.getComputedStyle(n);
|
|
76
|
+
return {
|
|
77
|
+
role: n.getAttribute('data-measure-role') || '',
|
|
78
|
+
tag: n.tagName.toLowerCase(),
|
|
79
|
+
cls: n.className || '',
|
|
80
|
+
x: r.left, y: r.top, w: r.width, h: r.height,
|
|
81
|
+
bottom: r.bottom, right: r.right,
|
|
82
|
+
// For the content-clipping gate: the computed overflow plus the
|
|
83
|
+
// scroll-vs-client deltas. `overflow != visible` decouples the
|
|
84
|
+
// border-box (read above) from the real content extent; a positive
|
|
85
|
+
// (scroll - client) is content sitting past the box edge that print
|
|
86
|
+
// silently clips. Integer-rounded by the browser, so a small
|
|
87
|
+
// tolerance on the Python side absorbs sub-pixel noise.
|
|
88
|
+
overflow_x: cs.overflowX, overflow_y: cs.overflowY,
|
|
89
|
+
scroll_h: n.scrollHeight, client_h: n.clientHeight,
|
|
90
|
+
scroll_w: n.scrollWidth, client_w: n.clientWidth,
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def compute_adjustment_hints(
|
|
98
|
+
bottoms: list[tuple[str, float]],
|
|
99
|
+
strip_top: float,
|
|
100
|
+
*,
|
|
101
|
+
min_gap: float,
|
|
102
|
+
max_gap: float,
|
|
103
|
+
keep_tol_px: float = 5.0,
|
|
104
|
+
) -> tuple[float, float, list[tuple[str, float, str]]]:
|
|
105
|
+
"""Per-column adjustment hints for a failed measure run.
|
|
106
|
+
|
|
107
|
+
Returns ``(target_gap, target_bottom, adjustments)`` where
|
|
108
|
+
``adjustments`` is one ``(name, current_bottom, hint)`` per column /
|
|
109
|
+
hero row. ``hint`` is one of:
|
|
110
|
+
|
|
111
|
+
* ``"keep"`` -- |delta| <= ``keep_tol_px``; not worth touching
|
|
112
|
+
because a single wrapped line of body text is ~25 px and edits
|
|
113
|
+
below that don't reliably change the column bottom. Callers
|
|
114
|
+
should pass the gate's ``--max-spread`` here so the keep band
|
|
115
|
+
tracks the gate: a column the spread check would tolerate is
|
|
116
|
+
never flagged for an edit.
|
|
117
|
+
* ``"grow ~N px"`` -- column needs to be taller (delta > 0).
|
|
118
|
+
* ``"trim ~N px"`` -- column needs to be shorter (delta < 0).
|
|
119
|
+
|
|
120
|
+
The target is ``strip_top - (min_gap + max_gap) / 2``: aim for the
|
|
121
|
+
centre of the gap band so a small post-edit drift in either direction
|
|
122
|
+
still passes the gate. Pure function so the rule is unit-testable
|
|
123
|
+
without spinning up Chromium.
|
|
124
|
+
"""
|
|
125
|
+
target_gap = (min_gap + max_gap) / 2.0
|
|
126
|
+
target_bottom = strip_top - target_gap
|
|
127
|
+
out: list[tuple[str, float, str]] = []
|
|
128
|
+
for name, b in bottoms:
|
|
129
|
+
delta = target_bottom - b # +ve grow, -ve trim
|
|
130
|
+
if abs(delta) <= keep_tol_px:
|
|
131
|
+
hint = "keep"
|
|
132
|
+
elif delta > 0:
|
|
133
|
+
hint = f"grow ~{int(round(delta))} px"
|
|
134
|
+
else:
|
|
135
|
+
hint = f"trim ~{int(round(-delta))} px"
|
|
136
|
+
out.append((name, b, hint))
|
|
137
|
+
return target_gap, target_bottom, out
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def cmd_measure(args: argparse.Namespace) -> int:
|
|
141
|
+
try:
|
|
142
|
+
from playwright.sync_api import sync_playwright
|
|
143
|
+
from playwright.sync_api import TimeoutError as PWTimeoutError
|
|
144
|
+
except ImportError:
|
|
145
|
+
_eprint("ERROR: playwright not installed. Run:")
|
|
146
|
+
_eprint(" python -m pip install playwright")
|
|
147
|
+
_eprint(" python -m playwright install chromium")
|
|
148
|
+
return 2
|
|
149
|
+
|
|
150
|
+
html_path = Path(args.html).resolve()
|
|
151
|
+
if not html_path.exists():
|
|
152
|
+
_eprint(f"ERROR: HTML not found: {ascii_safe(html_path)}")
|
|
153
|
+
return 2
|
|
154
|
+
|
|
155
|
+
resolved = _canvas.resolve_canvas(
|
|
156
|
+
html_path, args.canvas, label="[measure]"
|
|
157
|
+
)
|
|
158
|
+
if resolved is None:
|
|
159
|
+
_eprint(
|
|
160
|
+
"ERROR: could not find `@page { size: <W> <H> }` in HTML. "
|
|
161
|
+
"Add an @page rule (units: in/mm/cm/pt) or pass "
|
|
162
|
+
"`--canvas <W>x<H>in` / `--canvas 'A0 portrait'`. "
|
|
163
|
+
"Refusing to silently fall back."
|
|
164
|
+
)
|
|
165
|
+
return 2
|
|
166
|
+
canvas, viewport = resolved
|
|
167
|
+
|
|
168
|
+
with sync_playwright() as p:
|
|
169
|
+
browser, _ctx, page = _render.open_print_emulated_page(p, viewport)
|
|
170
|
+
nav_timed_out = False
|
|
171
|
+
try:
|
|
172
|
+
page.goto(html_path.as_uri(), wait_until="networkidle",
|
|
173
|
+
timeout=args.mathjax_timeout_ms)
|
|
174
|
+
except PWTimeoutError:
|
|
175
|
+
# Don't raw-traceback on a hung/slow resource. Record it and
|
|
176
|
+
# let settle_page surface a MathJax-specific failure first;
|
|
177
|
+
# otherwise fail-fast below. A HARD gate must NOT measure a
|
|
178
|
+
# poster that never finished loading -- a blocked remote image
|
|
179
|
+
# or web font would otherwise sneak through as a false PASS.
|
|
180
|
+
nav_timed_out = True
|
|
181
|
+
|
|
182
|
+
settle = _render.settle_page(
|
|
183
|
+
page,
|
|
184
|
+
mathjax_timeout_ms=args.mathjax_timeout_ms,
|
|
185
|
+
settle_ms=args.settle_ms,
|
|
186
|
+
)
|
|
187
|
+
fail = _render.hard_fail_on_settle_problems(
|
|
188
|
+
settle, mathjax_timeout_ms=args.mathjax_timeout_ms,
|
|
189
|
+
)
|
|
190
|
+
if fail is not None:
|
|
191
|
+
browser.close()
|
|
192
|
+
_eprint(f"FAIL: {fail}")
|
|
193
|
+
return 1
|
|
194
|
+
if nav_timed_out:
|
|
195
|
+
browser.close()
|
|
196
|
+
_eprint(
|
|
197
|
+
"FAIL: page did not reach network-idle within "
|
|
198
|
+
f"{args.mathjax_timeout_ms} ms; refusing to measure a "
|
|
199
|
+
"partially loaded poster. A blocked/slow remote resource "
|
|
200
|
+
"(CDN image, web font, MathJax) is the usual cause -- "
|
|
201
|
+
"inline assets, or raise --mathjax-timeout-ms."
|
|
202
|
+
)
|
|
203
|
+
return 1
|
|
204
|
+
|
|
205
|
+
data = page.evaluate(_MEASURE_JS)
|
|
206
|
+
browser.close()
|
|
207
|
+
|
|
208
|
+
if args.json_out:
|
|
209
|
+
Path(args.json_out).write_text(
|
|
210
|
+
json.dumps(data, indent=2), encoding="utf-8"
|
|
211
|
+
)
|
|
212
|
+
print(f"[measure] raw data -> {ascii_safe(args.json_out)}")
|
|
213
|
+
|
|
214
|
+
# Canvas-fill gate (coarse early diagnostic). The position-align
|
|
215
|
+
# check below is the authoritative rule — any poster whose bbox
|
|
216
|
+
# aligns to the page within `--position-tol-px` already fills
|
|
217
|
+
# ≈ 100 % of the canvas. This ratio check fires earlier on two
|
|
218
|
+
# specific failure modes with a more diagnostic error message:
|
|
219
|
+
# (a) missing `[data-measure-role="poster"]` — measure can't
|
|
220
|
+
# anchor the layout, so a silent PASS would be misleading;
|
|
221
|
+
# (b) ratio FAR outside the band (e.g. 42 % when the poster
|
|
222
|
+
# forgot the `@media print { :root { --u: 1mm } }` override
|
|
223
|
+
# and rendered at screen scale, or 200 % when hardcoded
|
|
224
|
+
# `width` exceeded `@page size`). The error message points
|
|
225
|
+
# at the common print-scale bug.
|
|
226
|
+
# For borderline 95–99 % cases, the position gate is the truth.
|
|
227
|
+
# Safe-area design belongs as internal padding on a full-bleed
|
|
228
|
+
# `.poster`, NOT as a smaller poster (which would clip the bbox
|
|
229
|
+
# alignment check).
|
|
230
|
+
poster_box = next((el for el in data if el["role"] == "poster"), None)
|
|
231
|
+
if poster_box is None:
|
|
232
|
+
_eprint(
|
|
233
|
+
"FAIL: no [data-measure-role=\"poster\"] element found on "
|
|
234
|
+
"the page. Add it to the root poster container -- measure "
|
|
235
|
+
"needs it to verify the canvas-fill, and preflight already "
|
|
236
|
+
"rejects pages without it."
|
|
237
|
+
)
|
|
238
|
+
return 1
|
|
239
|
+
vw, vh = viewport
|
|
240
|
+
fill_w = poster_box["w"] / vw
|
|
241
|
+
fill_h = poster_box["h"] / vh
|
|
242
|
+
lo = args.min_canvas_fill
|
|
243
|
+
hi = args.max_canvas_fill
|
|
244
|
+
if not (lo <= fill_w <= hi) or not (lo <= fill_h <= hi):
|
|
245
|
+
_eprint(
|
|
246
|
+
f"FAIL: [data-measure-role=\"poster\"] fills "
|
|
247
|
+
f"{fill_w * 100:.0f}% x {fill_h * 100:.0f}% of the print "
|
|
248
|
+
f"viewport (target {lo * 100:.0f}% - {hi * 100:.0f}% in "
|
|
249
|
+
f"BOTH dimensions). Common cause when too small: missing "
|
|
250
|
+
f"`@media print {{ :root {{ --u: 1mm }} }}` so the poster "
|
|
251
|
+
f"keeps the screen-mode unit scale in print. Common cause "
|
|
252
|
+
f"when too large: hardcoded `width` exceeds `@page size`."
|
|
253
|
+
)
|
|
254
|
+
return 1
|
|
255
|
+
# Positional check: poster must be anchored to the page's origin
|
|
256
|
+
# within `--position-tol-px`. A `transform: translateX(50 px)` would
|
|
257
|
+
# silently clip the right side of the print PDF; size alone can't
|
|
258
|
+
# see this.
|
|
259
|
+
tol = args.position_tol_px
|
|
260
|
+
pos_problems = []
|
|
261
|
+
if abs(poster_box["x"]) > tol:
|
|
262
|
+
pos_problems.append(f"x={poster_box['x']:.1f} (expected ~= 0)")
|
|
263
|
+
if abs(poster_box["y"]) > tol:
|
|
264
|
+
pos_problems.append(f"y={poster_box['y']:.1f} (expected ~= 0)")
|
|
265
|
+
if abs(poster_box["right"] - vw) > tol:
|
|
266
|
+
pos_problems.append(
|
|
267
|
+
f"right={poster_box['right']:.1f} (expected ~= {vw})"
|
|
268
|
+
)
|
|
269
|
+
if abs(poster_box["bottom"] - vh) > tol:
|
|
270
|
+
pos_problems.append(
|
|
271
|
+
f"bottom={poster_box['bottom']:.1f} (expected ~= {vh})"
|
|
272
|
+
)
|
|
273
|
+
if pos_problems:
|
|
274
|
+
_eprint(
|
|
275
|
+
"FAIL: [data-measure-role=\"poster\"] is not aligned to "
|
|
276
|
+
f"the page (tolerance +/-{tol:.1f} px):\n"
|
|
277
|
+
" " + ", ".join(pos_problems) + ".\n"
|
|
278
|
+
"Fix: make `.poster` full-bleed in print --\n"
|
|
279
|
+
" @media print {\n"
|
|
280
|
+
" .poster { width: 100%; height: 100%;\n"
|
|
281
|
+
" margin: 0; padding: 0 }\n"
|
|
282
|
+
" html,body { margin: 0; padding: 0 }\n"
|
|
283
|
+
" }\n"
|
|
284
|
+
"Then drop any `transform: translate*` / "
|
|
285
|
+
"`position: absolute` offsets.\n"
|
|
286
|
+
"Also check: put `@media print` AFTER the screen "
|
|
287
|
+
"`.poster` rule."
|
|
288
|
+
)
|
|
289
|
+
return 1
|
|
290
|
+
|
|
291
|
+
# Content-clipping gate (HARD). Everything below reads each element's
|
|
292
|
+
# border-box edge -- but `overflow` other than `visible` DECOUPLES that
|
|
293
|
+
# box from the real content extent: anything past the edge is clipped
|
|
294
|
+
# in print and silently lost, while the box (and so every spread/gap
|
|
295
|
+
# number below) still looks clean. The classic trap is a flex
|
|
296
|
+
# card/column/hero: when its overflow is hidden/scroll/auto its
|
|
297
|
+
# `min-height: auto` is floored toward 0, so flexbox shrinks the
|
|
298
|
+
# over-full item back inside its track and clips the overflow -- turning
|
|
299
|
+
# a too-full poster into a false PASS. (A fixed-/max-height box with any
|
|
300
|
+
# non-visible overflow clips the same way, without the flex step.) Catch
|
|
301
|
+
# it directly by comparing scroll-size to client-size on the alignment
|
|
302
|
+
# containers -- the exact roles whose bottoms feed spread/gap below.
|
|
303
|
+
#
|
|
304
|
+
# Scope is deliberately those role containers (card, column, hero), NOT
|
|
305
|
+
# a full-descendant sweep: the latter trips over MathJax's off-screen
|
|
306
|
+
# `<mjx-assistive-mml>` a11y nodes (overflow:hidden, a few px of
|
|
307
|
+
# intrinsic overflow) and would false-fail every math poster. Known
|
|
308
|
+
# limitation: an author-built inner panel that clips via its own
|
|
309
|
+
# `max-height; overflow:hidden` (e.g. a scroll-box around a wide table)
|
|
310
|
+
# is NOT scanned -- only the role container itself. `overflow: visible`
|
|
311
|
+
# is never flagged: that content spills VISIBLY and the existing
|
|
312
|
+
# gap/spread gate already sees the displaced box -- only the *hidden*
|
|
313
|
+
# clip is invisible to it.
|
|
314
|
+
clip_overflows = {"hidden", "clip", "scroll", "auto"}
|
|
315
|
+
clip_problems: list[str] = []
|
|
316
|
+
for el in data:
|
|
317
|
+
if el["role"] not in ("card", "column", "hero"):
|
|
318
|
+
continue
|
|
319
|
+
oy = str(el.get("overflow_y") or "").lower()
|
|
320
|
+
ox = str(el.get("overflow_x") or "").lower()
|
|
321
|
+
dy = el.get("scroll_h", 0) - el.get("client_h", 0)
|
|
322
|
+
dx = el.get("scroll_w", 0) - el.get("client_w", 0)
|
|
323
|
+
axes: list[str] = []
|
|
324
|
+
if oy in clip_overflows and dy > args.max_clip_px:
|
|
325
|
+
axes.append(f"{dy:.0f}px below the box (overflow-y: {oy})")
|
|
326
|
+
if ox in clip_overflows and dx > args.max_clip_px:
|
|
327
|
+
axes.append(f"{dx:.0f}px past the right (overflow-x: {ox})")
|
|
328
|
+
if axes:
|
|
329
|
+
cls = el.get("cls", "")
|
|
330
|
+
ident = f"{el['role']} <{el['tag']}" + (
|
|
331
|
+
f" class=\"{cls}\"" if cls else "") + ">"
|
|
332
|
+
clip_problems.append(f"{ident}: " + ", ".join(axes))
|
|
333
|
+
if clip_problems:
|
|
334
|
+
_eprint(
|
|
335
|
+
"FAIL: content overflows its box and is CLIPPED by "
|
|
336
|
+
"overflow:hidden/clip/scroll/auto -- print drops it silently "
|
|
337
|
+
"while the box still looks aligned:\n"
|
|
338
|
+
+ "\n".join(" " + p for p in clip_problems)
|
|
339
|
+
+ f"\n(tolerance {args.max_clip_px:.0f} px). Fix: remove the "
|
|
340
|
+
"`overflow` rule so the content overflows VISIBLY -- measure "
|
|
341
|
+
"then reports a negative gap pointing at the real 'too much "
|
|
342
|
+
"content' problem -- then cut content, shrink fonts, or enlarge "
|
|
343
|
+
"the canvas. Do NOT use overflow:hidden to make a too-full "
|
|
344
|
+
"column 'pass': a flex item with overflow other than visible "
|
|
345
|
+
"has min-height auto -> 0, so flexbox shrinks it and clips the "
|
|
346
|
+
"overflow."
|
|
347
|
+
)
|
|
348
|
+
return 1
|
|
349
|
+
|
|
350
|
+
columns: dict[int, dict[str, Any]] = {}
|
|
351
|
+
heros: list[dict[str, Any]] = []
|
|
352
|
+
footer_strips: list[dict[str, Any]] = []
|
|
353
|
+
footers: list[dict[str, Any]] = []
|
|
354
|
+
|
|
355
|
+
col_index = 0
|
|
356
|
+
for el in data:
|
|
357
|
+
role = el["role"]
|
|
358
|
+
if role == "column":
|
|
359
|
+
columns[col_index] = {"box": el, "last_card_bottom": None}
|
|
360
|
+
col_index += 1
|
|
361
|
+
elif role == "hero":
|
|
362
|
+
heros.append(el)
|
|
363
|
+
elif role == "footer-strip":
|
|
364
|
+
footer_strips.append(el)
|
|
365
|
+
elif role == "footer":
|
|
366
|
+
footers.append(el)
|
|
367
|
+
|
|
368
|
+
def x_overlaps(card: dict, box: dict) -> bool:
|
|
369
|
+
cx_mid = card["x"] + card["w"] / 2
|
|
370
|
+
return box["x"] <= cx_mid <= box["x"] + box["w"]
|
|
371
|
+
|
|
372
|
+
for el in data:
|
|
373
|
+
if el["role"] != "card":
|
|
374
|
+
continue
|
|
375
|
+
for ci, col in columns.items():
|
|
376
|
+
if x_overlaps(el, col["box"]):
|
|
377
|
+
col.setdefault("cards", []).append(el)
|
|
378
|
+
prev = col["last_card_bottom"]
|
|
379
|
+
if prev is None or el["bottom"] > prev:
|
|
380
|
+
col["last_card_bottom"] = el["bottom"]
|
|
381
|
+
break
|
|
382
|
+
|
|
383
|
+
empty_cols = [
|
|
384
|
+
ci for ci, col in columns.items()
|
|
385
|
+
if col["last_card_bottom"] is None
|
|
386
|
+
]
|
|
387
|
+
if empty_cols and not args.allow_empty_column:
|
|
388
|
+
_eprint(
|
|
389
|
+
f"ERROR: columns with no cards detected: "
|
|
390
|
+
f"{['col' + str(i) for i in empty_cols]}. "
|
|
391
|
+
"Add cards or pass --allow-empty-column."
|
|
392
|
+
)
|
|
393
|
+
return 1
|
|
394
|
+
|
|
395
|
+
# Intra-column whitespace gate (HARD). The spread/gap gates only read
|
|
396
|
+
# the LAST card's bottom -- `justify-content: space-between` (or a big
|
|
397
|
+
# margin) pins the first card to the top and the last to the bottom,
|
|
398
|
+
# so an under-filled column reads spread ~= 0 and a clean footer gap
|
|
399
|
+
# while a void sits mid-column, plainly visible in print. (Observed
|
|
400
|
+
# in the wild: 98-135 px voids against a 22.7 px design row-gap, with
|
|
401
|
+
# polish's relative-threshold warn silent.) Gate: every gap between
|
|
402
|
+
# consecutive stacked card rows must stay under --max-intercard-gap.
|
|
403
|
+
# The same band has a floor: a gap under --min-intercard-gap buries
|
|
404
|
+
# the card's drop shadow (`0 2u 6u` in the shipped templates) under
|
|
405
|
+
# the next card, fusing the stack into one slab.
|
|
406
|
+
max_icg = getattr(
|
|
407
|
+
args, "max_intercard_gap", DEFAULT_MAX_INTERCARD_GAP
|
|
408
|
+
)
|
|
409
|
+
min_icg = getattr(
|
|
410
|
+
args, "min_intercard_gap", DEFAULT_MIN_INTERCARD_GAP
|
|
411
|
+
)
|
|
412
|
+
icg_problems: list[str] = []
|
|
413
|
+
icg_tight: list[str] = []
|
|
414
|
+
icg_worst: tuple[str, float] | None = None
|
|
415
|
+
icg_tightest: tuple[str, float] | None = None
|
|
416
|
+
for ci, col in columns.items():
|
|
417
|
+
gaps_c = intercard_gaps(col.get("cards", []))
|
|
418
|
+
if not gaps_c:
|
|
419
|
+
continue
|
|
420
|
+
g = max(gaps_c)
|
|
421
|
+
g_lo = min(gaps_c)
|
|
422
|
+
if icg_worst is None or g > icg_worst[1]:
|
|
423
|
+
icg_worst = (f"col{ci}", g)
|
|
424
|
+
if icg_tightest is None or g_lo < icg_tightest[1]:
|
|
425
|
+
icg_tightest = (f"col{ci}", g_lo)
|
|
426
|
+
if g > max_icg:
|
|
427
|
+
icg_problems.append(
|
|
428
|
+
f"col{ci}: {g:.1f} px between stacked cards"
|
|
429
|
+
)
|
|
430
|
+
if g_lo < min_icg:
|
|
431
|
+
icg_tight.append(
|
|
432
|
+
f"col{ci}: {g_lo:.1f} px between stacked cards"
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
bottoms: list[tuple[str, float]] = []
|
|
436
|
+
for ci, col in columns.items():
|
|
437
|
+
b = col["last_card_bottom"]
|
|
438
|
+
if b is None:
|
|
439
|
+
b = col["box"]["bottom"]
|
|
440
|
+
bottoms.append((f"col{ci}", b))
|
|
441
|
+
for hi, hero in enumerate(heros):
|
|
442
|
+
bottoms.append(
|
|
443
|
+
(f"hero{hi}" if len(heros) > 1 else "hero", hero["bottom"])
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
if not bottoms:
|
|
447
|
+
_eprint(
|
|
448
|
+
"ERROR: no columns or hero found. "
|
|
449
|
+
'Did you add data-measure-role="column"?'
|
|
450
|
+
)
|
|
451
|
+
return 2
|
|
452
|
+
|
|
453
|
+
bs = [b for _, b in bottoms]
|
|
454
|
+
spread = max(bs) - min(bs)
|
|
455
|
+
|
|
456
|
+
max_bottom = max(bs)
|
|
457
|
+
|
|
458
|
+
def _pick_nearest(strips: list[dict[str, Any]],
|
|
459
|
+
target: float) -> dict[str, Any] | None:
|
|
460
|
+
if not strips:
|
|
461
|
+
return None
|
|
462
|
+
return min(strips, key=lambda s: abs(s["y"] - target))
|
|
463
|
+
|
|
464
|
+
if footer_strips:
|
|
465
|
+
next_strip = _pick_nearest(footer_strips, max_bottom)
|
|
466
|
+
next_name = "footer-strip"
|
|
467
|
+
elif footers:
|
|
468
|
+
next_strip = _pick_nearest(footers, max_bottom)
|
|
469
|
+
next_name = "footer"
|
|
470
|
+
else:
|
|
471
|
+
next_strip = None
|
|
472
|
+
next_name = None
|
|
473
|
+
|
|
474
|
+
gap_range: tuple[float, float] | None = None
|
|
475
|
+
gaps: list[tuple[str, float]] = []
|
|
476
|
+
if next_strip is not None:
|
|
477
|
+
for name, b in bottoms:
|
|
478
|
+
gaps.append((name, next_strip["y"] - b))
|
|
479
|
+
gap_range = (min(g for _, g in gaps), max(g for _, g in gaps))
|
|
480
|
+
|
|
481
|
+
print()
|
|
482
|
+
print(f"[measure] columns found: {len(columns)}"
|
|
483
|
+
+ (f" (+ {len(heros)} hero)" if heros else ""))
|
|
484
|
+
for name, b in bottoms:
|
|
485
|
+
print(f" {name:6s} last-card-bottom = {b:8.2f} px")
|
|
486
|
+
print(f" spread = {spread:.2f} px (target < {args.max_spread} px)")
|
|
487
|
+
if icg_worst is not None:
|
|
488
|
+
print(f" intercard gap in [{icg_tightest[1]:.2f} ({icg_tightest[0]}),"
|
|
489
|
+
f" {icg_worst[1]:.2f} ({icg_worst[0]})] px"
|
|
490
|
+
f" (target [{min_icg}, {max_icg}])")
|
|
491
|
+
if next_strip is not None:
|
|
492
|
+
lo, hi = gap_range # type: ignore[misc]
|
|
493
|
+
print(f" gap -> {next_name} in [{lo:.2f}, {hi:.2f}] px"
|
|
494
|
+
f" (target [{args.min_gap}, {args.max_gap}])")
|
|
495
|
+
else:
|
|
496
|
+
print(" gap -> (no footer-strip or footer below content)")
|
|
497
|
+
|
|
498
|
+
ok = True
|
|
499
|
+
if spread >= args.max_spread:
|
|
500
|
+
_eprint(f"FAIL: spread {spread:.2f} >= max {args.max_spread}")
|
|
501
|
+
ok = False
|
|
502
|
+
if icg_problems:
|
|
503
|
+
_eprint(
|
|
504
|
+
"FAIL: intra-column whitespace void (max intercard gap "
|
|
505
|
+
f"{max_icg:.0f} px):\n"
|
|
506
|
+
+ "\n".join(" " + p for p in icg_problems)
|
|
507
|
+
+ "\nColumns must be filled by CONTENT, not stretched "
|
|
508
|
+
"whitespace. Do NOT use `justify-content: space-between` / "
|
|
509
|
+
"`space-around` (or oversized margins) to fake bottom "
|
|
510
|
+
"alignment -- it pins the last card to the bottom so spread "
|
|
511
|
+
"reads ~0 while a void sits mid-column. Fix: grow figures or "
|
|
512
|
+
"text, rebalance cards across columns, or use a fixed "
|
|
513
|
+
"row-gap, then re-measure."
|
|
514
|
+
)
|
|
515
|
+
ok = False
|
|
516
|
+
if icg_tight:
|
|
517
|
+
_eprint(
|
|
518
|
+
"FAIL: stacked cards too tight (min intercard gap "
|
|
519
|
+
f"{min_icg:.0f} px):\n"
|
|
520
|
+
+ "\n".join(" " + p for p in icg_tight)
|
|
521
|
+
+ "\nA gap this small buries the card's drop shadow under "
|
|
522
|
+
"the next card, fusing the stack into one slab. Fix: restore "
|
|
523
|
+
"the column's design row-gap (shipped templates use 6u "
|
|
524
|
+
"~= 22.7 px) and absorb the height elsewhere (trim content "
|
|
525
|
+
"or shrink a figure); for a deliberately shadowless theme, "
|
|
526
|
+
"lower --min-intercard-gap."
|
|
527
|
+
)
|
|
528
|
+
ok = False
|
|
529
|
+
if next_strip is not None:
|
|
530
|
+
lo, hi = gap_range # type: ignore[misc]
|
|
531
|
+
if lo < args.min_gap:
|
|
532
|
+
_eprint(f"FAIL: min gap {lo:.2f} < {args.min_gap}")
|
|
533
|
+
ok = False
|
|
534
|
+
if hi > args.max_gap:
|
|
535
|
+
_eprint(f"FAIL: max gap {hi:.2f} > {args.max_gap}")
|
|
536
|
+
ok = False
|
|
537
|
+
elif not args.allow_no_footer_gap:
|
|
538
|
+
_eprint(
|
|
539
|
+
"FAIL: no footer-strip or footer found below content. "
|
|
540
|
+
"Pass --allow-no-footer-gap to skip this gate."
|
|
541
|
+
)
|
|
542
|
+
ok = False
|
|
543
|
+
|
|
544
|
+
if ok:
|
|
545
|
+
print("[measure] PASS")
|
|
546
|
+
return 0
|
|
547
|
+
|
|
548
|
+
# Failure path: surface per-column adjustment hints so the next
|
|
549
|
+
# iteration is a directed edit, not a guess. The math is mechanical
|
|
550
|
+
# (strip_top - target_gap = target_bottom; signed delta per column),
|
|
551
|
+
# but readers reliably mis-derive it under time pressure -- a fixed
|
|
552
|
+
# gate failure was costing roughly an extra rebuild per loop. Only
|
|
553
|
+
# print when the geometry is sane enough to give a meaningful target:
|
|
554
|
+
# we need a footer-strip/footer (the anchor) and at least one column
|
|
555
|
+
# bottom. Skip when the only failure is `spread`-without-strip; the
|
|
556
|
+
# raw column dump above is already actionable in that case.
|
|
557
|
+
if next_strip is not None and bottoms:
|
|
558
|
+
target_gap, target_bottom, adjustments = compute_adjustment_hints(
|
|
559
|
+
bottoms,
|
|
560
|
+
next_strip["y"],
|
|
561
|
+
min_gap=args.min_gap,
|
|
562
|
+
max_gap=args.max_gap,
|
|
563
|
+
keep_tol_px=args.max_spread,
|
|
564
|
+
)
|
|
565
|
+
|
|
566
|
+
print()
|
|
567
|
+
print("[measure] suggested adjustments:")
|
|
568
|
+
print(
|
|
569
|
+
f" target col bottom = {target_bottom:.0f} px"
|
|
570
|
+
f" (footer-strip/footer top {next_strip['y']:.0f} px"
|
|
571
|
+
f" - target gap {target_gap:.0f} px)"
|
|
572
|
+
)
|
|
573
|
+
for name, b, hint in adjustments:
|
|
574
|
+
print(f" {name:6s} {b:8.2f} px -> {hint}")
|
|
575
|
+
# The px magnitudes below are heuristics at typical print scale
|
|
576
|
+
# (~3000 px canvas) and don't scale with the canvas -- they are
|
|
577
|
+
# approximate by design; the per-column deltas above are exact.
|
|
578
|
+
print(
|
|
579
|
+
" Tip: a body paragraph adds/removes ~25 px per wrapped line,"
|
|
580
|
+
" a callout ~60-90 px,"
|
|
581
|
+
)
|
|
582
|
+
print(
|
|
583
|
+
" a small figure ~80-150 px. Prefer trimming the tallest"
|
|
584
|
+
" column first."
|
|
585
|
+
)
|
|
586
|
+
|
|
587
|
+
_eprint("[measure] FAIL -- alignment gate not met")
|
|
588
|
+
return 1
|