medsci-skills 4.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.
Files changed (702) hide show
  1. package/LICENSE +50 -0
  2. package/README.md +602 -0
  3. package/README_FIRST.md +27 -0
  4. package/bin/medsci-skills.js +159 -0
  5. package/installers/install-macos.command +19 -0
  6. package/installers/install-windows.cmd +26 -0
  7. package/installers/install-windows.ps1 +17 -0
  8. package/installers/install.py +218 -0
  9. package/metadata/skills_catalog.json +452 -0
  10. package/package.json +48 -0
  11. package/skills/academic-aio/SKILL.md +408 -0
  12. package/skills/academic-aio/references/case_studies/kjr_mllm_2025.md +82 -0
  13. package/skills/academic-aio/references/checklists/AIO_GENERAL.md +354 -0
  14. package/skills/academic-aio/references/journal_summarybox_templates.yaml +126 -0
  15. package/skills/academic-aio/references/oac_funding_checklist.yaml +129 -0
  16. package/skills/academic-aio/references/reporting_guideline_mapping.md +39 -0
  17. package/skills/academic-aio/references/schema_markup_templates/CodeRepository.jsonld +32 -0
  18. package/skills/academic-aio/references/schema_markup_templates/Dataset.jsonld +36 -0
  19. package/skills/academic-aio/references/schema_markup_templates/Person.jsonld +30 -0
  20. package/skills/academic-aio/references/schema_markup_templates/README.md +43 -0
  21. package/skills/academic-aio/references/schema_markup_templates/ScholarlyArticle.jsonld +55 -0
  22. package/skills/academic-aio/scripts/batch_metadata_audit.py +169 -0
  23. package/skills/academic-aio/scripts/validate_schema.py +118 -0
  24. package/skills/academic-aio/skill.yml +36 -0
  25. package/skills/academic-aio/templates/aio_audit_checklist.md.j2 +108 -0
  26. package/skills/add-journal/SKILL.md +482 -0
  27. package/skills/add-journal/skill.yml +33 -0
  28. package/skills/analyze-stats/SKILL.md +598 -0
  29. package/skills/analyze-stats/references/analysis_guides/missing_data.md +109 -0
  30. package/skills/analyze-stats/references/analysis_guides/nhis_icd10_mapping.md +247 -0
  31. package/skills/analyze-stats/references/analysis_guides/propensity_score.md +132 -0
  32. package/skills/analyze-stats/references/analysis_guides/regression.md +115 -0
  33. package/skills/analyze-stats/references/analysis_guides/repeated_measures.md +160 -0
  34. package/skills/analyze-stats/references/analysis_guides/survey_weighted.md +366 -0
  35. package/skills/analyze-stats/references/analysis_guides/test_selection.md +86 -0
  36. package/skills/analyze-stats/references/style/figure_style.mplstyle +69 -0
  37. package/skills/analyze-stats/references/style/theme_publication.R +147 -0
  38. package/skills/analyze-stats/references/table-standards/journal-profiles/ajr.yaml +51 -0
  39. package/skills/analyze-stats/references/table-standards/journal-profiles/european_radiology.yaml +55 -0
  40. package/skills/analyze-stats/references/table-standards/journal-profiles/jama.yaml +66 -0
  41. package/skills/analyze-stats/references/table-standards/journal-profiles/lancet.yaml +57 -0
  42. package/skills/analyze-stats/references/table-standards/journal-profiles/nejm.yaml +51 -0
  43. package/skills/analyze-stats/references/table-standards/journal-profiles/radiology.yaml +66 -0
  44. package/skills/analyze-stats/references/table-standards/table-standards.md +287 -0
  45. package/skills/analyze-stats/references/table-standards/table-types/diagnostic_accuracy.md +36 -0
  46. package/skills/analyze-stats/references/table-standards/table-types/meta_analysis.md +58 -0
  47. package/skills/analyze-stats/references/table-standards/table-types/model_comparison.md +36 -0
  48. package/skills/analyze-stats/references/table-standards/table-types/regression_results.md +50 -0
  49. package/skills/analyze-stats/references/table-standards/table-types/table1_demographics.md +51 -0
  50. package/skills/analyze-stats/references/table-standards/tool-comparison.md +79 -0
  51. package/skills/analyze-stats/references/templates/agreement_analysis.py +436 -0
  52. package/skills/analyze-stats/references/templates/dca_plot.R +237 -0
  53. package/skills/analyze-stats/references/templates/diagnostic_accuracy.py +401 -0
  54. package/skills/analyze-stats/references/templates/dta_meta_analysis.R +384 -0
  55. package/skills/analyze-stats/references/templates/forest_plot.py +412 -0
  56. package/skills/analyze-stats/references/templates/likert_summary.py +356 -0
  57. package/skills/analyze-stats/references/templates/meta_analysis.R +365 -0
  58. package/skills/analyze-stats/references/templates/propensity_score.py +478 -0
  59. package/skills/analyze-stats/references/templates/regression.py +425 -0
  60. package/skills/analyze-stats/references/templates/repeated_measures.py +434 -0
  61. package/skills/analyze-stats/references/templates/sample_size.R +382 -0
  62. package/skills/analyze-stats/references/templates/survey_weighted_analysis.py +411 -0
  63. package/skills/analyze-stats/references/templates/survival_analysis.py +325 -0
  64. package/skills/analyze-stats/references/templates/table1_demographics.py +287 -0
  65. package/skills/analyze-stats/scripts/check_generated_code.py +335 -0
  66. package/skills/analyze-stats/skill.yml +38 -0
  67. package/skills/analyze-stats/tests/fixtures/gen_bad.R +16 -0
  68. package/skills/analyze-stats/tests/fixtures/gen_bad.py +24 -0
  69. package/skills/analyze-stats/tests/fixtures/gen_clean.py +21 -0
  70. package/skills/analyze-stats/tests/test_generated_code.sh +59 -0
  71. package/skills/analyze-stats/tests/test_survival_template.sh +53 -0
  72. package/skills/author-strategy/SKILL.md +117 -0
  73. package/skills/author-strategy/analyze_patterns.py +303 -0
  74. package/skills/author-strategy/fetch_pubmed.py +374 -0
  75. package/skills/author-strategy/skill.yml +34 -0
  76. package/skills/batch-cohort/SKILL.md +223 -0
  77. package/skills/batch-cohort/references/base_template_knhanes.R +210 -0
  78. package/skills/batch-cohort/references/batch_template_generator.R +222 -0
  79. package/skills/batch-cohort/references/variable_coding_registry.md +136 -0
  80. package/skills/batch-cohort/skill.yml +35 -0
  81. package/skills/calc-sample-size/SKILL.md +491 -0
  82. package/skills/calc-sample-size/references/formulas.md +655 -0
  83. package/skills/calc-sample-size/references/observational_cohort.md +49 -0
  84. package/skills/calc-sample-size/skill.yml +51 -0
  85. package/skills/check-reporting/SKILL.md +534 -0
  86. package/skills/check-reporting/references/LICENSES.md +41 -0
  87. package/skills/check-reporting/references/checklists/AMSTAR2.md +54 -0
  88. package/skills/check-reporting/references/checklists/ARRIVE_2.md +234 -0
  89. package/skills/check-reporting/references/checklists/CARE.md +102 -0
  90. package/skills/check-reporting/references/checklists/CLAIM_2024.md +128 -0
  91. package/skills/check-reporting/references/checklists/CLEAR.md +113 -0
  92. package/skills/check-reporting/references/checklists/CONSORT.md +86 -0
  93. package/skills/check-reporting/references/checklists/COSMIN_RoB.md +136 -0
  94. package/skills/check-reporting/references/checklists/GRRAS.md +61 -0
  95. package/skills/check-reporting/references/checklists/MI_CLEAR_LLM.md +167 -0
  96. package/skills/check-reporting/references/checklists/MOOSE.md +85 -0
  97. package/skills/check-reporting/references/checklists/NOS.md +88 -0
  98. package/skills/check-reporting/references/checklists/PRISMA_2020.md +135 -0
  99. package/skills/check-reporting/references/checklists/PRISMA_DTA.md +36 -0
  100. package/skills/check-reporting/references/checklists/PRISMA_P.md +56 -0
  101. package/skills/check-reporting/references/checklists/PROBAST.md +75 -0
  102. package/skills/check-reporting/references/checklists/PROBAST_AI.md +130 -0
  103. package/skills/check-reporting/references/checklists/QUADAS2.md +77 -0
  104. package/skills/check-reporting/references/checklists/QUADAS_C.md +131 -0
  105. package/skills/check-reporting/references/checklists/ROBINS_E.md +179 -0
  106. package/skills/check-reporting/references/checklists/ROBINS_I.md +87 -0
  107. package/skills/check-reporting/references/checklists/ROBIS.md +114 -0
  108. package/skills/check-reporting/references/checklists/ROB_ME.md +126 -0
  109. package/skills/check-reporting/references/checklists/RoB2.md +79 -0
  110. package/skills/check-reporting/references/checklists/RoB_NMA.md +96 -0
  111. package/skills/check-reporting/references/checklists/SPIRIT.md +112 -0
  112. package/skills/check-reporting/references/checklists/SQUIRE_2.md +68 -0
  113. package/skills/check-reporting/references/checklists/STARD.md +129 -0
  114. package/skills/check-reporting/references/checklists/STARD_AI.md +211 -0
  115. package/skills/check-reporting/references/checklists/STROBE.md +80 -0
  116. package/skills/check-reporting/references/checklists/SWiM.md +33 -0
  117. package/skills/check-reporting/references/checklists/TRIPOD.md +157 -0
  118. package/skills/check-reporting/references/checklists/TRIPOD_AI.md +140 -0
  119. package/skills/check-reporting/references/step4c_registration_timing.md +93 -0
  120. package/skills/check-reporting/references/step4d_prisma_figure_audit.md +137 -0
  121. package/skills/check-reporting/scripts/check_checklist_exists.py +183 -0
  122. package/skills/check-reporting/scripts/check_checklist_version.py +168 -0
  123. package/skills/check-reporting/scripts/check_framework_naming.py +206 -0
  124. package/skills/check-reporting/scripts/check_prisma_figure.py +209 -0
  125. package/skills/check-reporting/scripts/prisma_cascade_check.py +274 -0
  126. package/skills/check-reporting/skill.yml +41 -0
  127. package/skills/check-reporting/tests/fixtures/framework_bad.md +8 -0
  128. package/skills/check-reporting/tests/fixtures/framework_clean.md +7 -0
  129. package/skills/check-reporting/tests/test_checklist_fail_fast.sh +77 -0
  130. package/skills/check-reporting/tests/test_checklist_version.sh +72 -0
  131. package/skills/check-reporting/tests/test_framework_naming.sh +45 -0
  132. package/skills/check-reporting/tests/test_prisma_cascade.sh +104 -0
  133. package/skills/clean-data/SKILL.md +180 -0
  134. package/skills/clean-data/references/cleaning_patterns.md +299 -0
  135. package/skills/clean-data/references/profiling_template.py +304 -0
  136. package/skills/clean-data/scripts/check_structural_zero.py +174 -0
  137. package/skills/clean-data/skill.yml +35 -0
  138. package/skills/clean-data/tests/fixtures/smoking.csv +8 -0
  139. package/skills/clean-data/tests/test_structural_zero.sh +49 -0
  140. package/skills/cross-national/SKILL.md +264 -0
  141. package/skills/cross-national/skill.yml +37 -0
  142. package/skills/define-variables/SKILL.md +146 -0
  143. package/skills/define-variables/references/common_definitions.md +190 -0
  144. package/skills/define-variables/skill.yml +34 -0
  145. package/skills/define-variables/templates/variable_operationalization.md +64 -0
  146. package/skills/deidentify/SKILL.md +203 -0
  147. package/skills/deidentify/deidentify.py +1224 -0
  148. package/skills/deidentify/locales/_template.json +45 -0
  149. package/skills/deidentify/locales/au.json +43 -0
  150. package/skills/deidentify/locales/ca.json +44 -0
  151. package/skills/deidentify/locales/cn.json +47 -0
  152. package/skills/deidentify/locales/de.json +48 -0
  153. package/skills/deidentify/locales/fr.json +48 -0
  154. package/skills/deidentify/locales/in.json +48 -0
  155. package/skills/deidentify/locales/jp.json +48 -0
  156. package/skills/deidentify/locales/kr.json +48 -0
  157. package/skills/deidentify/locales/uk.json +45 -0
  158. package/skills/deidentify/locales/us.json +43 -0
  159. package/skills/deidentify/references/date_shift_guide.md +82 -0
  160. package/skills/deidentify/references/hipaa_18_identifiers.md +48 -0
  161. package/skills/deidentify/references/korean_phi_patterns.md +135 -0
  162. package/skills/deidentify/skill.yml +43 -0
  163. package/skills/deidentify/tests/README.md +26 -0
  164. package/skills/deidentify/tests/test_clean.csv +16 -0
  165. package/skills/deidentify/tests/test_edge_cases.csv +11 -0
  166. package/skills/deidentify/tests/test_phi_korean.csv +11 -0
  167. package/skills/design-ai-benchmarking/SKILL.md +214 -0
  168. package/skills/design-ai-benchmarking/references/benchmark_export_schema.json +69 -0
  169. package/skills/design-ai-benchmarking/references/elicitation_rubric_template.md +37 -0
  170. package/skills/design-ai-benchmarking/skill.yml +38 -0
  171. package/skills/design-study/SKILL.md +298 -0
  172. package/skills/design-study/skill.yml +33 -0
  173. package/skills/fill-icmje-coi/SKILL.md +216 -0
  174. package/skills/fill-icmje-coi/scripts/fill_icmje_coi.py +140 -0
  175. package/skills/fill-icmje-coi/skill.yml +35 -0
  176. package/skills/fill-icmje-coi/templates/icmje_coi_seed_synthetic.docx +0 -0
  177. package/skills/fill-protocol/SKILL.md +248 -0
  178. package/skills/fill-protocol/examples/example_irb_template.yaml +53 -0
  179. package/skills/fill-protocol/references/best_practices.md +121 -0
  180. package/skills/fill-protocol/scripts/doc_to_docx.py +111 -0
  181. package/skills/fill-protocol/scripts/fill_form.py +611 -0
  182. package/skills/fill-protocol/scripts/inspect_template.py +61 -0
  183. package/skills/fill-protocol/setup.sh +162 -0
  184. package/skills/fill-protocol/skill.yml +37 -0
  185. package/skills/find-cohort-gap/SKILL.md +309 -0
  186. package/skills/find-cohort-gap/references/cohort_profile_template.md +93 -0
  187. package/skills/find-cohort-gap/references/onepager_template.md +84 -0
  188. package/skills/find-cohort-gap/references/pattern_scoring_rubric.md +169 -0
  189. package/skills/find-cohort-gap/references/saturation_query_templates.md +143 -0
  190. package/skills/find-cohort-gap/skill.yml +35 -0
  191. package/skills/find-journal/POLICY.md +87 -0
  192. package/skills/find-journal/SKILL.md +340 -0
  193. package/skills/find-journal/references/journal_profiles/AJNR.md +29 -0
  194. package/skills/find-journal/references/journal_profiles/AJR.md +30 -0
  195. package/skills/find-journal/references/journal_profiles/Abdominal_Radiology.md +30 -0
  196. package/skills/find-journal/references/journal_profiles/Academic_Radiology.md +30 -0
  197. package/skills/find-journal/references/journal_profiles/Annals_of_Internal_Medicine.md +33 -0
  198. package/skills/find-journal/references/journal_profiles/Artificial_Intelligence_in_Medicine.md +28 -0
  199. package/skills/find-journal/references/journal_profiles/BMC_Medicine.md +31 -0
  200. package/skills/find-journal/references/journal_profiles/British_Journal_of_Radiology.md +39 -0
  201. package/skills/find-journal/references/journal_profiles/CVIR.md +30 -0
  202. package/skills/find-journal/references/journal_profiles/Chest.md +39 -0
  203. package/skills/find-journal/references/journal_profiles/Clinical_Radiology.md +30 -0
  204. package/skills/find-journal/references/journal_profiles/Clinical_and_Molecular_Hepatology.md +32 -0
  205. package/skills/find-journal/references/journal_profiles/Diabetes_Metabolism_Journal.md +36 -0
  206. package/skills/find-journal/references/journal_profiles/Diagnostic_and_Interventional_Radiology.md +32 -0
  207. package/skills/find-journal/references/journal_profiles/Endocrinology_and_Metabolism.md +37 -0
  208. package/skills/find-journal/references/journal_profiles/European_Journal_of_Preventive_Cardiology.md +39 -0
  209. package/skills/find-journal/references/journal_profiles/European_Radiology.md +29 -0
  210. package/skills/find-journal/references/journal_profiles/Hepatology_Communications.md +40 -0
  211. package/skills/find-journal/references/journal_profiles/Hepatology_International.md +37 -0
  212. package/skills/find-journal/references/journal_profiles/IEEE_JBHI.md +28 -0
  213. package/skills/find-journal/references/journal_profiles/IEEE_TMI.md +28 -0
  214. package/skills/find-journal/references/journal_profiles/INSI.md +29 -0
  215. package/skills/find-journal/references/journal_profiles/Investigative_Radiology.md +25 -0
  216. package/skills/find-journal/references/journal_profiles/JACC_Advances.md +41 -0
  217. package/skills/find-journal/references/journal_profiles/JACC_Asia.md +30 -0
  218. package/skills/find-journal/references/journal_profiles/JACR.md +28 -0
  219. package/skills/find-journal/references/journal_profiles/JAMA.md +40 -0
  220. package/skills/find-journal/references/journal_profiles/JAMA_Network_Open.md +30 -0
  221. package/skills/find-journal/references/journal_profiles/JCSM.md +39 -0
  222. package/skills/find-journal/references/journal_profiles/JKMS.md +32 -0
  223. package/skills/find-journal/references/journal_profiles/JMIR.md +29 -0
  224. package/skills/find-journal/references/journal_profiles/JMIR_Medical_Education.md +29 -0
  225. package/skills/find-journal/references/journal_profiles/JNIS.md +35 -0
  226. package/skills/find-journal/references/journal_profiles/JVIR.md +31 -0
  227. package/skills/find-journal/references/journal_profiles/Journal_of_Biomedical_Informatics.md +29 -0
  228. package/skills/find-journal/references/journal_profiles/Journal_of_Clinical_Endocrinology_and_Metabolism.md +40 -0
  229. package/skills/find-journal/references/journal_profiles/Journal_of_Magnetic_Resonance_Imaging.md +30 -0
  230. package/skills/find-journal/references/journal_profiles/Journal_of_Nuclear_Medicine.md +31 -0
  231. package/skills/find-journal/references/journal_profiles/Journal_of_Stroke.md +32 -0
  232. package/skills/find-journal/references/journal_profiles/KJR.md +38 -0
  233. package/skills/find-journal/references/journal_profiles/Korean_Circulation_Journal.md +38 -0
  234. package/skills/find-journal/references/journal_profiles/Korean_Journal_of_Internal_Medicine.md +36 -0
  235. package/skills/find-journal/references/journal_profiles/Lancet_Diabetes_and_Endocrinology.md +40 -0
  236. package/skills/find-journal/references/journal_profiles/Lancet_Gastroenterology_and_Hepatology.md +49 -0
  237. package/skills/find-journal/references/journal_profiles/Lancet_Infectious_Diseases.md +38 -0
  238. package/skills/find-journal/references/journal_profiles/Lancet_Neurology.md +39 -0
  239. package/skills/find-journal/references/journal_profiles/Lancet_Oncology.md +40 -0
  240. package/skills/find-journal/references/journal_profiles/Lancet_Psychiatry.md +38 -0
  241. package/skills/find-journal/references/journal_profiles/Lancet_Public_Health.md +30 -0
  242. package/skills/find-journal/references/journal_profiles/Lancet_Respiratory_Medicine.md +39 -0
  243. package/skills/find-journal/references/journal_profiles/Liver_International.md +33 -0
  244. package/skills/find-journal/references/journal_profiles/Medical_Image_Analysis.md +28 -0
  245. package/skills/find-journal/references/journal_profiles/NEJM.md +33 -0
  246. package/skills/find-journal/references/journal_profiles/Nature_Machine_Intelligence.md +31 -0
  247. package/skills/find-journal/references/journal_profiles/Nature_Medicine.md +39 -0
  248. package/skills/find-journal/references/journal_profiles/Neuroradiology.md +31 -0
  249. package/skills/find-journal/references/journal_profiles/Nutrition_Metabolism_and_Cardiovascular_Diseases.md +39 -0
  250. package/skills/find-journal/references/journal_profiles/PLOS_Medicine.md +32 -0
  251. package/skills/find-journal/references/journal_profiles/RYAI.md +28 -0
  252. package/skills/find-journal/references/journal_profiles/Radiology.md +29 -0
  253. package/skills/find-journal/references/journal_profiles/Skeletal_Radiology.md +31 -0
  254. package/skills/find-journal/references/journal_profiles/Stroke.md +37 -0
  255. package/skills/find-journal/references/journal_profiles/The_BMJ.md +31 -0
  256. package/skills/find-journal/references/journal_profiles/The_Lancet.md +31 -0
  257. package/skills/find-journal/references/journal_profiles/The_Lancet_Digital_Health.md +29 -0
  258. package/skills/find-journal/references/journal_profiles/World_Journal_of_Hepatology.md +53 -0
  259. package/skills/find-journal/references/journal_profiles/npj_Digital_Medicine.md +29 -0
  260. package/skills/find-journal/skill.yml +34 -0
  261. package/skills/fulltext-retrieval/SKILL.md +174 -0
  262. package/skills/fulltext-retrieval/fetch_oa.py +433 -0
  263. package/skills/fulltext-retrieval/pdf_to_md.py +160 -0
  264. package/skills/fulltext-retrieval/skill.yml +41 -0
  265. package/skills/generate-codebook/SKILL.md +155 -0
  266. package/skills/generate-codebook/references/codebook_schema.md +76 -0
  267. package/skills/generate-codebook/scripts/generate_codebook.py +278 -0
  268. package/skills/generate-codebook/skill.yml +35 -0
  269. package/skills/generate-codebook/tests/test_generate_codebook.sh +76 -0
  270. package/skills/grant-builder/SKILL.md +251 -0
  271. package/skills/grant-builder/skill.yml +34 -0
  272. package/skills/humanize/SKILL.md +251 -0
  273. package/skills/humanize/references/ai_patterns.md +571 -0
  274. package/skills/humanize/skill.yml +33 -0
  275. package/skills/intake-project/SKILL.md +264 -0
  276. package/skills/intake-project/skill.yml +34 -0
  277. package/skills/lit-sync/SKILL.md +448 -0
  278. package/skills/lit-sync/references/locale/ko/note_templates.md +110 -0
  279. package/skills/lit-sync/skill.yml +52 -0
  280. package/skills/lit-sync/tests/test_poll_logic.sh +92 -0
  281. package/skills/ma-scout/SKILL.md +640 -0
  282. package/skills/ma-scout/references/project_readme_template.md +95 -0
  283. package/skills/ma-scout/references/project_readme_template_ko.md +82 -0
  284. package/skills/ma-scout/skill.yml +33 -0
  285. package/skills/make-figures/SKILL.md +957 -0
  286. package/skills/make-figures/references/critic_rubrics/data_plot.md +166 -0
  287. package/skills/make-figures/references/critic_rubrics/flow_diagram.md +169 -0
  288. package/skills/make-figures/references/design_principles.md +181 -0
  289. package/skills/make-figures/references/exemplar_diagrams/README.md +65 -0
  290. package/skills/make-figures/references/exemplar_diagrams/consort/README.md +15 -0
  291. package/skills/make-figures/references/exemplar_diagrams/consort/template_input.yaml +37 -0
  292. package/skills/make-figures/references/exemplar_diagrams/consort/template_output.pdf +0 -0
  293. package/skills/make-figures/references/exemplar_diagrams/consort/template_output.png +0 -0
  294. package/skills/make-figures/references/exemplar_diagrams/consort/template_output_600.png +0 -0
  295. package/skills/make-figures/references/exemplar_diagrams/other/other_02.meta.yaml +4 -0
  296. package/skills/make-figures/references/exemplar_diagrams/other/other_02.png +0 -0
  297. package/skills/make-figures/references/exemplar_diagrams/other/other_02_why.md +13 -0
  298. package/skills/make-figures/references/exemplar_diagrams/pipeline/README.md +15 -0
  299. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_01.meta.yaml +4 -0
  300. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_01.png +0 -0
  301. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_01_why.md +13 -0
  302. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_03.meta.yaml +4 -0
  303. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_03.png +0 -0
  304. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_03_why.md +13 -0
  305. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_04.meta.yaml +4 -0
  306. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_04.png +0 -0
  307. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_04_why.md +13 -0
  308. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_05.meta.yaml +4 -0
  309. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_05.png +0 -0
  310. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_05_why.md +13 -0
  311. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_06.meta.yaml +4 -0
  312. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_06.png +0 -0
  313. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_06_why.md +13 -0
  314. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_07.meta.yaml +4 -0
  315. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_07.png +0 -0
  316. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_07_why.md +13 -0
  317. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_08.meta.yaml +4 -0
  318. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_08.png +0 -0
  319. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_08_why.md +13 -0
  320. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_09.meta.yaml +4 -0
  321. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_09.png +0 -0
  322. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_09_why.md +13 -0
  323. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_10.meta.yaml +4 -0
  324. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_10.png +0 -0
  325. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_10_why.md +13 -0
  326. package/skills/make-figures/references/exemplar_diagrams/prisma/README.md +15 -0
  327. package/skills/make-figures/references/exemplar_diagrams/prisma/template_input.yaml +47 -0
  328. package/skills/make-figures/references/exemplar_diagrams/prisma/template_output.pdf +0 -0
  329. package/skills/make-figures/references/exemplar_diagrams/prisma/template_output.png +0 -0
  330. package/skills/make-figures/references/exemplar_diagrams/prisma/template_output_600.png +0 -0
  331. package/skills/make-figures/references/exemplar_diagrams/stard/README.md +15 -0
  332. package/skills/make-figures/references/exemplar_diagrams/stard/template_input.yaml +40 -0
  333. package/skills/make-figures/references/exemplar_diagrams/stard/template_output.pdf +0 -0
  334. package/skills/make-figures/references/exemplar_diagrams/stard/template_output.png +0 -0
  335. package/skills/make-figures/references/exemplar_diagrams/stard/template_output_600.png +0 -0
  336. package/skills/make-figures/references/exemplar_diagrams/strobe/template_input.yaml +43 -0
  337. package/skills/make-figures/references/exemplar_diagrams/strobe/template_input_pptx.yaml +43 -0
  338. package/skills/make-figures/references/exemplar_diagrams/strobe/template_output.pdf +0 -0
  339. package/skills/make-figures/references/exemplar_diagrams/strobe/template_output.png +0 -0
  340. package/skills/make-figures/references/exemplar_diagrams/strobe/template_output.pptx +0 -0
  341. package/skills/make-figures/references/exemplar_diagrams/strobe/template_output_600.png +0 -0
  342. package/skills/make-figures/references/figure_specs.md +291 -0
  343. package/skills/make-figures/references/flow_diagram_lessons.md +164 -0
  344. package/skills/make-figures/references/jacc_central_illustration_principles.md +91 -0
  345. package/skills/make-figures/references/medical_illustration_sources.md +98 -0
  346. package/skills/make-figures/references/pipeline_concepts_medical_ai.md +240 -0
  347. package/skills/make-figures/references/reporting_guideline_figure_map.md +104 -0
  348. package/skills/make-figures/references/visual_abstract_templates/european_radiology.pptx +0 -0
  349. package/skills/make-figures/references/visual_abstract_templates/jacc_central_illustration.pptx +0 -0
  350. package/skills/make-figures/references/visual_abstract_templates/medsci_default.pptx +0 -0
  351. package/skills/make-figures/references/visual_abstract_templates/template_guide.md +114 -0
  352. package/skills/make-figures/scripts/build_jacc_template.py +77 -0
  353. package/skills/make-figures/scripts/build_prisma2020_template.py +371 -0
  354. package/skills/make-figures/scripts/build_strobe_template.py +351 -0
  355. package/skills/make-figures/scripts/critic_figure.py +264 -0
  356. package/skills/make-figures/scripts/derive_figure_legend_counts.py +138 -0
  357. package/skills/make-figures/scripts/extract_exemplar_from_pdf.py +186 -0
  358. package/skills/make-figures/scripts/fetch_official_templates.sh +88 -0
  359. package/skills/make-figures/scripts/fill_prisma_template.py +142 -0
  360. package/skills/make-figures/scripts/generate_flow_diagram.R +133 -0
  361. package/skills/make-figures/scripts/generate_image.py +99 -0
  362. package/skills/make-figures/scripts/generate_visual_abstract.py +438 -0
  363. package/skills/make-figures/scripts/validate_pptx_mac_compat.py +233 -0
  364. package/skills/make-figures/skill.yml +52 -0
  365. package/skills/make-figures/templates/official/NOTES.md +62 -0
  366. package/skills/make-figures/templates/official/consort2010/CONSORT_2025_editable_checklist.docx +0 -0
  367. package/skills/make-figures/templates/official/consort2010/CONSORT_2025_flow_diagram.docx +0 -0
  368. package/skills/make-figures/templates/official/prisma2020/PRISMA_2020_flow_new_v1.pptx +0 -0
  369. package/skills/make-figures/templates/official/prisma2020/PRISMA_2020_flow_new_v2.pptx +0 -0
  370. package/skills/make-figures/templates/official/prisma2020/PRISMA_2020_flow_updated_v2.pptx +0 -0
  371. package/skills/make-figures/templates/official/spirit2013/SPIRIT_2025_editable_checklist.docx +0 -0
  372. package/skills/make-figures/templates/official/spirit2013/SPIRIT_2025_participant_timeline.docx +0 -0
  373. package/skills/make-figures/templates/official/stard2015/STARD_2015_checklist.docx +0 -0
  374. package/skills/make-figures/templates/official/stard2015/STARD_2015_flow_diagram.pdf +0 -0
  375. package/skills/make-figures/tests/fixtures/figure1_flow.yaml +8 -0
  376. package/skills/make-figures/tests/fixtures/manuscript_ok.md +9 -0
  377. package/skills/make-figures/tests/fixtures/manuscript_stale.md +4 -0
  378. package/skills/make-figures/tests/test_legend_reconcile.sh +36 -0
  379. package/skills/manage-project/SKILL.md +358 -0
  380. package/skills/manage-project/references/pre_submission_checklist.md +53 -0
  381. package/skills/manage-project/references/project_state_template.json +37 -0
  382. package/skills/manage-project/references/scaffold_templates.md +118 -0
  383. package/skills/manage-project/references/status_output_format.md +44 -0
  384. package/skills/manage-project/references/timeline_example.md +20 -0
  385. package/skills/manage-project/skill.yml +36 -0
  386. package/skills/manage-project/templates/SSOT.yaml.template +41 -0
  387. package/skills/manage-refs/LICENSE.zotero-mcp +21 -0
  388. package/skills/manage-refs/NOTICE.md +29 -0
  389. package/skills/manage-refs/SKILL.md +289 -0
  390. package/skills/manage-refs/citation_styles/README.md +40 -0
  391. package/skills/manage-refs/citation_styles/american-journal-of-roentgenology.csl +211 -0
  392. package/skills/manage-refs/citation_styles/cardiovascular-and-interventional-radiology.csl +19 -0
  393. package/skills/manage-refs/citation_styles/european-radiology.csl +19 -0
  394. package/skills/manage-refs/citation_styles/journal-of-cachexia-sarcopenia-and-muscle.csl +150 -0
  395. package/skills/manage-refs/citation_styles/journal-of-korean-medical-science-strict.csl +533 -0
  396. package/skills/manage-refs/citation_styles/journal-of-korean-medical-science.csl +16 -0
  397. package/skills/manage-refs/citation_styles/korean-journal-of-radiology.csl +155 -0
  398. package/skills/manage-refs/citation_styles/nature.csl +189 -0
  399. package/skills/manage-refs/citation_styles/nlm-citation-sequence.csl +535 -0
  400. package/skills/manage-refs/citation_styles/radiology.csl +228 -0
  401. package/skills/manage-refs/citation_styles/springer-basic-brackets.csl +187 -0
  402. package/skills/manage-refs/citation_styles/springer-vancouver-brackets.csl +276 -0
  403. package/skills/manage-refs/citation_styles/vancouver-superscript.csl +536 -0
  404. package/skills/manage-refs/citation_styles/vancouver.csl +535 -0
  405. package/skills/manage-refs/references/REFERENCE_STYLE_SPECS.md +59 -0
  406. package/skills/manage-refs/references/check_xref_symptoms.md +35 -0
  407. package/skills/manage-refs/scripts/_vendor_citation_writer.py +600 -0
  408. package/skills/manage-refs/scripts/check_citation_keys.py +112 -0
  409. package/skills/manage-refs/scripts/check_csl_render.py +102 -0
  410. package/skills/manage-refs/scripts/check_xref.py +633 -0
  411. package/skills/manage-refs/scripts/fill_journal_abbrev.py +104 -0
  412. package/skills/manage-refs/scripts/inject_zotero_cwyw.py +133 -0
  413. package/skills/manage-refs/scripts/md_marker_convert.py +193 -0
  414. package/skills/manage-refs/scripts/pre_submission_gate.sh +238 -0
  415. package/skills/manage-refs/scripts/render_pandoc.sh +88 -0
  416. package/skills/manage-refs/skill.yml +70 -0
  417. package/skills/manage-refs/tests/fixtures/pre_submission_gate/README.md +32 -0
  418. package/skills/manage-refs/tests/fixtures/pre_submission_gate/manuscript.md +10 -0
  419. package/skills/manage-refs/tests/fixtures/pre_submission_gate/refs.bib +34 -0
  420. package/skills/manage-refs/tests/fixtures/pre_submission_gate/run.sh +117 -0
  421. package/skills/manage-refs/tests/test_vN_docx_check.sh +145 -0
  422. package/skills/meta-analysis/SKILL.md +739 -0
  423. package/skills/meta-analysis/references/LICENSES.md +21 -0
  424. package/skills/meta-analysis/references/PROSPERO_template.md +221 -0
  425. package/skills/meta-analysis/references/ai_pre_screening_template.py +245 -0
  426. package/skills/meta-analysis/references/checklists/JBI_Case_Series.md +45 -0
  427. package/skills/meta-analysis/references/checklists/NOS.md +88 -0
  428. package/skills/meta-analysis/references/checklists/PRISMA_DTA.md +36 -0
  429. package/skills/meta-analysis/references/checklists/PROBAST.md +75 -0
  430. package/skills/meta-analysis/references/checklists/QUADAS2.md +77 -0
  431. package/skills/meta-analysis/references/checklists/ROBINS_I.md +87 -0
  432. package/skills/meta-analysis/references/checklists/RoB2.md +79 -0
  433. package/skills/meta-analysis/references/data_integrity_checklist.md +57 -0
  434. package/skills/meta-analysis/references/icmje_coi_guide.md +181 -0
  435. package/skills/meta-analysis/references/phase10_recovery.md +136 -0
  436. package/skills/meta-analysis/references/phase4_km_composite.md +58 -0
  437. package/skills/meta-analysis/references/phase6_statistical_synthesis.md +148 -0
  438. package/skills/meta-analysis/references/phase9_circulation.md +84 -0
  439. package/skills/meta-analysis/references/post_submission_release_ops.md +41 -0
  440. package/skills/meta-analysis/references/r_templates.md +132 -0
  441. package/skills/meta-analysis/references/review_orchestration.md +40 -0
  442. package/skills/meta-analysis/references/submission_package_drift.md +71 -0
  443. package/skills/meta-analysis/scripts/check_pool_consistency.py +201 -0
  444. package/skills/meta-analysis/scripts/cohort_overlap_check.py +242 -0
  445. package/skills/meta-analysis/scripts/dta_extraction_qc.py +137 -0
  446. package/skills/meta-analysis/scripts/screening_reconcile.py +160 -0
  447. package/skills/meta-analysis/skill.yml +47 -0
  448. package/skills/meta-analysis/templates/FINAL_POOL_LOCK.yaml.template +70 -0
  449. package/skills/meta-analysis/templates/extraction_form_v2.md +129 -0
  450. package/skills/meta-analysis/templates/supplementary_8file_checklist.md +94 -0
  451. package/skills/meta-analysis/tests/test_pool_consistency.sh +123 -0
  452. package/skills/orchestrate/SKILL.md +501 -0
  453. package/skills/orchestrate/references/dialogue_nodes.md +196 -0
  454. package/skills/orchestrate/references/report_template.md +109 -0
  455. package/skills/orchestrate/references/report_template_ko.md +88 -0
  456. package/skills/orchestrate/skill.yml +44 -0
  457. package/skills/peer-review/SKILL.md +381 -0
  458. package/skills/peer-review/references/aczel_2021_reviewer2_patterns.md +88 -0
  459. package/skills/peer-review/references/domain-probes/ai_overclaiming.md +47 -0
  460. package/skills/peer-review/references/domain-probes/narrative_review.md +44 -0
  461. package/skills/peer-review/references/domain-probes/observational_confounding.md +48 -0
  462. package/skills/peer-review/references/domain-probes/radiomics.md +38 -0
  463. package/skills/peer-review/references/domain-probes/sr_ma.md +87 -0
  464. package/skills/peer-review/references/domain-probes/survival_prognostic.md +68 -0
  465. package/skills/peer-review/references/exemplar_reviews/README.md +43 -0
  466. package/skills/peer-review/references/exemplar_reviews/ai_overclaiming.md +47 -0
  467. package/skills/peer-review/references/exemplar_reviews/calibration_missing.md +44 -0
  468. package/skills/peer-review/references/exemplar_reviews/data_leakage.md +48 -0
  469. package/skills/peer-review/references/exemplar_reviews/reference_standard_validity.md +45 -0
  470. package/skills/peer-review/references/narrative_review_audit.md +67 -0
  471. package/skills/peer-review/references/reviewer_calibration/README.md +34 -0
  472. package/skills/peer-review/references/reviewer_calibration/compliance_floor.md +52 -0
  473. package/skills/peer-review/references/reviewer_profiles/AJR.md +82 -0
  474. package/skills/peer-review/references/reviewer_profiles/EURE.md +64 -0
  475. package/skills/peer-review/references/reviewer_profiles/INSI.md +57 -0
  476. package/skills/peer-review/references/reviewer_profiles/KJR.md +100 -0
  477. package/skills/peer-review/references/reviewer_profiles/README.md +32 -0
  478. package/skills/peer-review/references/reviewer_profiles/RYAI.md +86 -0
  479. package/skills/peer-review/skill.yml +39 -0
  480. package/skills/present-paper/SKILL.md +675 -0
  481. package/skills/present-paper/references/critic_rubrics/slide.md +155 -0
  482. package/skills/present-paper/references/generate_pptx_templates.py +604 -0
  483. package/skills/present-paper/references/medical_presentation_templates.md +277 -0
  484. package/skills/present-paper/references/slide_design_principles.md +202 -0
  485. package/skills/present-paper/references/slide_visual_styles/nature_lancet.md +168 -0
  486. package/skills/present-paper/references/workflow-checklist.md +109 -0
  487. package/skills/present-paper/scripts/extract_pdf_figures.py +243 -0
  488. package/skills/present-paper/scripts/inject_pronunciation_notes.py +178 -0
  489. package/skills/present-paper/scripts/inject_speaker_notes.py +133 -0
  490. package/skills/present-paper/scripts/strip_notes_for_sharing.py +140 -0
  491. package/skills/present-paper/scripts/trim_caption.py +271 -0
  492. package/skills/present-paper/skill.yml +41 -0
  493. package/skills/present-paper/templates/build_pptx_nature_lancet.py +688 -0
  494. package/skills/publish-skill/SKILL.md +370 -0
  495. package/skills/publish-skill/references/license-compatibility-matrix.md +132 -0
  496. package/skills/publish-skill/references/pii-patterns.md +130 -0
  497. package/skills/publish-skill/scripts/audit_skill.sh +278 -0
  498. package/skills/publish-skill/skill.yml +35 -0
  499. package/skills/render-pdf-doc/SKILL.md +146 -0
  500. package/skills/render-pdf-doc/references/known_pitfalls.md +53 -0
  501. package/skills/render-pdf-doc/references/pandoc_korean_cheatsheet.md +77 -0
  502. package/skills/render-pdf-doc/scripts/check_deps.sh +42 -0
  503. package/skills/render-pdf-doc/scripts/infer_colwidths.py +164 -0
  504. package/skills/render-pdf-doc/scripts/render_pdf.sh +98 -0
  505. package/skills/render-pdf-doc/skill.yml +57 -0
  506. package/skills/render-pdf-doc/templates/anchor-doc.md +27 -0
  507. package/skills/render-pdf-doc/templates/anchor-doc_ko.md +25 -0
  508. package/skills/render-pdf-doc/templates/briefing-handout.md +33 -0
  509. package/skills/render-pdf-doc/templates/briefing-handout_ko.md +31 -0
  510. package/skills/render-pdf-doc/templates/proposal-cover.md +33 -0
  511. package/skills/render-pdf-doc/templates/proposal-cover_ko.md +31 -0
  512. package/skills/render-pdf-doc/templates/reference-table.md +22 -0
  513. package/skills/render-pdf-doc/templates/reference-table_ko.md +20 -0
  514. package/skills/replicate-study/SKILL.md +150 -0
  515. package/skills/replicate-study/references/harmonization_3country.csv +47 -0
  516. package/skills/replicate-study/references/harmonization_knhanes_nhanes.csv +68 -0
  517. package/skills/replicate-study/references/methodology_extraction_template.md +134 -0
  518. package/skills/replicate-study/skill.yml +37 -0
  519. package/skills/review-paper/SKILL.md +104 -0
  520. package/skills/review-paper/references/macro_skeleton.md +6 -0
  521. package/skills/review-paper/skill.yml +25 -0
  522. package/skills/revise/SKILL.md +515 -0
  523. package/skills/revise/references/r2r_voice.md +346 -0
  524. package/skills/revise/skill.yml +43 -0
  525. package/skills/search-lit/SKILL.md +443 -0
  526. package/skills/search-lit/references/parse_pubmed.py +326 -0
  527. package/skills/search-lit/references/pubmed_eutils.sh +111 -0
  528. package/skills/search-lit/skill.yml +46 -0
  529. package/skills/self-review/SKILL.md +1045 -0
  530. package/skills/self-review/references/domain-probes/ai_overclaiming.md +47 -0
  531. package/skills/self-review/references/domain-probes/narrative_review.md +44 -0
  532. package/skills/self-review/references/domain-probes/observational_confounding.md +48 -0
  533. package/skills/self-review/references/domain-probes/radiomics.md +38 -0
  534. package/skills/self-review/references/domain-probes/sr_ma.md +87 -0
  535. package/skills/self-review/references/domain-probes/survival_prognostic.md +68 -0
  536. package/skills/self-review/references/exemplar_findings/README.md +43 -0
  537. package/skills/self-review/references/exemplar_findings/cohort_arithmetic_mismatch.md +35 -0
  538. package/skills/self-review/references/exemplar_findings/estimand_drift_posthoc_primary.md +39 -0
  539. package/skills/self-review/references/exemplar_findings/scope_overreach_cross_sectional.md +35 -0
  540. package/skills/self-review/references/exemplar_findings/unadjusted_confounder.md +36 -0
  541. package/skills/self-review/references/panel_review_template.md +177 -0
  542. package/skills/self-review/scripts/check_artifact_coverage.py +301 -0
  543. package/skills/self-review/scripts/check_claim_artifact.py +248 -0
  544. package/skills/self-review/scripts/check_classical_style.py +185 -0
  545. package/skills/self-review/scripts/check_cohort_arithmetic.py +481 -0
  546. package/skills/self-review/scripts/check_confounding_completeness.py +287 -0
  547. package/skills/self-review/scripts/check_panel_diversity.py +336 -0
  548. package/skills/self-review/scripts/check_reference_adequacy.py +392 -0
  549. package/skills/self-review/scripts/check_reviewer_team_consistency.py +412 -0
  550. package/skills/self-review/scripts/check_scope_coherence.py +177 -0
  551. package/skills/self-review/skill.yml +47 -0
  552. package/skills/self-review/tests/fixtures/claim_manuscript.md +17 -0
  553. package/skills/self-review/tests/fixtures/claim_prereg.md +6 -0
  554. package/skills/self-review/tests/fixtures/cohort_bad.md +21 -0
  555. package/skills/self-review/tests/fixtures/cohort_clean.md +21 -0
  556. package/skills/self-review/tests/fixtures/cohort_partition.csv +5 -0
  557. package/skills/self-review/tests/fixtures/coverage_analysis/31_delong_nested_added_value.csv +3 -0
  558. package/skills/self-review/tests/fixtures/coverage_analysis/table1_demographics.csv +3 -0
  559. package/skills/self-review/tests/fixtures/coverage_clean.md +13 -0
  560. package/skills/self-review/tests/fixtures/coverage_manuscript.md +11 -0
  561. package/skills/self-review/tests/fixtures/panel_collapse.json +27 -0
  562. package/skills/self-review/tests/fixtures/panel_good.json +32 -0
  563. package/skills/self-review/tests/fixtures/panel_monoculture.json +32 -0
  564. package/skills/self-review/tests/fixtures/refadeq_letter.md +13 -0
  565. package/skills/self-review/tests/fixtures/refadeq_original_fixed.md +42 -0
  566. package/skills/self-review/tests/fixtures/refadeq_original_uncited.md +40 -0
  567. package/skills/self-review/tests/fixtures/scope_bad.md +9 -0
  568. package/skills/self-review/tests/fixtures/scope_clean.md +8 -0
  569. package/skills/self-review/tests/fixtures/scope_surrogate.md +8 -0
  570. package/skills/self-review/tests/fixtures/style_bad.md +13 -0
  571. package/skills/self-review/tests/fixtures/style_clean.md +11 -0
  572. package/skills/self-review/tests/fixtures/table1_by_exposure.csv +11 -0
  573. package/skills/self-review/tests/test_artifact_coverage.sh +44 -0
  574. package/skills/self-review/tests/test_claim_artifact.sh +50 -0
  575. package/skills/self-review/tests/test_classical_style.sh +44 -0
  576. package/skills/self-review/tests/test_cohort_arithmetic.sh +49 -0
  577. package/skills/self-review/tests/test_confounding_completeness.sh +66 -0
  578. package/skills/self-review/tests/test_panel_diversity.sh +55 -0
  579. package/skills/self-review/tests/test_panel_mode.sh +69 -0
  580. package/skills/self-review/tests/test_reference_adequacy.sh +68 -0
  581. package/skills/self-review/tests/test_reviewer_team_consistency.sh +138 -0
  582. package/skills/self-review/tests/test_scope_coherence.sh +46 -0
  583. package/skills/setup-medsci/SKILL.md +110 -0
  584. package/skills/setup-medsci/references/setup-checklist.md +51 -0
  585. package/skills/setup-medsci/skill.yml +30 -0
  586. package/skills/sync-submission/SKILL.md +382 -0
  587. package/skills/sync-submission/scripts/author_registry_example.yaml +36 -0
  588. package/skills/sync-submission/scripts/blind_sweep.py +203 -0
  589. package/skills/sync-submission/scripts/check_asset_anonymization.py +300 -0
  590. package/skills/sync-submission/scripts/check_cross_artifact_stale.py +211 -0
  591. package/skills/sync-submission/scripts/cover_letter_drift_check.py +451 -0
  592. package/skills/sync-submission/scripts/cross_document_n_check.py +486 -0
  593. package/skills/sync-submission/scripts/detect_copy_divergence.py +136 -0
  594. package/skills/sync-submission/scripts/preflight_gate.py +458 -0
  595. package/skills/sync-submission/scripts/scope_drift_check.py +362 -0
  596. package/skills/sync-submission/scripts/sync_submission.py +169 -0
  597. package/skills/sync-submission/skill.yml +43 -0
  598. package/skills/sync-submission/tests/fixtures/copy_ok.md +5 -0
  599. package/skills/sync-submission/tests/fixtures/copy_stale.md +5 -0
  600. package/skills/sync-submission/tests/fixtures/ssot.md +5 -0
  601. package/skills/sync-submission/tests/test_asset_anonymization.sh +99 -0
  602. package/skills/sync-submission/tests/test_copy_divergence.sh +44 -0
  603. package/skills/sync-submission/tests/test_cross_artifact_stale.sh +80 -0
  604. package/skills/sync-submission/tests/test_cross_document_n.sh +132 -0
  605. package/skills/sync-submission/tests/test_preflight_gate.sh +112 -0
  606. package/skills/sync-submission/tests/test_scope_drift.sh +122 -0
  607. package/skills/sync-submission/tests/test_vN_docx_assertion.sh +51 -0
  608. package/skills/verify-refs/SKILL.md +177 -0
  609. package/skills/verify-refs/references/manual_checkpoint_guide.md +100 -0
  610. package/skills/verify-refs/scripts/verify_cli.sh +62 -0
  611. package/skills/verify-refs/scripts/verify_refs.py +782 -0
  612. package/skills/verify-refs/skill.yml +44 -0
  613. package/skills/verify-refs/tests/fixtures/pagination_placeholder.bib +17 -0
  614. package/skills/verify-refs/tests/test_pagination_placeholder.sh +42 -0
  615. package/skills/version-dataset/SKILL.md +143 -0
  616. package/skills/version-dataset/references/manifest_schema.md +72 -0
  617. package/skills/version-dataset/scripts/version_dataset.py +242 -0
  618. package/skills/version-dataset/skill.yml +35 -0
  619. package/skills/version-dataset/tests/test_version_dataset.sh +52 -0
  620. package/skills/write-paper/SKILL.md +1148 -0
  621. package/skills/write-paper/references/exemplar_methods/README.md +38 -0
  622. package/skills/write-paper/references/exemplar_methods/ai_validation_tripod_claim.md +47 -0
  623. package/skills/write-paper/references/exemplar_methods/diagnostic_accuracy_stard.md +50 -0
  624. package/skills/write-paper/references/exemplar_methods/observational_cohort_strobe.md +43 -0
  625. package/skills/write-paper/references/journal_profiles/AJNR.md +185 -0
  626. package/skills/write-paper/references/journal_profiles/AJR.md +149 -0
  627. package/skills/write-paper/references/journal_profiles/Abdominal_Radiology.md +139 -0
  628. package/skills/write-paper/references/journal_profiles/Academic_Radiology.md +90 -0
  629. package/skills/write-paper/references/journal_profiles/Annals_of_Internal_Medicine.md +150 -0
  630. package/skills/write-paper/references/journal_profiles/Artificial_Intelligence_in_Medicine.md +82 -0
  631. package/skills/write-paper/references/journal_profiles/British_Journal_of_Radiology.md +161 -0
  632. package/skills/write-paper/references/journal_profiles/CVIR.md +157 -0
  633. package/skills/write-paper/references/journal_profiles/Chest.md +270 -0
  634. package/skills/write-paper/references/journal_profiles/Clinical_Radiology.md +160 -0
  635. package/skills/write-paper/references/journal_profiles/Clinical_and_Molecular_Hepatology.md +147 -0
  636. package/skills/write-paper/references/journal_profiles/Diabetes_Metabolism_Journal.md +163 -0
  637. package/skills/write-paper/references/journal_profiles/Diagnostic_and_Interventional_Radiology.md +216 -0
  638. package/skills/write-paper/references/journal_profiles/Endocrinology_and_Metabolism.md +167 -0
  639. package/skills/write-paper/references/journal_profiles/European_Journal_of_Preventive_Cardiology.md +192 -0
  640. package/skills/write-paper/references/journal_profiles/European_Radiology.md +159 -0
  641. package/skills/write-paper/references/journal_profiles/Hepatology_Communications.md +110 -0
  642. package/skills/write-paper/references/journal_profiles/Hepatology_International.md +106 -0
  643. package/skills/write-paper/references/journal_profiles/IEEE_TMI.md +180 -0
  644. package/skills/write-paper/references/journal_profiles/INSI.md +163 -0
  645. package/skills/write-paper/references/journal_profiles/Investigative_Radiology.md +86 -0
  646. package/skills/write-paper/references/journal_profiles/JACC_Advances.md +197 -0
  647. package/skills/write-paper/references/journal_profiles/JACC_Asia.md +168 -0
  648. package/skills/write-paper/references/journal_profiles/JACR.md +87 -0
  649. package/skills/write-paper/references/journal_profiles/JAMA.md +188 -0
  650. package/skills/write-paper/references/journal_profiles/JAMA_Network_Open.md +170 -0
  651. package/skills/write-paper/references/journal_profiles/JCSM.md +266 -0
  652. package/skills/write-paper/references/journal_profiles/JKMS.md +201 -0
  653. package/skills/write-paper/references/journal_profiles/JMIR.md +88 -0
  654. package/skills/write-paper/references/journal_profiles/JMIR_Medical_Education.md +86 -0
  655. package/skills/write-paper/references/journal_profiles/JNIS.md +227 -0
  656. package/skills/write-paper/references/journal_profiles/JVIR.md +158 -0
  657. package/skills/write-paper/references/journal_profiles/Journal_of_Clinical_Endocrinology_and_Metabolism.md +191 -0
  658. package/skills/write-paper/references/journal_profiles/Journal_of_Stroke.md +176 -0
  659. package/skills/write-paper/references/journal_profiles/KJR.md +185 -0
  660. package/skills/write-paper/references/journal_profiles/Korean_Circulation_Journal.md +184 -0
  661. package/skills/write-paper/references/journal_profiles/Korean_Journal_of_Internal_Medicine.md +178 -0
  662. package/skills/write-paper/references/journal_profiles/Lancet_Gastroenterology_and_Hepatology.md +127 -0
  663. package/skills/write-paper/references/journal_profiles/Liver_International.md +165 -0
  664. package/skills/write-paper/references/journal_profiles/Medical_Image_Analysis.md +147 -0
  665. package/skills/write-paper/references/journal_profiles/NEJM.md +147 -0
  666. package/skills/write-paper/references/journal_profiles/Nature_Medicine.md +181 -0
  667. package/skills/write-paper/references/journal_profiles/Neuroradiology.md +151 -0
  668. package/skills/write-paper/references/journal_profiles/Nutrition_Metabolism_and_Cardiovascular_Diseases.md +184 -0
  669. package/skills/write-paper/references/journal_profiles/PLOS_Medicine.md +166 -0
  670. package/skills/write-paper/references/journal_profiles/RYAI.md +124 -0
  671. package/skills/write-paper/references/journal_profiles/Radiology.md +173 -0
  672. package/skills/write-paper/references/journal_profiles/Skeletal_Radiology.md +135 -0
  673. package/skills/write-paper/references/journal_profiles/Stroke.md +210 -0
  674. package/skills/write-paper/references/journal_profiles/The_BMJ.md +121 -0
  675. package/skills/write-paper/references/journal_profiles/The_Lancet.md +112 -0
  676. package/skills/write-paper/references/journal_profiles/The_Lancet_Digital_Health.md +104 -0
  677. package/skills/write-paper/references/journal_profiles/World_Journal_of_Hepatology.md +106 -0
  678. package/skills/write-paper/references/journal_profiles/npj_Digital_Medicine.md +93 -0
  679. package/skills/write-paper/references/paper_types/ai_validation.md +270 -0
  680. package/skills/write-paper/references/paper_types/animal_study.md +194 -0
  681. package/skills/write-paper/references/paper_types/case_report.md +237 -0
  682. package/skills/write-paper/references/paper_types/cross_national.md +328 -0
  683. package/skills/write-paper/references/paper_types/letter.md +127 -0
  684. package/skills/write-paper/references/paper_types/meta_analysis.md +181 -0
  685. package/skills/write-paper/references/paper_types/nhis_cohort.md +297 -0
  686. package/skills/write-paper/references/paper_types/original_article.md +221 -0
  687. package/skills/write-paper/references/paper_types/technical_note.md +131 -0
  688. package/skills/write-paper/references/section_guides/discussion.md +155 -0
  689. package/skills/write-paper/references/section_guides/introduction.md +108 -0
  690. package/skills/write-paper/references/section_guides/methods.md +144 -0
  691. package/skills/write-paper/references/section_guides/results.md +113 -0
  692. package/skills/write-paper/references/section_guides/step7_1_classical_qc.md +67 -0
  693. package/skills/write-paper/references/section_guides/step7_4a_audit_recovery.md +74 -0
  694. package/skills/write-paper/references/section_guides/title_abstract.md +123 -0
  695. package/skills/write-paper/references/section_templates/methods_statistical.md +147 -0
  696. package/skills/write-paper/scripts/check_placeholders.py +182 -0
  697. package/skills/write-paper/skill.yml +48 -0
  698. package/skills/write-paper/tests/test_placeholders.sh +107 -0
  699. package/skills/write-protocol/SKILL.md +243 -0
  700. package/skills/write-protocol/references/ethics_checklist.md +150 -0
  701. package/skills/write-protocol/references/protocol_template.md +304 -0
  702. package/skills/write-protocol/skill.yml +34 -0
