@brainpilot/skills 0.0.6 → 0.0.7

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 (285) hide show
  1. package/package.json +2 -2
  2. package/skills/01_Meta-Skills/academic-research-hub/SKILL.md +108 -0
  3. package/skills/01_Meta-Skills/academic-research-hub/scripts/requirements.txt +17 -0
  4. package/skills/01_Meta-Skills/academic-research-hub/scripts/research.py +781 -0
  5. package/skills/01_Meta-Skills/beautiful-log/SKILL.md +64 -0
  6. package/skills/01_Meta-Skills/beautiful-log/scripts/beautiful_log.py +274 -0
  7. package/skills/01_Meta-Skills/ethoclaw-daily-paper/SKILL.md +130 -0
  8. package/skills/01_Meta-Skills/ethoclaw-daily-paper/assets/config.template.yaml +54 -0
  9. package/skills/01_Meta-Skills/ethoclaw-daily-paper/assets/top5_digest_template.md +5 -0
  10. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/build_top5_digest.py +300 -0
  11. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/common.py +137 -0
  12. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/merge_results.py +106 -0
  13. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/run_pipeline.py +177 -0
  14. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/search_arxiv.py +162 -0
  15. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/search_pubmed.py +202 -0
  16. package/skills/01_Meta-Skills/ethoclaw-normalize-tabular/SKILL.md +173 -0
  17. package/skills/01_Meta-Skills/ethoclaw-normalize-tabular/scripts/normalize_data.py +874 -0
  18. package/skills/01_Meta-Skills/ethoclaw-pdf-research/SKILL.md +134 -0
  19. package/skills/01_Meta-Skills/ethoclaw-pdf-research/references/confirmation-prompts.md +31 -0
  20. package/skills/01_Meta-Skills/ethoclaw-pdf-research/references/output-patterns.md +45 -0
  21. package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_markdown_deliverables.py +41 -0
  22. package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_research_log.py +84 -0
  23. package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_summary_md.py +63 -0
  24. package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/extract_pdf_bundle.py +140 -0
  25. package/skills/01_Meta-Skills/experiment-controller/SKILL.md +140 -0
  26. package/skills/01_Meta-Skills/knowledge-graph-builder/SKILL.md +366 -0
  27. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/entity_resolution.py +120 -0
  28. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/extraction_prompt_template.txt +19 -0
  29. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/graph_query.py +106 -0
  30. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/hypothesis_cli_reference.py +42 -0
  31. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/new_data_source_template.py +116 -0
  32. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/requirements.txt +15 -0
  33. package/skills/01_Meta-Skills/method-design/SKILL.md +61 -0
  34. package/skills/01_Meta-Skills/multi-search-engine/SKILL.md +119 -0
  35. package/skills/01_Meta-Skills/research-idea/SKILL.md +65 -0
  36. package/skills/05_EEG_ERP/eeg-skill/SKILL.md +197 -0
  37. package/skills/05_EEG_ERP/meg-skill/SKILL.md +188 -0
  38. package/skills/05_EEG_ERP/meg-skill/scripts/time_frequency.py +223 -0
  39. package/skills/05_EEG_ERP/mne-eeg-tool/SKILL.md +165 -0
  40. package/skills/05_EEG_ERP/mne-eeg-tool/scripts/eeg_pipeline_reference.py +231 -0
  41. package/skills/05_EEG_ERP/seed-iv-skill/SKILL.md +184 -0
  42. package/skills/05_EEG_ERP/seed-iv-skill/scripts/classify_seed_iv.py +154 -0
  43. package/skills/05_EEG_ERP/seed-iv-skill/scripts/extract_seed_iv_features.py +190 -0
  44. package/skills/05_EEG_ERP/seed-iv-skill/scripts/validate_seed_iv.py +102 -0
  45. package/skills/05_EEG_ERP/seed-vig-skill/SKILL.md +182 -0
  46. package/skills/05_EEG_ERP/seed-vig-skill/scripts/classify_seed_vig.py +165 -0
  47. package/skills/05_EEG_ERP/seed-vig-skill/scripts/extract_seed_vig_features.py +185 -0
  48. package/skills/05_EEG_ERP/seed-vig-skill/scripts/validate_seed_vig.py +88 -0
  49. package/skills/06_fMRI_Neuroimaging/abcd-skill/SKILL.md +308 -0
  50. package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/abcd_qc_summary.py +449 -0
  51. package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/extract_abcd_phenotype.py +292 -0
  52. package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/reorganize_abcd.py +387 -0
  53. package/skills/06_fMRI_Neuroimaging/abide-skill/SKILL.md +302 -0
  54. package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/abide_qc_summary.py +317 -0
  55. package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/extract_abide_phenotype.py +267 -0
  56. package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/reorganize_abide.py +387 -0
  57. package/skills/06_fMRI_Neuroimaging/adhd200-skill/SKILL.md +244 -0
  58. package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/adhd200_qc_summary.py +98 -0
  59. package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/extract_adhd200_phenotype.py +134 -0
  60. package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/reorganize_adhd200.py +206 -0
  61. package/skills/06_fMRI_Neuroimaging/adni-skill/SKILL.md +358 -0
  62. package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/generate_adni_task_files.py +1305 -0
  63. package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/generate_vqa_from_tasks.py +766 -0
  64. package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/reorganize_adni.py +491 -0
  65. package/skills/06_fMRI_Neuroimaging/aibl-skill/SKILL.md +295 -0
  66. package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/aibl_qc_summary.py +260 -0
  67. package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/extract_aibl_phenotype.py +365 -0
  68. package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/reorganize_aibl.py +394 -0
  69. package/skills/06_fMRI_Neuroimaging/aomic-skill/SKILL.md +292 -0
  70. package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/aomic_qc_summary.py +258 -0
  71. package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/extract_aomic_phenotype.py +284 -0
  72. package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/reorganize_aomic.py +322 -0
  73. package/skills/06_fMRI_Neuroimaging/asl-skill/SKILL.md +168 -0
  74. package/skills/06_fMRI_Neuroimaging/asl-skill/scripts/compute_cbf.py +224 -0
  75. package/skills/06_fMRI_Neuroimaging/bids-organizer/SKILL.md +241 -0
  76. package/skills/06_fMRI_Neuroimaging/bold5000-skill/SKILL.md +186 -0
  77. package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/bold5000_qc_summary.py +96 -0
  78. package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/extract_bold5000_stimulus.py +125 -0
  79. package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/reorganize_bold5000.py +102 -0
  80. package/skills/06_fMRI_Neuroimaging/camcan-skill/SKILL.md +213 -0
  81. package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/camcan_qc_summary.py +131 -0
  82. package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/extract_camcan_phenotype.py +145 -0
  83. package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/validate_camcan.py +141 -0
  84. package/skills/06_fMRI_Neuroimaging/cobre-skill/SKILL.md +201 -0
  85. package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/cobre_qc_summary.py +95 -0
  86. package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/extract_cobre_phenotype.py +104 -0
  87. package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/reorganize_cobre.py +140 -0
  88. package/skills/06_fMRI_Neuroimaging/conn-tool/SKILL.md +180 -0
  89. package/skills/06_fMRI_Neuroimaging/dcm2nii/SKILL.md +189 -0
  90. package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/SKILL.md +183 -0
  91. package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/dmt_har_med_qc_summary.py +96 -0
  92. package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/extract_dmt_har_med_phenotype.py +121 -0
  93. package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/reorganize_dmt_har_med.py +125 -0
  94. package/skills/06_fMRI_Neuroimaging/dwi-skill/SKILL.md +359 -0
  95. package/skills/06_fMRI_Neuroimaging/fmri-skill/SKILL.md +371 -0
  96. package/skills/06_fMRI_Neuroimaging/fmriprep-tool/SKILL.md +228 -0
  97. package/skills/06_fMRI_Neuroimaging/freesurfer-tool/SKILL.md +286 -0
  98. package/skills/06_fMRI_Neuroimaging/freesurfer-tool/scripts/freesurfer_processor.py +145 -0
  99. package/skills/06_fMRI_Neuroimaging/fsl-tool/SKILL.md +208 -0
  100. package/skills/06_fMRI_Neuroimaging/hbn-skill/SKILL.md +271 -0
  101. package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/extract_hbn_phenotype.py +107 -0
  102. package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/hbn_qc_summary.py +96 -0
  103. package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/reorganize_hbn.py +150 -0
  104. package/skills/06_fMRI_Neuroimaging/hcpa-skill/SKILL.md +210 -0
  105. package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/extract_hcpa_phenotype.py +146 -0
  106. package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/hcpa_qc_summary.py +120 -0
  107. package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/reorganize_hcpa.py +155 -0
  108. package/skills/06_fMRI_Neuroimaging/hcpd-skill/SKILL.md +210 -0
  109. package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/extract_hcpd_phenotype.py +148 -0
  110. package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/hcpd_qc_summary.py +125 -0
  111. package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/reorganize_hcpd.py +146 -0
  112. package/skills/06_fMRI_Neuroimaging/hcpep-skill/SKILL.md +215 -0
  113. package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/extract_hcpep_phenotype.py +157 -0
  114. package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/hcpep_qc_summary.py +143 -0
  115. package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/reorganize_hcpep.py +146 -0
  116. package/skills/06_fMRI_Neuroimaging/hcppipeline-tool/SKILL.md +217 -0
  117. package/skills/06_fMRI_Neuroimaging/hcpya-skill/SKILL.md +214 -0
  118. package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/extract_hcpya_phenotype.py +190 -0
  119. package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/hcpya_qc_summary.py +152 -0
  120. package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/reorganize_hcpya.py +203 -0
  121. package/skills/06_fMRI_Neuroimaging/ixi-skill/SKILL.md +198 -0
  122. package/skills/06_fMRI_Neuroimaging/ixi-skill/scripts/ixi_qc_summary.py +137 -0
  123. package/skills/06_fMRI_Neuroimaging/ixi-skill/scripts/reorganize_ixi.py +190 -0
  124. package/skills/06_fMRI_Neuroimaging/mnd-skill/SKILL.md +191 -0
  125. package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/extract_mnd_phenotype.py +143 -0
  126. package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/mnd_qc_summary.py +120 -0
  127. package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/validate_mnd.py +107 -0
  128. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/SKILL.md +203 -0
  129. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/analyze_lesions.py +119 -0
  130. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/longitudinal_lesion.py +148 -0
  131. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/mschallenge_qc_summary.py +132 -0
  132. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/validate_mschallenge.py +116 -0
  133. package/skills/06_fMRI_Neuroimaging/nibabel-skill/SKILL.md +184 -0
  134. package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/atlas_coordinate_reference.py +61 -0
  135. package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/freesurfer_io_reference.py +34 -0
  136. package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/nifti_inspection_reference.py +35 -0
  137. package/skills/06_fMRI_Neuroimaging/nifd-skill/SKILL.md +205 -0
  138. package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/extract_nifd_phenotype.py +132 -0
  139. package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/nifd_qc_summary.py +111 -0
  140. package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/validate_nifd.py +111 -0
  141. package/skills/06_fMRI_Neuroimaging/nii2dcm/SKILL.md +143 -0
  142. package/skills/06_fMRI_Neuroimaging/nilearn-tool/SKILL.md +266 -0
  143. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/connectome_reference.py +65 -0
  144. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/denoise_timeseries_reference.py +58 -0
  145. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/hierarchical_parcellation_reference.py +53 -0
  146. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/kmeans_parcellation_reference.py +53 -0
  147. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/preprocess_bold_reference.py +76 -0
  148. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/rest_dictlearning_reference.py +56 -0
  149. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/rest_ica_reference.py +59 -0
  150. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/second_level_glm_reference.py +58 -0
  151. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/spacenet_classifier_reference.py +59 -0
  152. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/svm_classifier_reference.py +60 -0
  153. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/task_glm_reference.py +63 -0
  154. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/zalff_summary_reference.py +109 -0
  155. package/skills/06_fMRI_Neuroimaging/nsd-skill/SKILL.md +210 -0
  156. package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/extract_nsd_stimulus.py +171 -0
  157. package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/nsd_qc_summary.py +142 -0
  158. package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/validate_nsd.py +142 -0
  159. package/skills/06_fMRI_Neuroimaging/oasis-skill/SKILL.md +205 -0
  160. package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/extract_oasis_phenotype.py +126 -0
  161. package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/oasis_qc_summary.py +115 -0
  162. package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/validate_oasis.py +119 -0
  163. package/skills/06_fMRI_Neuroimaging/pet-skill/SKILL.md +173 -0
  164. package/skills/06_fMRI_Neuroimaging/pet-skill/scripts/compute_suvr.py +202 -0
  165. package/skills/06_fMRI_Neuroimaging/pnc-skill/SKILL.md +206 -0
  166. package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/extract_pnc_phenotype.py +136 -0
  167. package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/pnc_qc_summary.py +116 -0
  168. package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/validate_pnc.py +120 -0
  169. package/skills/06_fMRI_Neuroimaging/ppmi-skill/SKILL.md +209 -0
  170. package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/extract_ppmi_phenotype.py +138 -0
  171. package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/ppmi_qc_summary.py +111 -0
  172. package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/validate_ppmi.py +117 -0
  173. package/skills/06_fMRI_Neuroimaging/qsiprep-tool/SKILL.md +320 -0
  174. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/SKILL.md +215 -0
  175. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/extract_rest_mdd_phenotype.py +132 -0
  176. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/harmonize_sites.py +152 -0
  177. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/rest_mdd_qc_summary.py +124 -0
  178. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/validate_rest_mdd.py +103 -0
  179. package/skills/06_fMRI_Neuroimaging/smri-skill/SKILL.md +302 -0
  180. package/skills/06_fMRI_Neuroimaging/tcp-skill/SKILL.md +204 -0
  181. package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/extract_tcp_phenotype.py +139 -0
  182. package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/tcp_qc_summary.py +111 -0
  183. package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/validate_tcp.py +99 -0
  184. package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/SKILL.md +217 -0
  185. package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/extract_ucla_cnp_phenotype.py +145 -0
  186. package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/ucla_cnp_qc_summary.py +111 -0
  187. package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/validate_ucla_cnp.py +113 -0
  188. package/skills/06_fMRI_Neuroimaging/ukb-skill/SKILL.md +310 -0
  189. package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/build_ukb_survival.py +210 -0
  190. package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/extract_ukb_cases.py +308 -0
  191. package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/extract_ukb_phenotype.py +232 -0
  192. package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/ukb_qc_summary.py +158 -0
  193. package/skills/06_fMRI_Neuroimaging/wmh-segmentation/SKILL.md +133 -0
  194. package/skills/07_Computational_Modeling/detrending/SKILL.md +118 -0
  195. package/skills/07_Computational_Modeling/dictlearning/SKILL.md +122 -0
  196. package/skills/07_Computational_Modeling/filtering/SKILL.md +121 -0
  197. package/skills/07_Computational_Modeling/glm/SKILL.md +153 -0
  198. package/skills/07_Computational_Modeling/hierarchical/SKILL.md +121 -0
  199. package/skills/07_Computational_Modeling/ica/SKILL.md +122 -0
  200. package/skills/07_Computational_Modeling/kmeans/SKILL.md +119 -0
  201. package/skills/07_Computational_Modeling/run_models/SKILL.md +427 -0
  202. package/skills/07_Computational_Modeling/spacenet/SKILL.md +122 -0
  203. package/skills/07_Computational_Modeling/svm/SKILL.md +120 -0
  204. package/skills/08_Computational_Neuroscience/brain_gnn/SKILL.md +183 -0
  205. package/skills/08_Computational_Neuroscience/dipy-tool/SKILL.md +239 -0
  206. package/skills/08_Computational_Neuroscience/dipy-tool/scripts/dti_metrics_reference.py +70 -0
  207. package/skills/08_Computational_Neuroscience/dipy-tool/scripts/load_and_mask_reference.py +76 -0
  208. package/skills/08_Computational_Neuroscience/dipy-tool/scripts/roi_stats_reference.py +59 -0
  209. package/skills/08_Computational_Neuroscience/fm_app/SKILL.md +195 -0
  210. package/skills/08_Computational_Neuroscience/neurostorm/SKILL.md +151 -0
  211. package/skills/13_Visualization/brain-visualization/SKILL.md +191 -0
  212. package/skills/13_Visualization/brain-visualization/scripts/connectome_reference.py +108 -0
  213. package/skills/13_Visualization/brain-visualization/scripts/freesurfer_ply_reference.py +54 -0
  214. package/skills/13_Visualization/brain-visualization/scripts/zalff_summary_reference.py +116 -0
  215. package/skills/13_Visualization/ethoclaw-paper-figure-layout/SKILL.md +78 -0
  216. package/skills/13_Visualization/ethoclaw-paper-figure-layout/assets/naturecomm_figures.tex +74 -0
  217. package/skills/13_Visualization/ethoclaw-paper-figure-layout/scripts/layout_results_foldered.py +579 -0
  218. package/skills/14_Writing/overleaf-skill/SKILL.md +184 -0
  219. package/skills/14_Writing/overleaf-skill/scripts/install.sh +30 -0
  220. package/skills/14_Writing/paper-writing/SKILL.md +146 -0
  221. package/skills/14_Writing/paper-writing/scripts/data_statement_templates.py +164 -0
  222. package/skills/14_Writing/paper-writing/scripts/figure_templates.py +315 -0
  223. package/skills/14_Writing/paper-writing/scripts/nature_figure_style.py +214 -0
  224. package/skills/14_Writing/paper-writing/scripts/section_phrasebank.py +246 -0
  225. package/skills/16_Animal_Behavior/deeplabcut/SKILL.md +154 -0
  226. package/skills/16_Animal_Behavior/deeplabcut/references/3d-pose.md +89 -0
  227. package/skills/16_Animal_Behavior/deeplabcut/references/maDLC.md +123 -0
  228. package/skills/16_Animal_Behavior/deeplabcut/references/modelzoo.md +98 -0
  229. package/skills/16_Animal_Behavior/deeplabcut/references/standard-pipeline.md +165 -0
  230. package/skills/16_Animal_Behavior/deeplabcut/references/utilities.md +146 -0
  231. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/SKILL.md +274 -0
  232. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/report_template_en.html +112 -0
  233. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/report_template_en.md +21 -0
  234. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/cluster-section.md +5 -0
  235. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/heatmap-section.md +5 -0
  236. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/integrated-interpretation.md +3 -0
  237. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/overview.md +3 -0
  238. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/project-summary.md +3 -0
  239. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/radar-section.md +5 -0
  240. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/raw-trajectory.md +3 -0
  241. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/sample-check.md +3 -0
  242. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/single-subject-section.md +3 -0
  243. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/stats-section.md +5 -0
  244. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/epm.md +52 -0
  245. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/fst.md +37 -0
  246. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/nor.md +39 -0
  247. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/oft.md +43 -0
  248. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/tcst.md +45 -0
  249. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/tst.md +36 -0
  250. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/input-types.md +59 -0
  251. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/interpretation-guardrails.md +45 -0
  252. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/metadata-schema.md +57 -0
  253. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/report-sections.md +86 -0
  254. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/section-selection-rules.md +169 -0
  255. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/build_report_manifest.py +27 -0
  256. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/render_report.py +34 -0
  257. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/report_utils.py +1121 -0
  258. package/skills/16_Animal_Behavior/ethoclaw-animal-grounding/SKILL.md +390 -0
  259. package/skills/16_Animal_Behavior/ethoclaw-animal-grounding/reference_code.py +98 -0
  260. package/skills/16_Animal_Behavior/ethoclaw-animal-pose-estimation/SKILL.md +336 -0
  261. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/README.md +21 -0
  262. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/SKILL.md +41 -0
  263. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/batch_kinematic_generator.py +663 -0
  264. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/config.json +19 -0
  265. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/generate_kinematic_parameter.py +401 -0
  266. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/kinematic_generator.py +265 -0
  267. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/SKILL.md +72 -0
  268. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/references/config.example.toml +56 -0
  269. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/scripts/cluster_all_params.py +232 -0
  270. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/scripts/cluster_all_params_from_config.py +236 -0
  271. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/SKILL.md +68 -0
  272. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/references/notes.md +5 -0
  273. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/scripts/plot_h5_radar.py +513 -0
  274. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/SKILL.md +52 -0
  275. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/config.toml +81 -0
  276. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/references/stats-rule.md +18 -0
  277. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_inspect.py +79 -0
  278. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_violin_batch.py +624 -0
  279. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_violin_stats.py +438 -0
  280. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/SKILL.md +280 -0
  281. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/core_scripts/heatmap_trajectory.py +790 -0
  282. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/core_scripts/heatmap_velocity.py +855 -0
  283. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/reference_data/reference_2d.csv +101 -0
  284. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/reference_data/reference_2d.h5 +0 -0
  285. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/reference_data/reference_data_readme.md +126 -0