@@ -0,0 +1,109 @@
1
+ # Presentation Preparation Checklist
2
+
3
+ Use this checklist to verify completeness at each phase.
4
+
5
+ ---
6
+
7
+ ## Phase 0: Init & Outline
8
+
9
+ ### Paper Analysis
10
+ - [ ] Full citation with DOI/PMID recorded
11
+ - [ ] Background gap clearly identified
12
+ - [ ] Study design classified (RCT, cohort, case series, etc.)
13
+ - [ ] Sample size and key inclusion/exclusion criteria noted
14
+ - [ ] Primary and secondary outcomes listed
15
+ - [ ] Key results with effect sizes and confidence intervals
16
+ - [ ] Limitations enumerated (minimum 3)
17
+ - [ ] Clinical/scientific significance stated
18
+
19
+ ### Audience Assessment
20
+ - [ ] Target audience specialties identified
21
+ - [ ] Knowledge level estimated (student / trainee / specialist / mixed)
22
+ - [ ] Specialty-specific terms that need plain-language explanation listed
23
+ - [ ] Prior session topics noted (for coursework presentations)
24
+
25
+ ### Outline
26
+ - [ ] Slide count matches presentation time (roughly 1 slide per minute)
27
+ - [ ] Time allocated per slide
28
+ - [ ] Narrative arc: context → gap → methods → results → implications
29
+ - [ ] Opening connects to audience's existing knowledge
30
+ - [ ] Closing has clear take-home messages (3-5 maximum)
31
+
32
+ ---
33
+
34
+ ## Phase 1: Supporting Research
35
+
36
+ ### Search Completeness
37
+ - [ ] Follow-up studies searched (has finding been replicated?)
38
+ - [ ] Contradicting evidence searched (balance for Q&A)
39
+ - [ ] Review articles checked (authoritative framing)
40
+ - [ ] Clinical trial data checked (real-world context)
41
+
42
+ ### Citation Verification
43
+ - [ ] Every reference has DOI or PMID
44
+ - [ ] No fabricated citations
45
+ - [ ] Unverifiable references marked [UNVERIFIED]
46
+
47
+ ### Data Extraction
48
+ - [ ] Only presentation-relevant data extracted (not full paper summaries)
49
+ - [ ] Data source (reference number) linked to each statistic
50
+ - [ ] Numbers cross-checked against original papers
51
+
52
+ ---
53
+
54
+ ## Phase 2: Script & Content
55
+
56
+ ### Audience Adaptation
57
+ - [ ] Technical terms explained at appropriate depth for audience
58
+ - [ ] Mixed-audience terms have one-line plain-language additions
59
+ - [ ] No unexplained abbreviations on first use
60
+ - [ ] Pronunciation guides for drug names and key abbreviations
61
+
62
+ ### Script Quality
63
+ - [ ] Script matches allocated time (130-150 words/min for academic talks)
64
+ - [ ] Transitions between slides are explicit
65
+ - [ ] Opening hooks audience attention
66
+ - [ ] Closing reinforces key messages
67
+ - [ ] Limitations acknowledged honestly (not hidden)
68
+
69
+ ### Optional Extension
70
+ - [ ] Extension section included only if user requested
71
+ - [ ] Extension connects naturally to main content
72
+ - [ ] Extension has concrete evidence (not speculation)
73
+
74
+ ---
75
+
76
+ ## Phase 3: Slides & Notes
77
+
78
+ ### Note Injection
79
+ - [ ] Notes mapped to correct slide numbers
80
+ - [ ] Slide content NOT modified (only notes pane)
81
+ - [ ] Script verified by running inject script on a copy first
82
+ - [ ] Output file opened and spot-checked in presentation software
83
+
84
+ ### Content Consistency
85
+ - [ ] Numbers in notes match numbers on slides
86
+ - [ ] If slides round numbers (e.g., 12% vs 10.9%), notes use precise values
87
+ - [ ] Slide titles match script section references
88
+
89
+ ---
90
+
91
+ ## Phase 4: Q&A Preparation
92
+
93
+ ### Question Coverage
94
+ - [ ] Methodology questions (study design choices, limitations)
95
+ - [ ] Domain expert questions (deep technical details)
96
+ - [ ] Generalist questions (clinical relevance, so-what)
97
+ - [ ] Student questions (concept clarification)
98
+
99
+ ### Answer Quality
100
+ - [ ] Each answer follows: Acknowledge → Evidence → Conclude
101
+ - [ ] Limitations acknowledged, not deflected
102
+ - [ ] Supporting evidence cited with author/year
103
+ - [ ] Answers are concise (30-60 seconds speaking time each)
104
+
105
+ ### Quick Review Sheet
106
+ - [ ] Key numbers in a single table
107
+ - [ ] Common confusion points listed
108
+ - [ ] Classification frameworks distinguished (if multiple exist)
109
+ - [ ] Precise values noted where slides use rounded numbers
@@ -0,0 +1,243 @@
1
+ #!/usr/bin/env python3
2
+ """Extract figures from PDF pages via pdftoppm + PIL crop (normalized box coords).
3
+
4
+ Two usage modes:
5
+
6
+ 1. **CLI single-crop**: extract one or more figures from specific pages of a PDF
7
+ using normalized (0–1) crop boxes.
8
+
9
+ extract_pdf_figures.py paper.pdf \\
10
+ --page 5 --crop 0.10,0.05,0.95,0.55 --out fig01.png
11
+
12
+ extract_pdf_figures.py paper.pdf \\
13
+ --pages 5,6 \\
14
+ --crops "0.10,0.05,0.95,0.55;0.05,0.05,0.95,0.50" \\
15
+ --out fig01.png,fig02.png
16
+
17
+ 2. **YAML config batch**: extract many figures across multiple PDFs declaratively.
18
+
19
+ extract_pdf_figures.py --config figures.yaml --out-dir extracted/
20
+
21
+ YAML schema:
22
+
23
+ dpi: 250 # default 250; override per item with item.dpi
24
+ pdf_dir: /abs/path/to/pdfs/ # optional base path resolved per item.pdf
25
+ items:
26
+ - name: fig01_concept_overview
27
+ pdf: 01_paper.pdf # joined with pdf_dir if relative
28
+ page: 4 # 1-indexed
29
+ crop: [0.06, 0.08, 0.97, 0.52] # [left, top, right, bottom] normalized
30
+ caption: "Conceptual overview (Author YYYY Fig 1)" # optional, only logged
31
+
32
+ Requires: pdftoppm (poppler-utils — `brew install poppler`), Pillow.
33
+ Optional: PyYAML for --config mode (`pip install pyyaml`).
34
+
35
+ Cross-references:
36
+ - /present-paper Phase 3 (Slides & Notes)
37
+ - references/slide_visual_styles/nature_lancet.md §5 (figure handling)
38
+ - ~/.claude/rules/pptx-mac-compatibility.md §7 (Inches EMU pitfall)
39
+ """
40
+ from __future__ import annotations
41
+
42
+ import argparse
43
+ import shutil
44
+ import subprocess
45
+ import sys
46
+ import tempfile
47
+ from pathlib import Path
48
+ from typing import Iterable
49
+
50
+ try:
51
+ from PIL import Image
52
+ except ImportError:
53
+ sys.stderr.write("ERROR: Pillow is required. Install: pip install Pillow\n")
54
+ raise
55
+
56
+
57
+ def _parse_crop(s: str) -> tuple[float, float, float, float]:
58
+ """Parse 'l,t,r,b' string into normalized box tuple. Validates 0 <= l<r <=1, t<b."""
59
+ parts = s.split(",")
60
+ if len(parts) != 4:
61
+ raise ValueError(f"crop must be 4 comma-separated floats, got: {s!r}")
62
+ l, t, r, b = (float(x) for x in parts)
63
+ for label, v in (("left", l), ("top", t), ("right", r), ("bottom", b)):
64
+ if not 0.0 <= v <= 1.0:
65
+ raise ValueError(f"crop {label}={v} not in [0,1]")
66
+ if not (l < r and t < b):
67
+ raise ValueError(f"crop must satisfy left<right and top<bottom; got {s!r}")
68
+ return (l, t, r, b)
69
+
70
+
71
+ def _render_page(pdf: Path, page: int, dpi: int, tmp_dir: Path) -> Path:
72
+ """Render a single PDF page to PNG using pdftoppm; return resulting file path."""
73
+ if not pdf.exists():
74
+ raise FileNotFoundError(f"PDF not found: {pdf}")
75
+ out_prefix = tmp_dir / f"page_{page}"
76
+ cmd = [
77
+ "pdftoppm",
78
+ "-png",
79
+ "-r", str(dpi),
80
+ "-f", str(page),
81
+ "-l", str(page),
82
+ str(pdf),
83
+ str(out_prefix),
84
+ ]
85
+ proc = subprocess.run(cmd, capture_output=True, text=True)
86
+ if proc.returncode != 0:
87
+ raise RuntimeError(
88
+ f"pdftoppm failed for {pdf.name} page {page}:\n{proc.stderr.strip()}"
89
+ )
90
+ # pdftoppm writes "<prefix>-<padded_page>.png" — width varies with total pages.
91
+ matches = sorted(tmp_dir.glob(f"page_{page}-*.png"))
92
+ if not matches:
93
+ raise RuntimeError(
94
+ f"pdftoppm produced no output for {pdf.name} page {page} "
95
+ f"(expected page_{page}-*.png in {tmp_dir})"
96
+ )
97
+ return matches[0]
98
+
99
+
100
+ def _crop_image(src: Path, box: tuple[float, float, float, float], dst: Path) -> tuple[int, int]:
101
+ """Crop src image by normalized box and save to dst. Returns (w, h) of cropped image."""
102
+ img = Image.open(src)
103
+ W, H = img.size
104
+ l, t, r, b = box
105
+ cropped = img.crop((int(W * l), int(H * t), int(W * r), int(H * b)))
106
+ dst.parent.mkdir(parents=True, exist_ok=True)
107
+ cropped.save(dst, "PNG", optimize=True)
108
+ return cropped.size
109
+
110
+
111
+ def extract_one(pdf: Path, page: int, crop: tuple[float, float, float, float],
112
+ out: Path, dpi: int = 250) -> Path:
113
+ """Single-figure extraction. Returns the output path."""
114
+ with tempfile.TemporaryDirectory() as td:
115
+ page_png = _render_page(pdf, page, dpi, Path(td))
116
+ w, h = _crop_image(page_png, crop, out)
117
+ print(f"OK {out.name:50s} ({w}x{h}) {pdf.name} page {page}")
118
+ return out
119
+
120
+
121
+ def extract_batch(items: Iterable[dict], out_dir: Path, default_dpi: int = 250,
122
+ pdf_dir: Path | None = None) -> list[Path]:
123
+ """Batch extraction from YAML config. Caches rendered pages per (pdf, page, dpi).
124
+
125
+ Each item dict accepts:
126
+ name (str, required): output filename stem (.png appended)
127
+ pdf (str, required): PDF path (joined with pdf_dir if relative)
128
+ page (int, required): 1-indexed PDF page number
129
+ crop (list[float], required): [left, top, right, bottom] normalized
130
+ dpi (int, optional): override default_dpi
131
+ caption (str, optional): logged only
132
+ """
133
+ out_dir = Path(out_dir)
134
+ out_dir.mkdir(parents=True, exist_ok=True)
135
+ results: list[Path] = []
136
+ with tempfile.TemporaryDirectory() as td:
137
+ td_path = Path(td)
138
+ cache: dict[tuple[str, int, int], Path] = {}
139
+ for item in items:
140
+ try:
141
+ name = item["name"]
142
+ pdf_str = item["pdf"]
143
+ page = int(item["page"])
144
+ crop = tuple(float(x) for x in item["crop"])
145
+ if len(crop) != 4:
146
+ raise ValueError("crop must have 4 elements")
147
+ dpi = int(item.get("dpi", default_dpi))
148
+ except (KeyError, ValueError, TypeError) as e:
149
+ print(f"SKIP item {item!r}: {e}")
150
+ continue
151
+
152
+ pdf = Path(pdf_str)
153
+ if pdf_dir is not None and not pdf.is_absolute():
154
+ pdf = pdf_dir / pdf
155
+
156
+ cache_key = (str(pdf), page, dpi)
157
+ if cache_key not in cache:
158
+ try:
159
+ cache[cache_key] = _render_page(pdf, page, dpi, td_path)
160
+ except (FileNotFoundError, RuntimeError) as e:
161
+ print(f"SKIP {name}: {e}")
162
+ continue
163
+
164
+ dst = out_dir / f"{name}.png"
165
+ try:
166
+ w, h = _crop_image(cache[cache_key], crop, dst)
167
+ except ValueError as e:
168
+ print(f"SKIP {name}: {e}")
169
+ continue
170
+
171
+ caption = item.get("caption", "")
172
+ tail = f" {caption}" if caption else ""
173
+ print(f"OK {dst.name:50s} ({w}x{h}) {pdf.name} page {page}{tail}")
174
+ results.append(dst)
175
+
176
+ print(f"\nTotal: {len(results)} figures in {out_dir}")
177
+ return results
178
+
179
+
180
+ def _cli() -> int:
181
+ p = argparse.ArgumentParser(
182
+ description="Extract figures from PDF pages (pdftoppm + PIL crop).",
183
+ formatter_class=argparse.RawDescriptionHelpFormatter,
184
+ )
185
+ p.add_argument("pdf", nargs="?", help="PDF input (single-crop mode); omit for --config mode")
186
+ p.add_argument("--page", type=int, help="single-crop: 1-indexed page number")
187
+ p.add_argument("--pages", help="single-crop: comma-separated pages (paired with --crops)")
188
+ p.add_argument("--crop", help="single-crop: 'l,t,r,b' normalized box")
189
+ p.add_argument("--crops", help="single-crop: ';'-separated 'l,t,r,b' boxes paired with --pages")
190
+ p.add_argument("--out", help="single-crop: output path (or comma-separated paths)")
191
+ p.add_argument("--out-dir", help="batch mode: output directory")
192
+ p.add_argument("--dpi", type=int, default=250, help="render DPI (default 250)")
193
+ p.add_argument("--config", help="batch mode: YAML config path")
194
+ args = p.parse_args()
195
+
196
+ # Batch (YAML) mode
197
+ if args.config:
198
+ try:
199
+ import yaml # type: ignore
200
+ except ImportError:
201
+ sys.stderr.write("ERROR: --config requires PyYAML. Install: pip install pyyaml\n")
202
+ return 2
203
+ cfg_path = Path(args.config)
204
+ if not cfg_path.exists():
205
+ sys.stderr.write(f"ERROR: config not found: {cfg_path}\n")
206
+ return 2
207
+ cfg = yaml.safe_load(cfg_path.read_text()) or {}
208
+ items = cfg.get("items", [])
209
+ out_dir = Path(args.out_dir or cfg.get("out_dir", "extracted"))
210
+ dpi = int(args.dpi if args.dpi != 250 else cfg.get("dpi", 250))
211
+ pdf_dir = cfg.get("pdf_dir")
212
+ pdf_dir = Path(pdf_dir) if pdf_dir else None
213
+ extract_batch(items, out_dir, default_dpi=dpi, pdf_dir=pdf_dir)
214
+ return 0
215
+
216
+ # Single-crop mode (single or paired)
217
+ if not args.pdf:
218
+ p.error("pdf positional argument required for single-crop mode (or use --config)")
219
+ pdf = Path(args.pdf)
220
+
221
+ if args.crops or args.pages:
222
+ if not (args.crops and args.pages and args.out):
223
+ p.error("--pages, --crops, and --out must all be set together")
224
+ pages = [int(x) for x in args.pages.split(",")]
225
+ crops = [_parse_crop(c) for c in args.crops.split(";")]
226
+ outs = [Path(o.strip()) for o in args.out.split(",")]
227
+ if not (len(pages) == len(crops) == len(outs)):
228
+ p.error(
229
+ f"counts mismatch: {len(pages)} pages, {len(crops)} crops, {len(outs)} outs"
230
+ )
231
+ for pg, cb, op in zip(pages, crops, outs):
232
+ extract_one(pdf, pg, cb, op, dpi=args.dpi)
233
+ return 0
234
+
235
+ if not (args.page is not None and args.crop and args.out):
236
+ p.error("single crop requires --page, --crop, --out")
237
+ box = _parse_crop(args.crop)
238
+ extract_one(pdf, args.page, box, Path(args.out), dpi=args.dpi)
239
+ return 0
240
+
241
+
242
+ if __name__ == "__main__":
243
+ sys.exit(_cli())
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env python3
2
+ """Append a pronunciation guide section to every slide's speaker notes.
3
+
4
+ Designed for non-native presenters who want a per-slide reading reference
5
+ without affecting the audience-facing view. Scans each slide's notes text
6
+ for tokens defined in a YAML/JSON ``PRON_DICT`` file (term → reading +
7
+ full-name), uses word-boundary regex to avoid false positives, and writes
8
+ a "[ 발음 ]" (or user-defined) section at the bottom of the notes.
9
+
10
+ Also auto-matches allele-style tokens (HLA-DRB1*07:01, HLA-A*02:01, …)
11
+ that match a configurable regex and synthesizes a reading by combining
12
+ the base reading from PRON_DICT with "스타 NN콜론NN".
13
+
14
+ This script is invocation-agnostic: it modifies a PPTX in place (or to a
15
+ new path) and does not assume any specific lecture topic. The PRON_DICT
16
+ file is supplied by the caller and is the only language/domain config.
17
+
18
+ Usage
19
+ -----
20
+
21
+ PRON_DICT is YAML or JSON. Each key is the term as it appears in the
22
+ notes text. Each value is a 2-tuple [reading, full_name].
23
+
24
+ ```yaml
25
+ # pron_dict.yaml
26
+ GWAS: ["지와스", "Genome-wide association study"]
27
+ HLA: ["에이치-엘-에이", "Human leukocyte antigen"]
28
+ LGI1: ["엘-지-아이-원", "Leucine-rich glioma-inactivated 1"]
29
+ Perriot: ["페리오", "프랑스, t 묵음"]
30
+ ```
31
+
32
+ ```bash
33
+ python3 inject_pronunciation_notes.py input.pptx output.pptx \
34
+ --dict pron_dict.yaml --header "[ 발음 ]"
35
+ ```
36
+ """
37
+ from __future__ import annotations
38
+
39
+ import argparse
40
+ import json
41
+ import re
42
+ import shutil
43
+ import sys
44
+ from pathlib import Path
45
+
46
+ from pptx import Presentation
47
+ from pptx.util import Pt
48
+
49
+ DEFAULT_ALLELE_RE = r"\b(?:HLA-)?[A-Z]{1,5}[0-9]?\*[0-9]{2}:[0-9]{2}(?:N|L|S|Q)?\b"
50
+ DEFAULT_HEADER = "[ Pronunciation ]"
51
+
52
+
53
+ def load_dict(path: Path) -> dict:
54
+ if path.suffix.lower() in (".yaml", ".yml"):
55
+ try:
56
+ import yaml # type: ignore
57
+ except ImportError:
58
+ raise SystemExit("PyYAML required for YAML dict; pip install pyyaml")
59
+ with path.open() as f:
60
+ raw = yaml.safe_load(f)
61
+ elif path.suffix.lower() == ".json":
62
+ with path.open() as f:
63
+ raw = json.load(f)
64
+ else:
65
+ raise SystemExit(f"unsupported dict format: {path.suffix}")
66
+ out = {}
67
+ for term, value in raw.items():
68
+ if isinstance(value, (list, tuple)) and len(value) >= 1:
69
+ reading = value[0]
70
+ fullname = value[1] if len(value) > 1 else ""
71
+ elif isinstance(value, str):
72
+ reading, fullname = value, ""
73
+ else:
74
+ continue
75
+ out[term] = (reading, fullname)
76
+ return out
77
+
78
+
79
+ def find_terms(text: str, pron_dict: dict, allele_re: str | None):
80
+ """Return [(term, reading, fullname)] for every dict key appearing in *text*."""
81
+ if not text:
82
+ return []
83
+ hits = []
84
+ seen = set()
85
+ for term, (reading, fullname) in pron_dict.items():
86
+ pat = r"(?<![A-Za-z0-9_])" + re.escape(term) + r"(?![A-Za-z0-9_])"
87
+ if re.search(pat, text):
88
+ if term not in seen:
89
+ hits.append((term, reading, fullname))
90
+ seen.add(term)
91
+ if allele_re:
92
+ allele_pattern = re.compile(allele_re)
93
+ alleles = sorted(set(allele_pattern.findall(text)))
94
+ for a in alleles:
95
+ if a in seen:
96
+ continue
97
+ base = a.replace("HLA-", "").split("*")[0]
98
+ tail = a.split("*", 1)[1] if "*" in a else ""
99
+ base_reading = pron_dict.get(base, (base.lower(), ""))[0]
100
+ reading = f"{base_reading} star {tail.replace(':', ' colon ')}"
101
+ hits.append((a, reading, "HLA allele"))
102
+ seen.add(a)
103
+ return hits
104
+
105
+
106
+ def inject_notes(slide, terms, header: str):
107
+ if not terms:
108
+ return False
109
+ tf = slide.notes_slide.notes_text_frame
110
+
111
+ # blank separator
112
+ p = tf.add_paragraph()
113
+ r = p.add_run(); r.text = " "
114
+ r.font.size = Pt(11)
115
+
116
+ # header
117
+ p = tf.add_paragraph()
118
+ r = p.add_run(); r.text = header
119
+ r.font.bold = True
120
+ r.font.size = Pt(12)
121
+
122
+ # each term: "▪ term — reading · fullname"
123
+ for term, reading, fullname in terms:
124
+ p = tf.add_paragraph()
125
+ r = p.add_run(); r.text = f"▪ {term}"
126
+ r.font.bold = True
127
+ r.font.size = Pt(11)
128
+ r2 = p.add_run(); r2.text = f" — {reading}"
129
+ r2.font.size = Pt(11)
130
+ if fullname:
131
+ r3 = p.add_run(); r3.text = f" · {fullname}"
132
+ r3.font.italic = True
133
+ r3.font.size = Pt(11)
134
+ return True
135
+
136
+
137
+ def main():
138
+ ap = argparse.ArgumentParser()
139
+ ap.add_argument("src", type=Path)
140
+ ap.add_argument("dst", type=Path)
141
+ ap.add_argument("--dict", required=True, type=Path,
142
+ help="path to pron_dict.yaml or pron_dict.json")
143
+ ap.add_argument("--header", default=DEFAULT_HEADER,
144
+ help="section header text (default: %(default)s)")
145
+ ap.add_argument("--allele-regex", default=DEFAULT_ALLELE_RE,
146
+ help="regex for allele-style tokens (set to empty string to disable)")
147
+ args = ap.parse_args()
148
+
149
+ if not args.src.exists():
150
+ print(f"source not found: {args.src}", file=sys.stderr)
151
+ sys.exit(1)
152
+ if args.src != args.dst:
153
+ shutil.copy(args.src, args.dst)
154
+
155
+ pron_dict = load_dict(args.dict)
156
+ print(f"loaded {len(pron_dict)} terms from {args.dict}")
157
+
158
+ allele_re = args.allele_regex if args.allele_regex else None
159
+ prs = Presentation(args.dst)
160
+ n_injected = 0
161
+ n_terms_total = 0
162
+ for slide in prs.slides:
163
+ if not slide.has_notes_slide:
164
+ continue
165
+ body = slide.notes_slide.notes_text_frame.text
166
+ if args.header in body:
167
+ continue # already injected on a previous run
168
+ terms = find_terms(body, pron_dict, allele_re)
169
+ if inject_notes(slide, terms, args.header):
170
+ n_injected += 1
171
+ n_terms_total += len(terms)
172
+ prs.save(args.dst)
173
+ print(f"injected pronunciation on {n_injected} slides ({n_terms_total} term entries)")
174
+ print(f"OK: {args.dst}")
175
+
176
+
177
+ if __name__ == "__main__":
178
+ main()
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env python3
2
+ """Inject speaker notes into PowerPoint presentation slides.
3
+
4
+ This script adds or replaces speaker notes in a PPTX file without modifying
5
+ slide content, layout, or design. Notes are defined as a dictionary mapping
6
+ slide numbers (1-indexed) to note text.
7
+
8
+ Usage:
9
+ python inject_speaker_notes.py input.pptx
10
+ python inject_speaker_notes.py input.pptx -o output.pptx
11
+ python inject_speaker_notes.py input.pptx --append
12
+ python inject_speaker_notes.py input.pptx --dry-run
13
+
14
+ Requirements:
15
+ pip install python-pptx
16
+
17
+ License: MIT
18
+ """
19
+
20
+ import argparse
21
+ import sys
22
+ from pathlib import Path
23
+
24
+ try:
25
+ from pptx import Presentation
26
+ except ImportError:
27
+ print("Error: python-pptx is required. Install with: pip install python-pptx")
28
+ sys.exit(1)
29
+
30
+
31
+ # ---------------------------------------------------------------------------
32
+ # Speaker notes dictionary
33
+ # Map slide number (1-indexed) to note text.
34
+ # Empty string or missing key = skip that slide.
35
+ # ---------------------------------------------------------------------------
36
+ notes: dict[int, str] = {
37
+ # 1: """Speaker note for slide 1.""",
38
+ # 2: """Speaker note for slide 2.""",
39
+ }
40
+
41
+
42
+ def inject_notes(
43
+ input_path: str,
44
+ output_path: str | None = None,
45
+ append: bool = False,
46
+ dry_run: bool = False,
47
+ ) -> None:
48
+ """Inject speaker notes into a PPTX file.
49
+
50
+ Args:
51
+ input_path: Path to input PPTX file.
52
+ output_path: Path to output PPTX file. Defaults to input with _notes suffix.
53
+ append: If True, append to existing notes instead of replacing.
54
+ dry_run: If True, print what would be done without saving.
55
+ """
56
+ input_file = Path(input_path)
57
+ if not input_file.exists():
58
+ print(f"Error: {input_file} not found")
59
+ sys.exit(1)
60
+
61
+ if output_path is None:
62
+ output_file = input_file.with_stem(input_file.stem + "_notes")
63
+ else:
64
+ output_file = Path(output_path)
65
+
66
+ prs = Presentation(str(input_file))
67
+ total_slides = len(prs.slides)
68
+ updated = 0
69
+
70
+ for i, slide in enumerate(prs.slides, 1):
71
+ if i not in notes or not notes[i]:
72
+ continue
73
+
74
+ if dry_run:
75
+ preview = notes[i][:80].replace("\n", " ")
76
+ print(f" Slide {i:2d}: would {'append' if append else 'set'} → {preview}...")
77
+ updated += 1
78
+ continue
79
+
80
+ if not slide.has_notes_slide:
81
+ slide.notes_slide # creates notes slide
82
+
83
+ tf = slide.notes_slide.notes_text_frame
84
+ if append and tf.text.strip():
85
+ tf.text = tf.text + "\n\n---\n\n" + notes[i]
86
+ else:
87
+ tf.text = notes[i]
88
+ updated += 1
89
+
90
+ if dry_run:
91
+ print(f"\nDry run: {updated}/{total_slides} slides would be updated")
92
+ return
93
+
94
+ prs.save(str(output_file))
95
+ print(f"Done: {output_file} ({updated}/{total_slides} slides updated)")
96
+
97
+
98
+ def main() -> None:
99
+ parser = argparse.ArgumentParser(
100
+ description="Inject speaker notes into PowerPoint slides",
101
+ epilog="Notes are defined in the 'notes' dictionary in this script.",
102
+ )
103
+ parser.add_argument("input", help="Input PPTX file")
104
+ parser.add_argument(
105
+ "-o", "--output",
106
+ help="Output PPTX file (default: input with _notes suffix)",
107
+ )
108
+ parser.add_argument(
109
+ "--append",
110
+ action="store_true",
111
+ help="Append to existing notes instead of replacing",
112
+ )
113
+ parser.add_argument(
114
+ "--dry-run",
115
+ action="store_true",
116
+ help="Print what would be done without saving",
117
+ )
118
+ args = parser.parse_args()
119
+
120
+ if not notes:
121
+ print("Warning: notes dictionary is empty. Edit this script to add notes.")
122
+ print("Example:")
123
+ print(' notes = {')
124
+ print(' 1: """Your note for slide 1.""",')
125
+ print(' 2: """Your note for slide 2.""",')
126
+ print(' }')
127
+ sys.exit(0)
128
+
129
+ inject_notes(args.input, args.output, args.append, args.dry_run)
130
+
131
+
132
+ if __name__ == "__main__":
133
+ main()