@@ -0,0 +1,491 @@
1
+ #!/usr/bin/env python3
2
+ import argparse
3
+ import gzip
4
+ import os
5
+ import re
6
+ import shutil
7
+ import subprocess
8
+ import sys
9
+ import time
10
+ from collections import defaultdict
11
+ from pathlib import Path
12
+ from typing import Iterable, List, Optional, Set, Tuple
13
+
14
+ SIDECAREXT = [".json", ".bval", ".bvec"]
15
+ DATE_PATTERN = re.compile(r"(\d{4}-\d{2}-\d{2})")
16
+
17
+
18
+ def canonical_name(name: str) -> str:
19
+ # Normalize folder names by removing all non-alphanumeric characters.
20
+ return re.sub(r"[^a-z0-9]+", "", name.lower())
21
+
22
+
23
+ def resolve_modality(folder_name: str) -> Optional[str]:
24
+ key = canonical_name(folder_name)
25
+
26
+ # T1
27
+ if "mprage" in key:
28
+ return "T1"
29
+
30
+ # Flair
31
+ if "flair" in key:
32
+ return "Flair"
33
+
34
+ # T2
35
+ if "t2space" in key or ("t2" in key and "space" in key):
36
+ return "T2"
37
+
38
+ # PD
39
+ if "pd" in key and "fse" in key:
40
+ return "PD"
41
+
42
+ # DTI
43
+ if "dti" in key:
44
+ return "DTI"
45
+
46
+ # fMRI
47
+ if "rsfmri" in key or "fmri" in key:
48
+ return "fmri"
49
+
50
+ return None
51
+
52
+
53
+ def normalize_date_name(folder_name: str) -> Optional[str]:
54
+ # Extract only YYYY-MM-DD from names like 2006-05-02_12_31_52.0
55
+ match = DATE_PATTERN.search(folder_name)
56
+ if match:
57
+ return match.group(1)
58
+ return None
59
+
60
+
61
+ def is_nifti_file(path: Path) -> bool:
62
+ name = path.name.lower()
63
+ return name.endswith(".nii") or name.endswith(".nii.gz")
64
+
65
+
66
+ def is_related_output_file(path: Path) -> bool:
67
+ name = path.name.lower()
68
+ if name.endswith(".nii") or name.endswith(".nii.gz"):
69
+ return True
70
+ return any(name.endswith(ext) for ext in SIDECAREXT)
71
+
72
+
73
+ def nifti_stem(filename: str) -> str:
74
+ if filename.endswith(".nii.gz"):
75
+ return filename[:-7]
76
+ if filename.endswith(".nii"):
77
+ return filename[:-4]
78
+ return Path(filename).stem
79
+
80
+
81
+ def gunzip_to_nii(src_gz: Path, dst_nii: Path) -> None:
82
+ dst_nii.parent.mkdir(parents=True, exist_ok=True)
83
+ if dst_nii.exists():
84
+ dst_nii.unlink()
85
+ with gzip.open(src_gz, "rb") as f_in, open(dst_nii, "wb") as f_out:
86
+ shutil.copyfileobj(f_in, f_out)
87
+ src_gz.unlink()
88
+
89
+
90
+ def move_file(src: Path, dst: Path) -> None:
91
+ dst.parent.mkdir(parents=True, exist_ok=True)
92
+ if dst.exists():
93
+ dst.unlink()
94
+ if os.path.abspath(str(src)) != os.path.abspath(str(dst)):
95
+ shutil.move(str(src), str(dst))
96
+
97
+
98
+ def cleanup_target_files(output_dir: Path, out_name: str) -> None:
99
+ candidates = [
100
+ output_dir / f"{out_name}.nii",
101
+ output_dir / f"{out_name}.nii.gz",
102
+ ]
103
+ for ext in SIDECAREXT:
104
+ candidates.append(output_dir / f"{out_name}{ext}")
105
+
106
+ for path in candidates:
107
+ if path.exists():
108
+ path.unlink()
109
+
110
+
111
+ def move_sidecars(src_dir: Path, old_stem: str, dst_dir: Path, new_stem: str) -> None:
112
+ for ext in SIDECAREXT:
113
+ src = src_dir / f"{old_stem}{ext}"
114
+ dst = dst_dir / f"{new_stem}{ext}"
115
+ if src.exists():
116
+ move_file(src, dst)
117
+
118
+
119
+ def relocate_output(primary_src: Path, output_dir: Path, out_name: str) -> Path:
120
+ output_dir.mkdir(parents=True, exist_ok=True)
121
+ final_nii = output_dir / f"{out_name}.nii"
122
+ old_stem = nifti_stem(primary_src.name)
123
+
124
+ if primary_src.name.endswith(".nii.gz"):
125
+ gunzip_to_nii(primary_src, final_nii)
126
+ elif primary_src.name.endswith(".nii"):
127
+ move_file(primary_src, final_nii)
128
+ else:
129
+ raise RuntimeError(f"Unsupported NIfTI output: {primary_src}")
130
+
131
+ move_sidecars(primary_src.parent, old_stem, output_dir, out_name)
132
+ return final_nii
133
+
134
+
135
+ def run_command(cmd: List[str], cwd: Optional[Path] = None) -> Tuple[int, str]:
136
+ result = subprocess.run(
137
+ cmd,
138
+ cwd=str(cwd) if cwd else None,
139
+ stdout=subprocess.PIPE,
140
+ stderr=subprocess.STDOUT,
141
+ text=True,
142
+ )
143
+ return result.returncode, result.stdout
144
+
145
+
146
+ def snapshot_related_files(roots: Iterable[Path]) -> Set[str]:
147
+ files: Set[str] = set()
148
+ for root in roots:
149
+ if not root.exists():
150
+ continue
151
+ for path in root.rglob("*"):
152
+ if path.is_file() and is_related_output_file(path):
153
+ files.add(str(path.resolve()))
154
+ return files
155
+
156
+
157
+ def find_recent_nifti_files(roots: Iterable[Path], start_time: float) -> List[Path]:
158
+ candidates: List[Path] = []
159
+ for root in roots:
160
+ if not root.exists():
161
+ continue
162
+ for path in root.rglob("*"):
163
+ if not path.is_file():
164
+ continue
165
+ if not is_nifti_file(path):
166
+ continue
167
+ try:
168
+ if path.stat().st_mtime >= start_time - 2:
169
+ candidates.append(path)
170
+ except FileNotFoundError:
171
+ continue
172
+ candidates.sort(key=lambda p: p.stat().st_mtime, reverse=True)
173
+ return candidates
174
+
175
+
176
+ def finalize_named_output(output_dir: Path, out_name: str) -> Optional[Path]:
177
+ exact_nii = output_dir / f"{out_name}.nii"
178
+ if exact_nii.exists():
179
+ return exact_nii
180
+
181
+ exact_niigz = output_dir / f"{out_name}.nii.gz"
182
+ if exact_niigz.exists():
183
+ return relocate_output(exact_niigz, output_dir, out_name)
184
+
185
+ candidates = []
186
+ candidates.extend(output_dir.glob(f"{out_name}*.nii"))
187
+ candidates.extend(output_dir.glob(f"{out_name}*.nii.gz"))
188
+ candidates = sorted(candidates, key=lambda p: p.stat().st_mtime, reverse=True)
189
+
190
+ if candidates:
191
+ return relocate_output(candidates[0], output_dir, out_name)
192
+
193
+ return None
194
+
195
+
196
+ def finalize_new_output(
197
+ roots: Iterable[Path],
198
+ before: Set[str],
199
+ output_dir: Path,
200
+ out_name: str,
201
+ start_time: float,
202
+ ) -> Optional[Path]:
203
+ after = snapshot_related_files(roots)
204
+ new_files = [Path(p) for p in sorted(after - before)]
205
+ nifti_candidates = [p for p in new_files if is_nifti_file(p)]
206
+
207
+ if not nifti_candidates:
208
+ nifti_candidates = find_recent_nifti_files(roots, start_time)
209
+
210
+ nifti_candidates = sorted(
211
+ nifti_candidates,
212
+ key=lambda p: p.stat().st_mtime if p.exists() else 0,
213
+ reverse=True,
214
+ )
215
+
216
+ if not nifti_candidates:
217
+ return None
218
+
219
+ return relocate_output(nifti_candidates[0], output_dir, out_name)
220
+
221
+
222
+ def convert_series(
223
+ dicom_dir: Path,
224
+ output_dir: Path,
225
+ out_name: str,
226
+ cmd_name: str,
227
+ overwrite: bool = False,
228
+ ) -> Path:
229
+ final_nii = output_dir / f"{out_name}.nii"
230
+ if final_nii.exists() and not overwrite:
231
+ return final_nii
232
+
233
+ if overwrite:
234
+ cleanup_target_files(output_dir, out_name)
235
+
236
+ output_dir.mkdir(parents=True, exist_ok=True)
237
+ logs = []
238
+
239
+ # Try dcm2niix-style arguments first.
240
+ before1 = snapshot_related_files([output_dir])
241
+ start_time1 = time.time()
242
+ rc1, log1 = run_command(
243
+ [cmd_name, "-o", str(output_dir), "-f", out_name, "-z", "n", str(dicom_dir)]
244
+ )
245
+ logs.append(f"[Attempt 1]\n{log1}")
246
+
247
+ named_result = finalize_named_output(output_dir, out_name)
248
+ if named_result is not None:
249
+ return named_result
250
+
251
+ recent_result = finalize_new_output([output_dir], before1, output_dir, out_name, start_time1)
252
+ if rc1 == 0 and recent_result is not None:
253
+ return recent_result
254
+
255
+ # Fallback to legacy dcm2nii-style invocation.
256
+ search_roots = list({output_dir, dicom_dir, dicom_dir.parent})
257
+ before2 = snapshot_related_files(search_roots)
258
+ start_time2 = time.time()
259
+ rc2, log2 = run_command([cmd_name, str(dicom_dir)], cwd=output_dir)
260
+ logs.append(f"[Attempt 2]\n{log2}")
261
+
262
+ result = finalize_new_output(search_roots, before2, output_dir, out_name, start_time2)
263
+ if result is not None:
264
+ return result
265
+
266
+ full_log = "\n".join(logs)
267
+ raise RuntimeError(
268
+ f"Conversion failed for {dicom_dir}\n"
269
+ f"Command: {cmd_name}\n"
270
+ f"Could not locate generated NIfTI output.\n"
271
+ f"{full_log}"
272
+ )
273
+
274
+
275
+ def find_first_dicom_container(date_dir: Path, max_depth: int = 6) -> Optional[Path]:
276
+ # Open the first child folder under the date folder, then keep descending
277
+ # into the first subfolder until files are found.
278
+ if not date_dir.is_dir():
279
+ return None
280
+
281
+ first_level_subdirs = sorted([p for p in date_dir.iterdir() if p.is_dir()], key=lambda p: p.name)
282
+ current = first_level_subdirs[0] if first_level_subdirs else date_dir
283
+
284
+ for _ in range(max_depth + 1):
285
+ try:
286
+ entries = list(current.iterdir())
287
+ except Exception:
288
+ return None
289
+
290
+ if any(e.is_file() for e in entries):
291
+ return current
292
+
293
+ subdirs = sorted([e for e in entries if e.is_dir()], key=lambda p: p.name)
294
+ if not subdirs:
295
+ return None
296
+
297
+ current = subdirs[0]
298
+
299
+ try:
300
+ if any(e.is_file() for e in current.iterdir()):
301
+ return current
302
+ except Exception:
303
+ return None
304
+
305
+ return None
306
+
307
+
308
+ def is_subject_dir(path: Path) -> bool:
309
+ if not path.is_dir():
310
+ return False
311
+
312
+ try:
313
+ for child in path.iterdir():
314
+ if child.is_dir() and resolve_modality(child.name):
315
+ return True
316
+ except Exception:
317
+ return False
318
+
319
+ return False
320
+
321
+
322
+ def process_subject(
323
+ subject_dir: Path,
324
+ cmd_name: str,
325
+ overwrite: bool = False,
326
+ cleanup: bool = False,
327
+ ) -> Tuple[int, int, int]:
328
+ converted = 0
329
+ skipped = 0
330
+ failed = 0
331
+ subject_has_failure = False
332
+ modality_dirs: List[Path] = []
333
+ # Tracks modality/date combinations that have already produced an output.
334
+ resolved_modality_dates: Set[Tuple[str, str]] = set()
335
+
336
+ for modality_dir in sorted(subject_dir.iterdir(), key=lambda p: p.name):
337
+ if not modality_dir.is_dir():
338
+ continue
339
+
340
+ modality_name = resolve_modality(modality_dir.name)
341
+ if modality_name is None:
342
+ print(f"[INFO] {subject_dir.name} | ignored unknown folder: {modality_dir.name}")
343
+ continue
344
+
345
+ modality_dirs.append(modality_dir)
346
+
347
+ # Group all time folders by YYYY-MM-DD.
348
+ date_groups = defaultdict(list)
349
+ for raw_date_dir in sorted(modality_dir.iterdir(), key=lambda p: p.name):
350
+ if not raw_date_dir.is_dir():
351
+ continue
352
+
353
+ date_key = normalize_date_name(raw_date_dir.name)
354
+ if date_key is None:
355
+ print(f"[WARN] {subject_dir.name} | {modality_name} | invalid date folder name: {raw_date_dir.name}")
356
+ failed += 1
357
+ subject_has_failure = True
358
+ continue
359
+
360
+ date_groups[date_key].append(raw_date_dir)
361
+
362
+ for date_key in sorted(date_groups.keys()):
363
+ same_day_dirs = sorted(date_groups[date_key], key=lambda p: p.name)
364
+ source_date_dir = same_day_dirs[0]
365
+ modality_date_key = (modality_name, date_key)
366
+
367
+ if modality_date_key in resolved_modality_dates:
368
+ print(
369
+ f"[SKIP] {subject_dir.name} | {date_key} | {modality_name} "
370
+ f"already resolved from another source folder"
371
+ )
372
+ skipped += 1
373
+ continue
374
+
375
+ if len(same_day_dirs) > 1:
376
+ ignored_names = ", ".join(p.name for p in same_day_dirs[1:])
377
+ print(
378
+ f"[WARN] {subject_dir.name} | {date_key} | {modality_name} "
379
+ f"multiple time folders found, using first: {source_date_dir.name}; ignored: {ignored_names}"
380
+ )
381
+
382
+ target_date_dir = subject_dir / date_key
383
+ target_nii = target_date_dir / f"{modality_name}.nii"
384
+
385
+ if target_nii.exists() and not overwrite:
386
+ print(f"[SKIP] {subject_dir.name} | {date_key} | {modality_name} already exists")
387
+ resolved_modality_dates.add(modality_date_key)
388
+ skipped += 1
389
+ continue
390
+
391
+ dicom_dir = find_first_dicom_container(source_date_dir)
392
+ if dicom_dir is None:
393
+ print(f"[WARN] {subject_dir.name} | {date_key} | {modality_name} no DICOM folder found")
394
+ failed += 1
395
+ subject_has_failure = True
396
+ continue
397
+
398
+ try:
399
+ target_date_dir.mkdir(parents=True, exist_ok=True)
400
+ result = convert_series(
401
+ dicom_dir=dicom_dir,
402
+ output_dir=target_date_dir,
403
+ out_name=modality_name,
404
+ cmd_name=cmd_name,
405
+ overwrite=overwrite,
406
+ )
407
+ print(f"[OK] {subject_dir.name} | {date_key} | {modality_name} -> {result}")
408
+ resolved_modality_dates.add(modality_date_key)
409
+ converted += 1
410
+ except Exception as e:
411
+ print(f"[FAIL] {subject_dir.name} | {date_key} | {modality_name}")
412
+ print(f" {e}")
413
+ failed += 1
414
+ subject_has_failure = True
415
+ if target_date_dir.exists():
416
+ try:
417
+ if not any(target_date_dir.iterdir()):
418
+ target_date_dir.rmdir()
419
+ except Exception:
420
+ pass
421
+
422
+ if cleanup and modality_dirs:
423
+ if subject_has_failure:
424
+ print(f"[KEEP] {subject_dir.name} has failures, original modality folders are kept")
425
+ else:
426
+ for modality_dir in modality_dirs:
427
+ print(f"[RM] Removing original folder: {modality_dir}")
428
+ shutil.rmtree(modality_dir)
429
+
430
+ return converted, skipped, failed
431
+
432
+
433
+ def main() -> int:
434
+ parser = argparse.ArgumentParser(
435
+ description="Reorganize ADNI folders from modality-based to date-based using YYYY-MM-DD."
436
+ )
437
+ parser.add_argument("--root", default=".", help="ADNI root directory, default is current directory")
438
+ parser.add_argument("--cmd", default="dcm2nii", help="Converter command, default is dcm2nii")
439
+ parser.add_argument("--overwrite", action="store_true", help="Overwrite existing output NIfTI files")
440
+ parser.add_argument("--cleanup", action="store_true", help="Remove original modality folders after successful conversion")
441
+ args = parser.parse_args()
442
+
443
+ root = Path(args.root).resolve()
444
+
445
+ if not root.exists() or not root.is_dir():
446
+ print(f"Root directory does not exist: {root}", file=sys.stderr)
447
+ return 1
448
+
449
+ if shutil.which(args.cmd) is None:
450
+ print(f"Command not found in PATH: {args.cmd}", file=sys.stderr)
451
+ return 1
452
+
453
+ subject_dirs = sorted([p for p in root.iterdir() if is_subject_dir(p)], key=lambda p: p.name)
454
+ if not subject_dirs:
455
+ print("No subject folders containing known modality folders were found.")
456
+ return 0
457
+
458
+ total_converted = 0
459
+ total_skipped = 0
460
+ total_failed = 0
461
+
462
+ print(f"Found {len(subject_dirs)} subject folders")
463
+ print(f"Using converter command: {args.cmd}")
464
+ print("Date folders will be normalized to YYYY-MM-DD")
465
+ print("Start processing...\n")
466
+
467
+ for subject_dir in subject_dirs:
468
+ print(f"=== Processing subject: {subject_dir.name} ===")
469
+ converted, skipped, failed = process_subject(
470
+ subject_dir=subject_dir,
471
+ cmd_name=args.cmd,
472
+ overwrite=args.overwrite,
473
+ cleanup=args.cleanup,
474
+ )
475
+ total_converted += converted
476
+ total_skipped += skipped
477
+ total_failed += failed
478
+ print(
479
+ f"=== Done: {subject_dir.name} | converted={converted}, skipped={skipped}, failed={failed} ===\n"
480
+ )
481
+
482
+ print("All done")
483
+ print(f"Converted: {total_converted}")
484
+ print(f"Skipped: {total_skipped}")
485
+ print(f"Failed: {total_failed}")
486
+
487
+ return 0 if total_failed == 0 else 2
488
+
489
+
490
+ if __name__ == "__main__":
491
+ sys.exit(main())