scientific-writer 2.3.1__py3-none-any.whl
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.
- scientific_writer/.claude/WRITER.md +822 -0
- scientific_writer/.claude/settings.local.json +30 -0
- scientific_writer/.claude/skills/citation-management/SKILL.md +1046 -0
- scientific_writer/.claude/skills/citation-management/assets/bibtex_template.bib +264 -0
- scientific_writer/.claude/skills/citation-management/assets/citation_checklist.md +386 -0
- scientific_writer/.claude/skills/citation-management/references/bibtex_formatting.md +908 -0
- scientific_writer/.claude/skills/citation-management/references/citation_validation.md +794 -0
- scientific_writer/.claude/skills/citation-management/references/google_scholar_search.md +725 -0
- scientific_writer/.claude/skills/citation-management/references/metadata_extraction.md +870 -0
- scientific_writer/.claude/skills/citation-management/references/pubmed_search.md +839 -0
- scientific_writer/.claude/skills/citation-management/scripts/doi_to_bibtex.py +204 -0
- scientific_writer/.claude/skills/citation-management/scripts/extract_metadata.py +569 -0
- scientific_writer/.claude/skills/citation-management/scripts/format_bibtex.py +349 -0
- scientific_writer/.claude/skills/citation-management/scripts/search_google_scholar.py +282 -0
- scientific_writer/.claude/skills/citation-management/scripts/search_pubmed.py +398 -0
- scientific_writer/.claude/skills/citation-management/scripts/validate_citations.py +497 -0
- scientific_writer/.claude/skills/clinical-reports/IMPLEMENTATION_SUMMARY.md +641 -0
- scientific_writer/.claude/skills/clinical-reports/README.md +236 -0
- scientific_writer/.claude/skills/clinical-reports/SKILL.md +1088 -0
- scientific_writer/.claude/skills/clinical-reports/assets/case_report_template.md +352 -0
- scientific_writer/.claude/skills/clinical-reports/assets/clinical_trial_csr_template.md +353 -0
- scientific_writer/.claude/skills/clinical-reports/assets/clinical_trial_sae_template.md +359 -0
- scientific_writer/.claude/skills/clinical-reports/assets/consult_note_template.md +305 -0
- scientific_writer/.claude/skills/clinical-reports/assets/discharge_summary_template.md +453 -0
- scientific_writer/.claude/skills/clinical-reports/assets/hipaa_compliance_checklist.md +395 -0
- scientific_writer/.claude/skills/clinical-reports/assets/history_physical_template.md +305 -0
- scientific_writer/.claude/skills/clinical-reports/assets/lab_report_template.md +309 -0
- scientific_writer/.claude/skills/clinical-reports/assets/pathology_report_template.md +249 -0
- scientific_writer/.claude/skills/clinical-reports/assets/quality_checklist.md +338 -0
- scientific_writer/.claude/skills/clinical-reports/assets/radiology_report_template.md +318 -0
- scientific_writer/.claude/skills/clinical-reports/assets/soap_note_template.md +253 -0
- scientific_writer/.claude/skills/clinical-reports/references/case_report_guidelines.md +570 -0
- scientific_writer/.claude/skills/clinical-reports/references/clinical_trial_reporting.md +693 -0
- scientific_writer/.claude/skills/clinical-reports/references/data_presentation.md +530 -0
- scientific_writer/.claude/skills/clinical-reports/references/diagnostic_reports_standards.md +629 -0
- scientific_writer/.claude/skills/clinical-reports/references/medical_terminology.md +588 -0
- scientific_writer/.claude/skills/clinical-reports/references/patient_documentation.md +744 -0
- scientific_writer/.claude/skills/clinical-reports/references/peer_review_standards.md +585 -0
- scientific_writer/.claude/skills/clinical-reports/references/regulatory_compliance.md +577 -0
- scientific_writer/.claude/skills/clinical-reports/scripts/check_deidentification.py +346 -0
- scientific_writer/.claude/skills/clinical-reports/scripts/compliance_checker.py +78 -0
- scientific_writer/.claude/skills/clinical-reports/scripts/extract_clinical_data.py +102 -0
- scientific_writer/.claude/skills/clinical-reports/scripts/format_adverse_events.py +103 -0
- scientific_writer/.claude/skills/clinical-reports/scripts/generate_report_template.py +163 -0
- scientific_writer/.claude/skills/clinical-reports/scripts/terminology_validator.py +133 -0
- scientific_writer/.claude/skills/clinical-reports/scripts/validate_case_report.py +334 -0
- scientific_writer/.claude/skills/clinical-reports/scripts/validate_trial_report.py +89 -0
- scientific_writer/.claude/skills/document-skills/docx/LICENSE.txt +30 -0
- scientific_writer/.claude/skills/document-skills/docx/SKILL.md +197 -0
- scientific_writer/.claude/skills/document-skills/docx/docx-js.md +350 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/mce/mc.xsd +75 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/scripts/pack.py +159 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/scripts/unpack.py +29 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/scripts/validate.py +69 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/scripts/validation/__init__.py +15 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/scripts/validation/base.py +951 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/scripts/validation/docx.py +274 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/scripts/validation/pptx.py +315 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml/scripts/validation/redlining.py +279 -0
- scientific_writer/.claude/skills/document-skills/docx/ooxml.md +610 -0
- scientific_writer/.claude/skills/document-skills/docx/scripts/__init__.py +1 -0
- scientific_writer/.claude/skills/document-skills/docx/scripts/document.py +1276 -0
- scientific_writer/.claude/skills/document-skills/docx/scripts/templates/comments.xml +3 -0
- scientific_writer/.claude/skills/document-skills/docx/scripts/templates/commentsExtended.xml +3 -0
- scientific_writer/.claude/skills/document-skills/docx/scripts/templates/commentsExtensible.xml +3 -0
- scientific_writer/.claude/skills/document-skills/docx/scripts/templates/commentsIds.xml +3 -0
- scientific_writer/.claude/skills/document-skills/docx/scripts/templates/people.xml +3 -0
- scientific_writer/.claude/skills/document-skills/docx/scripts/utilities.py +374 -0
- scientific_writer/.claude/skills/document-skills/pdf/LICENSE.txt +30 -0
- scientific_writer/.claude/skills/document-skills/pdf/SKILL.md +294 -0
- scientific_writer/.claude/skills/document-skills/pdf/forms.md +205 -0
- scientific_writer/.claude/skills/document-skills/pdf/reference.md +612 -0
- scientific_writer/.claude/skills/document-skills/pdf/scripts/check_bounding_boxes.py +70 -0
- scientific_writer/.claude/skills/document-skills/pdf/scripts/check_bounding_boxes_test.py +226 -0
- scientific_writer/.claude/skills/document-skills/pdf/scripts/check_fillable_fields.py +12 -0
- scientific_writer/.claude/skills/document-skills/pdf/scripts/convert_pdf_to_images.py +35 -0
- scientific_writer/.claude/skills/document-skills/pdf/scripts/create_validation_image.py +41 -0
- scientific_writer/.claude/skills/document-skills/pdf/scripts/extract_form_field_info.py +152 -0
- scientific_writer/.claude/skills/document-skills/pdf/scripts/fill_fillable_fields.py +114 -0
- scientific_writer/.claude/skills/document-skills/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
- scientific_writer/.claude/skills/document-skills/pptx/LICENSE.txt +30 -0
- scientific_writer/.claude/skills/document-skills/pptx/SKILL.md +484 -0
- scientific_writer/.claude/skills/document-skills/pptx/html2pptx.md +625 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/mce/mc.xsd +75 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/scripts/pack.py +159 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/scripts/unpack.py +29 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/scripts/validate.py +69 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/scripts/validation/__init__.py +15 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/scripts/validation/base.py +951 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/scripts/validation/docx.py +274 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/scripts/validation/pptx.py +315 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml/scripts/validation/redlining.py +279 -0
- scientific_writer/.claude/skills/document-skills/pptx/ooxml.md +427 -0
- scientific_writer/.claude/skills/document-skills/pptx/scripts/html2pptx.js +979 -0
- scientific_writer/.claude/skills/document-skills/pptx/scripts/inventory.py +1020 -0
- scientific_writer/.claude/skills/document-skills/pptx/scripts/rearrange.py +231 -0
- scientific_writer/.claude/skills/document-skills/pptx/scripts/replace.py +385 -0
- scientific_writer/.claude/skills/document-skills/pptx/scripts/thumbnail.py +450 -0
- scientific_writer/.claude/skills/document-skills/xlsx/LICENSE.txt +30 -0
- scientific_writer/.claude/skills/document-skills/xlsx/SKILL.md +289 -0
- scientific_writer/.claude/skills/document-skills/xlsx/recalc.py +178 -0
- scientific_writer/.claude/skills/hypothesis-generation/SKILL.md +155 -0
- scientific_writer/.claude/skills/hypothesis-generation/assets/hypothesis_output_template.md +302 -0
- scientific_writer/.claude/skills/hypothesis-generation/references/experimental_design_patterns.md +327 -0
- scientific_writer/.claude/skills/hypothesis-generation/references/hypothesis_quality_criteria.md +196 -0
- scientific_writer/.claude/skills/hypothesis-generation/references/literature_search_strategies.md +505 -0
- scientific_writer/.claude/skills/latex-posters/README.md +417 -0
- scientific_writer/.claude/skills/latex-posters/SKILL.md +919 -0
- scientific_writer/.claude/skills/latex-posters/assets/baposter_template.tex +257 -0
- scientific_writer/.claude/skills/latex-posters/assets/beamerposter_template.tex +244 -0
- scientific_writer/.claude/skills/latex-posters/assets/poster_quality_checklist.md +358 -0
- scientific_writer/.claude/skills/latex-posters/assets/tikzposter_template.tex +251 -0
- scientific_writer/.claude/skills/latex-posters/references/latex_poster_packages.md +745 -0
- scientific_writer/.claude/skills/latex-posters/references/poster_content_guide.md +748 -0
- scientific_writer/.claude/skills/latex-posters/references/poster_design_principles.md +806 -0
- scientific_writer/.claude/skills/latex-posters/references/poster_layout_design.md +900 -0
- scientific_writer/.claude/skills/latex-posters/scripts/review_poster.sh +214 -0
- scientific_writer/.claude/skills/literature-review/SKILL.md +546 -0
- scientific_writer/.claude/skills/literature-review/assets/review_template.md +412 -0
- scientific_writer/.claude/skills/literature-review/references/citation_styles.md +166 -0
- scientific_writer/.claude/skills/literature-review/references/database_strategies.md +381 -0
- scientific_writer/.claude/skills/literature-review/scripts/generate_pdf.py +176 -0
- scientific_writer/.claude/skills/literature-review/scripts/search_databases.py +303 -0
- scientific_writer/.claude/skills/literature-review/scripts/verify_citations.py +222 -0
- scientific_writer/.claude/skills/markitdown/INSTALLATION_GUIDE.md +318 -0
- scientific_writer/.claude/skills/markitdown/LICENSE.txt +22 -0
- scientific_writer/.claude/skills/markitdown/OPENROUTER_INTEGRATION.md +359 -0
- scientific_writer/.claude/skills/markitdown/QUICK_REFERENCE.md +309 -0
- scientific_writer/.claude/skills/markitdown/README.md +184 -0
- scientific_writer/.claude/skills/markitdown/SKILL.md +450 -0
- scientific_writer/.claude/skills/markitdown/SKILL_SUMMARY.md +307 -0
- scientific_writer/.claude/skills/markitdown/assets/example_usage.md +463 -0
- scientific_writer/.claude/skills/markitdown/references/api_reference.md +399 -0
- scientific_writer/.claude/skills/markitdown/references/file_formats.md +542 -0
- scientific_writer/.claude/skills/markitdown/scripts/batch_convert.py +228 -0
- scientific_writer/.claude/skills/markitdown/scripts/convert_literature.py +283 -0
- scientific_writer/.claude/skills/markitdown/scripts/convert_with_ai.py +243 -0
- scientific_writer/.claude/skills/paper-2-web/SKILL.md +455 -0
- scientific_writer/.claude/skills/paper-2-web/references/installation.md +141 -0
- scientific_writer/.claude/skills/paper-2-web/references/paper2poster.md +346 -0
- scientific_writer/.claude/skills/paper-2-web/references/paper2video.md +305 -0
- scientific_writer/.claude/skills/paper-2-web/references/paper2web.md +187 -0
- scientific_writer/.claude/skills/paper-2-web/references/usage_examples.md +436 -0
- scientific_writer/.claude/skills/peer-review/SKILL.md +375 -0
- scientific_writer/.claude/skills/peer-review/references/common_issues.md +552 -0
- scientific_writer/.claude/skills/peer-review/references/reporting_standards.md +290 -0
- scientific_writer/.claude/skills/research-grants/README.md +285 -0
- scientific_writer/.claude/skills/research-grants/SKILL.md +896 -0
- scientific_writer/.claude/skills/research-grants/assets/budget_justification_template.md +453 -0
- scientific_writer/.claude/skills/research-grants/assets/nih_specific_aims_template.md +166 -0
- scientific_writer/.claude/skills/research-grants/assets/nsf_project_summary_template.md +92 -0
- scientific_writer/.claude/skills/research-grants/references/broader_impacts.md +392 -0
- scientific_writer/.claude/skills/research-grants/references/darpa_guidelines.md +636 -0
- scientific_writer/.claude/skills/research-grants/references/doe_guidelines.md +586 -0
- scientific_writer/.claude/skills/research-grants/references/nih_guidelines.md +851 -0
- scientific_writer/.claude/skills/research-grants/references/nsf_guidelines.md +570 -0
- scientific_writer/.claude/skills/research-grants/references/specific_aims_guide.md +458 -0
- scientific_writer/.claude/skills/research-lookup/README.md +116 -0
- scientific_writer/.claude/skills/research-lookup/SKILL.md +443 -0
- scientific_writer/.claude/skills/research-lookup/examples.py +174 -0
- scientific_writer/.claude/skills/research-lookup/lookup.py +93 -0
- scientific_writer/.claude/skills/research-lookup/research_lookup.py +335 -0
- scientific_writer/.claude/skills/research-lookup/scripts/research_lookup.py +261 -0
- scientific_writer/.claude/skills/scholar-evaluation/SKILL.md +254 -0
- scientific_writer/.claude/skills/scholar-evaluation/references/evaluation_framework.md +663 -0
- scientific_writer/.claude/skills/scholar-evaluation/scripts/calculate_scores.py +378 -0
- scientific_writer/.claude/skills/scientific-critical-thinking/SKILL.md +530 -0
- scientific_writer/.claude/skills/scientific-critical-thinking/references/common_biases.md +364 -0
- scientific_writer/.claude/skills/scientific-critical-thinking/references/evidence_hierarchy.md +484 -0
- scientific_writer/.claude/skills/scientific-critical-thinking/references/experimental_design.md +496 -0
- scientific_writer/.claude/skills/scientific-critical-thinking/references/logical_fallacies.md +478 -0
- scientific_writer/.claude/skills/scientific-critical-thinking/references/scientific_method.md +169 -0
- scientific_writer/.claude/skills/scientific-critical-thinking/references/statistical_pitfalls.md +506 -0
- scientific_writer/.claude/skills/scientific-schematics/SKILL.md +2035 -0
- scientific_writer/.claude/skills/scientific-schematics/assets/block_diagram_template.tex +199 -0
- scientific_writer/.claude/skills/scientific-schematics/assets/circuit_template.tex +159 -0
- scientific_writer/.claude/skills/scientific-schematics/assets/flowchart_template.tex +161 -0
- scientific_writer/.claude/skills/scientific-schematics/assets/pathway_template.tex +162 -0
- scientific_writer/.claude/skills/scientific-schematics/assets/tikz_styles.tex +422 -0
- scientific_writer/.claude/skills/scientific-schematics/references/best_practices.md +562 -0
- scientific_writer/.claude/skills/scientific-schematics/references/diagram_types.md +637 -0
- scientific_writer/.claude/skills/scientific-schematics/references/python_libraries.md +791 -0
- scientific_writer/.claude/skills/scientific-schematics/references/tikz_guide.md +734 -0
- scientific_writer/.claude/skills/scientific-schematics/scripts/circuit_generator.py +307 -0
- scientific_writer/.claude/skills/scientific-schematics/scripts/compile_tikz.py +292 -0
- scientific_writer/.claude/skills/scientific-schematics/scripts/generate_flowchart.py +281 -0
- scientific_writer/.claude/skills/scientific-schematics/scripts/pathway_diagram.py +406 -0
- scientific_writer/.claude/skills/scientific-writing/SKILL.md +443 -0
- scientific_writer/.claude/skills/scientific-writing/references/citation_styles.md +720 -0
- scientific_writer/.claude/skills/scientific-writing/references/figures_tables.md +806 -0
- scientific_writer/.claude/skills/scientific-writing/references/imrad_structure.md +658 -0
- scientific_writer/.claude/skills/scientific-writing/references/reporting_guidelines.md +748 -0
- scientific_writer/.claude/skills/scientific-writing/references/writing_principles.md +824 -0
- scientific_writer/.claude/skills/treatment-plans/README.md +488 -0
- scientific_writer/.claude/skills/treatment-plans/SKILL.md +1536 -0
- scientific_writer/.claude/skills/treatment-plans/assets/STYLING_QUICK_REFERENCE.md +185 -0
- scientific_writer/.claude/skills/treatment-plans/assets/chronic_disease_management_plan.tex +665 -0
- scientific_writer/.claude/skills/treatment-plans/assets/general_medical_treatment_plan.tex +547 -0
- scientific_writer/.claude/skills/treatment-plans/assets/medical_treatment_plan.sty +222 -0
- scientific_writer/.claude/skills/treatment-plans/assets/mental_health_treatment_plan.tex +774 -0
- scientific_writer/.claude/skills/treatment-plans/assets/one_page_treatment_plan.tex +193 -0
- scientific_writer/.claude/skills/treatment-plans/assets/pain_management_plan.tex +799 -0
- scientific_writer/.claude/skills/treatment-plans/assets/perioperative_care_plan.tex +753 -0
- scientific_writer/.claude/skills/treatment-plans/assets/quality_checklist.md +471 -0
- scientific_writer/.claude/skills/treatment-plans/assets/rehabilitation_treatment_plan.tex +756 -0
- scientific_writer/.claude/skills/treatment-plans/references/goal_setting_frameworks.md +411 -0
- scientific_writer/.claude/skills/treatment-plans/references/intervention_guidelines.md +507 -0
- scientific_writer/.claude/skills/treatment-plans/references/regulatory_compliance.md +476 -0
- scientific_writer/.claude/skills/treatment-plans/references/specialty_specific_guidelines.md +655 -0
- scientific_writer/.claude/skills/treatment-plans/references/treatment_plan_standards.md +485 -0
- scientific_writer/.claude/skills/treatment-plans/scripts/check_completeness.py +318 -0
- scientific_writer/.claude/skills/treatment-plans/scripts/generate_template.py +244 -0
- scientific_writer/.claude/skills/treatment-plans/scripts/timeline_generator.py +369 -0
- scientific_writer/.claude/skills/treatment-plans/scripts/validate_treatment_plan.py +367 -0
- scientific_writer/.claude/skills/venue-templates/SKILL.md +590 -0
- scientific_writer/.claude/skills/venue-templates/assets/grants/nih_specific_aims.tex +235 -0
- scientific_writer/.claude/skills/venue-templates/assets/grants/nsf_proposal_template.tex +375 -0
- scientific_writer/.claude/skills/venue-templates/assets/journals/nature_article.tex +171 -0
- scientific_writer/.claude/skills/venue-templates/assets/journals/neurips_article.tex +283 -0
- scientific_writer/.claude/skills/venue-templates/assets/journals/plos_one.tex +317 -0
- scientific_writer/.claude/skills/venue-templates/assets/posters/beamerposter_academic.tex +311 -0
- scientific_writer/.claude/skills/venue-templates/references/conferences_formatting.md +564 -0
- scientific_writer/.claude/skills/venue-templates/references/grants_requirements.md +787 -0
- scientific_writer/.claude/skills/venue-templates/references/journals_formatting.md +486 -0
- scientific_writer/.claude/skills/venue-templates/references/posters_guidelines.md +628 -0
- scientific_writer/.claude/skills/venue-templates/scripts/customize_template.py +206 -0
- scientific_writer/.claude/skills/venue-templates/scripts/query_template.py +260 -0
- scientific_writer/.claude/skills/venue-templates/scripts/validate_format.py +255 -0
- scientific_writer/__init__.py +43 -0
- scientific_writer/api.py +393 -0
- scientific_writer/cli.py +326 -0
- scientific_writer/core.py +275 -0
- scientific_writer/models.py +76 -0
- scientific_writer/utils.py +289 -0
- scientific_writer-2.3.1.dist-info/METADATA +272 -0
- scientific_writer-2.3.1.dist-info/RECORD +315 -0
- scientific_writer-2.3.1.dist-info/WHEEL +4 -0
- scientific_writer-2.3.1.dist-info/entry_points.txt +2 -0
- scientific_writer-2.3.1.dist-info/licenses/LICENSE +22 -0
scientific_writer/cli.py
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Scientific Writer CLI Tool
|
|
4
|
+
A command-line interface for scientific writing powered by Claude Code.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
import time
|
|
10
|
+
import asyncio
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Optional
|
|
13
|
+
from dotenv import load_dotenv
|
|
14
|
+
|
|
15
|
+
from claude_agent_sdk import query, ClaudeAgentOptions
|
|
16
|
+
|
|
17
|
+
from .core import (
|
|
18
|
+
get_api_key,
|
|
19
|
+
load_system_instructions,
|
|
20
|
+
ensure_output_folder,
|
|
21
|
+
get_data_files,
|
|
22
|
+
process_data_files,
|
|
23
|
+
create_data_context_message,
|
|
24
|
+
setup_claude_skills,
|
|
25
|
+
)
|
|
26
|
+
from .utils import find_existing_papers, detect_paper_reference
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
async def main():
|
|
30
|
+
"""Main CLI loop for the scientific writer."""
|
|
31
|
+
# Explicitly load .env file from current working directory
|
|
32
|
+
# This ensures API keys are available in the shell environment
|
|
33
|
+
cwd_resolved = Path.cwd().resolve()
|
|
34
|
+
env_file = cwd_resolved / ".env"
|
|
35
|
+
if env_file.exists():
|
|
36
|
+
load_dotenv(dotenv_path=env_file, override=True)
|
|
37
|
+
|
|
38
|
+
# Get API key (verify it exists)
|
|
39
|
+
try:
|
|
40
|
+
get_api_key()
|
|
41
|
+
except ValueError as e:
|
|
42
|
+
print(f"Error: {e}")
|
|
43
|
+
sys.exit(1)
|
|
44
|
+
|
|
45
|
+
# Get the current working directory (user's directory) and package directory
|
|
46
|
+
# Capture and resolve the current working directory at CLI invocation time
|
|
47
|
+
cwd = Path.cwd().resolve() # User's current working directory (absolute path)
|
|
48
|
+
package_dir = Path(__file__).parent.absolute() # Package installation directory (scientific_writer/)
|
|
49
|
+
|
|
50
|
+
# Set up Claude skills in the working directory (includes WRITER.md)
|
|
51
|
+
setup_claude_skills(package_dir, cwd)
|
|
52
|
+
|
|
53
|
+
# Ensure paper_outputs folder exists in user's directory
|
|
54
|
+
output_folder = ensure_output_folder(cwd)
|
|
55
|
+
|
|
56
|
+
# Load system instructions from .claude/WRITER.md in working directory
|
|
57
|
+
system_instructions = load_system_instructions(cwd)
|
|
58
|
+
|
|
59
|
+
# Add conversation continuity instruction
|
|
60
|
+
# Note: The Python CLI handles session tracking via current_paper_path
|
|
61
|
+
# These instructions only apply WITHIN a single CLI session, not across different chat sessions
|
|
62
|
+
system_instructions += "\n\n" + f"""
|
|
63
|
+
IMPORTANT - WORKING DIRECTORY:
|
|
64
|
+
- Your working directory is: {cwd}
|
|
65
|
+
- ALWAYS create paper_outputs folder in this directory: {cwd}/paper_outputs/
|
|
66
|
+
- NEVER write to /tmp/ or any other temporary directory
|
|
67
|
+
- All paper outputs MUST go to: {cwd}/paper_outputs/<timestamp>_<description>/
|
|
68
|
+
|
|
69
|
+
IMPORTANT - CONVERSATION CONTINUITY:
|
|
70
|
+
- The user will provide context in their prompt if they want to continue working on an existing paper
|
|
71
|
+
- If the prompt includes [CONTEXT: You are currently working on a paper in: ...], continue editing that paper
|
|
72
|
+
- If no such context is provided, this is a NEW paper request - create a new paper directory
|
|
73
|
+
- Do NOT assume there's an existing paper unless explicitly told in the prompt context
|
|
74
|
+
- Each new chat session should start with a new paper unless context says otherwise
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
# Configure the Claude agent options
|
|
78
|
+
options = ClaudeAgentOptions(
|
|
79
|
+
system_prompt=system_instructions,
|
|
80
|
+
model="claude-sonnet-4-5", # Always use Claude Sonnet 4.5
|
|
81
|
+
allowed_tools=["Read", "Write", "Edit", "Bash", "research-lookup"], # Default Claude Code tools + research lookup
|
|
82
|
+
permission_mode="bypassPermissions", # Execute immediately without approval prompts
|
|
83
|
+
setting_sources=["project"], # Load skills from project .claude directory
|
|
84
|
+
cwd=str(cwd), # Set working directory to user's current directory
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Track conversation state
|
|
88
|
+
current_paper_path = None
|
|
89
|
+
conversation_history = []
|
|
90
|
+
|
|
91
|
+
# Print welcome message
|
|
92
|
+
print("=" * 70)
|
|
93
|
+
print("Scientific Writer CLI - Powered by Claude Sonnet 4.5")
|
|
94
|
+
print("=" * 70)
|
|
95
|
+
print("\nWelcome! I'm your scientific writing assistant.")
|
|
96
|
+
print("\nI can help you with:")
|
|
97
|
+
print(" ⢠Writing scientific papers (IMRaD structure)")
|
|
98
|
+
print(" ⢠Literature reviews and citation management")
|
|
99
|
+
print(" ⢠Peer review feedback")
|
|
100
|
+
print(" ⢠Real-time research lookup using Perplexity Sonar Pro")
|
|
101
|
+
print(" ⢠Document manipulation (docx, pdf, pptx, xlsx)")
|
|
102
|
+
print("\nš Workflow:")
|
|
103
|
+
print(" 1. I'll present a brief plan and immediately start execution")
|
|
104
|
+
print(" 2. I'll provide continuous updates during the process")
|
|
105
|
+
print(" 3. All outputs saved to: paper_outputs/<timestamp_description>/")
|
|
106
|
+
print(" 4. Progress tracked in real-time in progress.md")
|
|
107
|
+
print(f"\nš Working directory: {cwd}")
|
|
108
|
+
print(f"š Output folder: {output_folder}")
|
|
109
|
+
print(f"\nš¦ Data Files:")
|
|
110
|
+
print(" ⢠Place files in the 'data/' folder to include them in your paper")
|
|
111
|
+
print(" ⢠Manuscript files (.tex, .md, .docx, .pdf) ā copied to drafts/ for EDITING")
|
|
112
|
+
print(" ⢠Data files (csv, txt, json, etc.) ā copied to paper's data/ folder")
|
|
113
|
+
print(" ⢠Images (png, jpg, svg, etc.) ā copied to paper's figures/ folder")
|
|
114
|
+
print(" ⢠Original files are automatically deleted after copying")
|
|
115
|
+
print("\nš¤ Intelligent Paper Detection:")
|
|
116
|
+
print(" ⢠I automatically detect when you're referring to a previous paper")
|
|
117
|
+
print(" ⢠Continue: 'continue', 'update', 'edit', 'the paper', etc.")
|
|
118
|
+
print(" ⢠Search: 'look for', 'find', 'show me', 'where is', etc.")
|
|
119
|
+
print(" ⢠Or reference the paper topic (e.g., 'find the acoustics paper')")
|
|
120
|
+
print(" ⢠Say 'new paper' to explicitly start a fresh paper")
|
|
121
|
+
print("\nType 'exit' or 'quit' to end the session.")
|
|
122
|
+
print("Type 'help' for usage tips.")
|
|
123
|
+
print("=" * 70)
|
|
124
|
+
print()
|
|
125
|
+
|
|
126
|
+
# Main loop
|
|
127
|
+
while True:
|
|
128
|
+
try:
|
|
129
|
+
# Get user input
|
|
130
|
+
user_input = input("\n> ").strip()
|
|
131
|
+
|
|
132
|
+
# Handle special commands
|
|
133
|
+
if user_input.lower() in ["exit", "quit"]:
|
|
134
|
+
print("\nThank you for using Scientific Writer CLI. Goodbye!")
|
|
135
|
+
break
|
|
136
|
+
|
|
137
|
+
if user_input.lower() == "help":
|
|
138
|
+
_print_help()
|
|
139
|
+
continue
|
|
140
|
+
|
|
141
|
+
if not user_input:
|
|
142
|
+
continue
|
|
143
|
+
|
|
144
|
+
# Get all existing papers
|
|
145
|
+
existing_papers = find_existing_papers(output_folder)
|
|
146
|
+
|
|
147
|
+
# Check if user wants to start a new paper
|
|
148
|
+
new_paper_keywords = ["new paper", "start fresh", "start afresh", "create new", "different paper", "another paper"]
|
|
149
|
+
is_new_paper_request = any(keyword in user_input.lower() for keyword in new_paper_keywords)
|
|
150
|
+
|
|
151
|
+
# Try to detect reference to existing paper
|
|
152
|
+
detected_paper_path = None
|
|
153
|
+
if not is_new_paper_request:
|
|
154
|
+
detected_paper_path = detect_paper_reference(user_input, existing_papers)
|
|
155
|
+
|
|
156
|
+
# If we detected a paper reference and it's different from current, update it
|
|
157
|
+
if detected_paper_path and str(detected_paper_path) != current_paper_path:
|
|
158
|
+
current_paper_path = str(detected_paper_path)
|
|
159
|
+
print(f"\nš Detected reference to existing paper: {detected_paper_path.name}")
|
|
160
|
+
print(f"š Working on: {current_paper_path}\n")
|
|
161
|
+
elif detected_paper_path and str(detected_paper_path) == current_paper_path:
|
|
162
|
+
# Already working on the right paper, just confirm
|
|
163
|
+
print(f"š Continuing with: {Path(current_paper_path).name}\n")
|
|
164
|
+
|
|
165
|
+
# Check for data files and process them if we have a current paper
|
|
166
|
+
data_context = ""
|
|
167
|
+
data_files = get_data_files(cwd)
|
|
168
|
+
|
|
169
|
+
if data_files and current_paper_path and not is_new_paper_request:
|
|
170
|
+
print(f"š¦ Found {len(data_files)} file(s) in data folder. Processing...")
|
|
171
|
+
processed_info = process_data_files(cwd, data_files, current_paper_path)
|
|
172
|
+
if processed_info:
|
|
173
|
+
data_context = create_data_context_message(processed_info)
|
|
174
|
+
manuscript_count = len(processed_info.get('manuscript_files', []))
|
|
175
|
+
data_count = len(processed_info.get('data_files', []))
|
|
176
|
+
image_count = len(processed_info.get('image_files', []))
|
|
177
|
+
if manuscript_count > 0:
|
|
178
|
+
print(f" ā Copied {manuscript_count} manuscript file(s) to drafts/ [EDITING MODE]")
|
|
179
|
+
if data_count > 0:
|
|
180
|
+
print(f" ā Copied {data_count} data file(s) to data/")
|
|
181
|
+
if image_count > 0:
|
|
182
|
+
print(f" ā Copied {image_count} image(s) to figures/")
|
|
183
|
+
print(" ā Deleted original files from data folder\n")
|
|
184
|
+
elif data_files and not current_paper_path:
|
|
185
|
+
# Store data files info for later processing once paper is created
|
|
186
|
+
print(f"\nš¦ Found {len(data_files)} file(s) in data folder.")
|
|
187
|
+
print(" They will be processed once the paper directory is created.\n")
|
|
188
|
+
|
|
189
|
+
# Build contextual prompt
|
|
190
|
+
contextual_prompt = user_input
|
|
191
|
+
|
|
192
|
+
# Add context about current paper if one exists and not starting new
|
|
193
|
+
if current_paper_path and not is_new_paper_request:
|
|
194
|
+
contextual_prompt = f"""[CONTEXT: You are currently working on a paper in: {current_paper_path}]
|
|
195
|
+
[INSTRUCTION: Continue editing this existing paper. Do NOT create a new paper directory.]
|
|
196
|
+
{data_context}
|
|
197
|
+
User request: {user_input}"""
|
|
198
|
+
elif is_new_paper_request:
|
|
199
|
+
# Reset paper tracking when explicitly starting new
|
|
200
|
+
current_paper_path = None
|
|
201
|
+
print("š Starting a new paper...\n")
|
|
202
|
+
|
|
203
|
+
# Send query to Claude
|
|
204
|
+
print() # Add blank line before response
|
|
205
|
+
async for message in query(prompt=contextual_prompt, options=options):
|
|
206
|
+
# Handle AssistantMessage with content blocks
|
|
207
|
+
if hasattr(message, "content") and message.content:
|
|
208
|
+
for block in message.content:
|
|
209
|
+
if hasattr(block, "text"):
|
|
210
|
+
print(block.text, end="", flush=True)
|
|
211
|
+
|
|
212
|
+
print() # Add blank line after response
|
|
213
|
+
|
|
214
|
+
# Try to detect if a new paper directory was created
|
|
215
|
+
if not current_paper_path or is_new_paper_request:
|
|
216
|
+
# Look for the most recently modified directory in paper_outputs
|
|
217
|
+
# Only update if it was modified in the last 10 seconds (indicating it was just created)
|
|
218
|
+
try:
|
|
219
|
+
paper_dirs = [d for d in output_folder.iterdir() if d.is_dir()]
|
|
220
|
+
if paper_dirs:
|
|
221
|
+
most_recent = max(paper_dirs, key=lambda d: d.stat().st_mtime)
|
|
222
|
+
time_since_modification = time.time() - most_recent.stat().st_mtime
|
|
223
|
+
|
|
224
|
+
# Only set as current paper if it was modified very recently (within last 10 seconds)
|
|
225
|
+
if time_since_modification < 10:
|
|
226
|
+
current_paper_path = str(most_recent)
|
|
227
|
+
print(f"\nš Working on: {most_recent.name}")
|
|
228
|
+
except Exception:
|
|
229
|
+
pass # Silently fail if we can't detect the directory
|
|
230
|
+
|
|
231
|
+
# Process any remaining data files now that we have a paper path
|
|
232
|
+
# This is outside the try-except so file processing errors are not silently ignored
|
|
233
|
+
if current_paper_path:
|
|
234
|
+
remaining_data_files = get_data_files(cwd)
|
|
235
|
+
if remaining_data_files:
|
|
236
|
+
print(f"\nš¦ Processing {len(remaining_data_files)} data file(s)...")
|
|
237
|
+
processed_info = process_data_files(cwd, remaining_data_files, current_paper_path)
|
|
238
|
+
if processed_info:
|
|
239
|
+
manuscript_count = len(processed_info.get('manuscript_files', []))
|
|
240
|
+
data_count = len(processed_info.get('data_files', []))
|
|
241
|
+
image_count = len(processed_info.get('image_files', []))
|
|
242
|
+
if manuscript_count > 0:
|
|
243
|
+
print(f" ā Copied {manuscript_count} manuscript file(s) to drafts/ [EDITING MODE]")
|
|
244
|
+
if data_count > 0:
|
|
245
|
+
print(f" ā Copied {data_count} data file(s) to data/")
|
|
246
|
+
if image_count > 0:
|
|
247
|
+
print(f" ā Copied {image_count} image(s) to figures/")
|
|
248
|
+
print(" ā Deleted original files from data folder")
|
|
249
|
+
|
|
250
|
+
except KeyboardInterrupt:
|
|
251
|
+
print("\n\nInterrupted. Type 'exit' to quit or continue with a new prompt.")
|
|
252
|
+
continue
|
|
253
|
+
except Exception as e:
|
|
254
|
+
print(f"\nError: {str(e)}")
|
|
255
|
+
print("Please try again or type 'exit' to quit.")
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _print_help():
|
|
259
|
+
"""Print help information."""
|
|
260
|
+
print("\n" + "=" * 70)
|
|
261
|
+
print("HELP - Scientific Writer CLI")
|
|
262
|
+
print("=" * 70)
|
|
263
|
+
print("\nš What I Can Do:")
|
|
264
|
+
print(" ⢠Create complete scientific papers (LaTeX, Word, Markdown)")
|
|
265
|
+
print(" ⢠Literature reviews with citation management")
|
|
266
|
+
print(" ⢠Peer review feedback on drafts")
|
|
267
|
+
print(" ⢠Real-time research lookup using Perplexity Sonar Pro")
|
|
268
|
+
print(" ⢠Format citations in any style (APA, IEEE, Nature, etc.)")
|
|
269
|
+
print(" ⢠Document manipulation (docx, pdf, pptx, xlsx)")
|
|
270
|
+
print("\nš How I Work:")
|
|
271
|
+
print(" 1. You describe what you need")
|
|
272
|
+
print(" 2. I present a brief plan and start execution immediately")
|
|
273
|
+
print(" 3. I provide continuous progress updates")
|
|
274
|
+
print(" 4. All files organized in paper_outputs/ folder")
|
|
275
|
+
print("\nš” Example Requests:")
|
|
276
|
+
print(" 'Create a NeurIPS paper on transformer attention mechanisms'")
|
|
277
|
+
print(" 'Write a literature review on CRISPR gene editing'")
|
|
278
|
+
print(" 'Review my methods section in draft.docx'")
|
|
279
|
+
print(" 'Research recent advances in quantum computing 2024'")
|
|
280
|
+
print(" 'Create a Nature paper on climate change impacts'")
|
|
281
|
+
print(" 'Format 20 citations in IEEE style'")
|
|
282
|
+
print("\nš File Organization:")
|
|
283
|
+
print(" All work saved to: paper_outputs/<timestamp>_<description>/")
|
|
284
|
+
print(" - drafts/ - Working versions")
|
|
285
|
+
print(" - final/ - Completed documents")
|
|
286
|
+
print(" - references/ - Bibliography files")
|
|
287
|
+
print(" - figures/ - Images and charts")
|
|
288
|
+
print(" - data/ - Data files for the paper")
|
|
289
|
+
print(" - progress.md - Real-time progress log")
|
|
290
|
+
print(" - SUMMARY.md - Project summary and instructions")
|
|
291
|
+
print("\nš¦ Data Files:")
|
|
292
|
+
print(" Place files in the 'data/' folder at project root:")
|
|
293
|
+
print(" ⢠Manuscript files (.tex, .md, .docx, .pdf) ā copied to drafts/ for EDITING")
|
|
294
|
+
print(" ⢠Data files (csv, txt, json, etc.) ā copied to paper's data/")
|
|
295
|
+
print(" ⢠Images (png, jpg, svg, etc.) ā copied to paper's figures/")
|
|
296
|
+
print(" ⢠Files are used as context for the paper")
|
|
297
|
+
print(" ⢠Original files automatically deleted after copying")
|
|
298
|
+
print("\nšÆ Pro Tips:")
|
|
299
|
+
print(" ⢠Be specific about journal/conference (e.g., 'Nature', 'NeurIPS')")
|
|
300
|
+
print(" ⢠Mention citation style if you have a preference")
|
|
301
|
+
print(" ⢠I'll make smart defaults if you don't specify details")
|
|
302
|
+
print(" ⢠Check progress.md for detailed execution logs")
|
|
303
|
+
print("\nš Intelligent Paper Detection:")
|
|
304
|
+
print(" ⢠I automatically detect when you're referring to a previous paper")
|
|
305
|
+
print(" ⢠Continue working: 'continue the paper', 'update my paper', 'edit the poster'")
|
|
306
|
+
print(" ⢠Search/find: 'look for the X paper', 'find the paper about Y'")
|
|
307
|
+
print(" ⢠Or mention the paper topic: 'show me the acoustics paper'")
|
|
308
|
+
print(" ⢠Keywords like 'continue', 'update', 'edit', 'look for', 'find' trigger detection")
|
|
309
|
+
print(" ⢠I'll find the most relevant paper based on topic matching")
|
|
310
|
+
print(" ⢠Say 'new paper' or 'start fresh' to explicitly begin a new one")
|
|
311
|
+
print(" ⢠Current working paper is tracked throughout the session")
|
|
312
|
+
print("=" * 70)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def cli_main():
|
|
316
|
+
"""Entry point for the CLI script."""
|
|
317
|
+
try:
|
|
318
|
+
asyncio.run(main())
|
|
319
|
+
except KeyboardInterrupt:
|
|
320
|
+
print("\n\nExiting...")
|
|
321
|
+
sys.exit(0)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
if __name__ == "__main__":
|
|
325
|
+
cli_main()
|
|
326
|
+
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"""Core utilities for scientific writer."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import shutil
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional, List, Dict, Any
|
|
7
|
+
from dotenv import load_dotenv
|
|
8
|
+
|
|
9
|
+
# Load environment variables from .env file if it exists
|
|
10
|
+
load_dotenv()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def setup_claude_skills(package_dir: Path, work_dir: Path) -> None:
|
|
14
|
+
"""
|
|
15
|
+
Set up Claude skills and WRITER.md by copying .claude/ from package to working directory.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
package_dir: Package installation directory containing .claude/
|
|
19
|
+
work_dir: User's working directory where .claude/ should be copied
|
|
20
|
+
"""
|
|
21
|
+
source_claude = package_dir / ".claude"
|
|
22
|
+
dest_claude = work_dir / ".claude"
|
|
23
|
+
|
|
24
|
+
# Copy .claude directory (which includes skills/ and WRITER.md) if source exists and destination doesn't
|
|
25
|
+
if source_claude.exists() and not dest_claude.exists():
|
|
26
|
+
try:
|
|
27
|
+
shutil.copytree(source_claude, dest_claude)
|
|
28
|
+
print(f"ā Initialized Claude configuration in {dest_claude}")
|
|
29
|
+
print(f"ā Skills and system instructions (WRITER.md) ready")
|
|
30
|
+
except Exception as e:
|
|
31
|
+
print(f"Warning: Could not copy Claude configuration: {e}")
|
|
32
|
+
elif not source_claude.exists():
|
|
33
|
+
print(f"Warning: .claude directory not found in package: {source_claude}")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_api_key(api_key: Optional[str] = None) -> str:
|
|
37
|
+
"""
|
|
38
|
+
Get the Anthropic API key.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
api_key: Optional API key to use. If not provided, reads from environment.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
The API key.
|
|
45
|
+
|
|
46
|
+
Raises:
|
|
47
|
+
ValueError: If API key is not found.
|
|
48
|
+
"""
|
|
49
|
+
if api_key:
|
|
50
|
+
return api_key
|
|
51
|
+
|
|
52
|
+
env_key = os.getenv("ANTHROPIC_API_KEY")
|
|
53
|
+
if not env_key:
|
|
54
|
+
raise ValueError(
|
|
55
|
+
"ANTHROPIC_API_KEY not found. Either pass api_key parameter or set "
|
|
56
|
+
"ANTHROPIC_API_KEY environment variable."
|
|
57
|
+
)
|
|
58
|
+
return env_key
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def load_system_instructions(work_dir: Path) -> str:
|
|
62
|
+
"""
|
|
63
|
+
Load system instructions from .claude/WRITER.md in the working directory.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
work_dir: Working directory containing .claude/WRITER.md.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
System instructions string.
|
|
70
|
+
"""
|
|
71
|
+
instructions_file = work_dir / ".claude" / "WRITER.md"
|
|
72
|
+
|
|
73
|
+
if instructions_file.exists():
|
|
74
|
+
with open(instructions_file, 'r', encoding='utf-8') as f:
|
|
75
|
+
return f.read()
|
|
76
|
+
else:
|
|
77
|
+
# Fallback if WRITER.md doesn't exist
|
|
78
|
+
return (
|
|
79
|
+
"You are a scientific writing assistant. Follow best practices for "
|
|
80
|
+
"scientific communication and always present a plan before execution."
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def ensure_output_folder(cwd: Path, custom_dir: Optional[str] = None) -> Path:
|
|
85
|
+
"""
|
|
86
|
+
Ensure the paper_outputs folder exists.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
cwd: Current working directory (project root).
|
|
90
|
+
custom_dir: Optional custom output directory path.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Path to the output folder.
|
|
94
|
+
"""
|
|
95
|
+
if custom_dir:
|
|
96
|
+
output_folder = Path(custom_dir).resolve()
|
|
97
|
+
else:
|
|
98
|
+
output_folder = cwd / "paper_outputs"
|
|
99
|
+
|
|
100
|
+
output_folder.mkdir(exist_ok=True, parents=True)
|
|
101
|
+
return output_folder
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def get_image_extensions() -> set:
|
|
105
|
+
"""Return a set of common image file extensions."""
|
|
106
|
+
return {'.png', '.jpg', '.jpeg', '.gif', '.bmp', '.tiff', '.tif', '.svg', '.webp', '.ico'}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def get_manuscript_extensions() -> set:
|
|
110
|
+
"""Return a set of manuscript file extensions that should go to drafts/ folder."""
|
|
111
|
+
return {'.tex', '.md', '.docx', '.pdf'}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def get_data_files(cwd: Path, data_files: Optional[List[str]] = None) -> List[Path]:
|
|
115
|
+
"""
|
|
116
|
+
Get data files either from provided list or from data folder.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
cwd: Current working directory (project root).
|
|
120
|
+
data_files: Optional list of file paths. If not provided, reads from data/ folder.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
List of Path objects for data files.
|
|
124
|
+
"""
|
|
125
|
+
if data_files:
|
|
126
|
+
return [Path(f).resolve() for f in data_files]
|
|
127
|
+
|
|
128
|
+
data_folder = cwd / "data"
|
|
129
|
+
if not data_folder.exists():
|
|
130
|
+
return []
|
|
131
|
+
|
|
132
|
+
files = []
|
|
133
|
+
for file_path in data_folder.iterdir():
|
|
134
|
+
if file_path.is_file():
|
|
135
|
+
files.append(file_path)
|
|
136
|
+
|
|
137
|
+
return files
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def process_data_files(
|
|
141
|
+
cwd: Path,
|
|
142
|
+
data_files: List[Path],
|
|
143
|
+
paper_output_path: str,
|
|
144
|
+
delete_originals: bool = True
|
|
145
|
+
) -> Optional[Dict[str, Any]]:
|
|
146
|
+
"""
|
|
147
|
+
Process data files by copying them to the paper output folder.
|
|
148
|
+
Manuscript files (.tex, .md, .docx, .pdf) go to drafts/,
|
|
149
|
+
images go to figures/, other files go to data/.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
cwd: Current working directory (project root).
|
|
153
|
+
data_files: List of file paths to process.
|
|
154
|
+
paper_output_path: Path to the paper output directory.
|
|
155
|
+
delete_originals: Whether to delete original files after copying.
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
Dictionary with information about processed files, or None if no files.
|
|
159
|
+
"""
|
|
160
|
+
if not data_files:
|
|
161
|
+
return None
|
|
162
|
+
|
|
163
|
+
paper_output = Path(paper_output_path)
|
|
164
|
+
data_output = paper_output / "data"
|
|
165
|
+
figures_output = paper_output / "figures"
|
|
166
|
+
drafts_output = paper_output / "drafts"
|
|
167
|
+
|
|
168
|
+
# Ensure output directories exist
|
|
169
|
+
data_output.mkdir(parents=True, exist_ok=True)
|
|
170
|
+
figures_output.mkdir(parents=True, exist_ok=True)
|
|
171
|
+
drafts_output.mkdir(parents=True, exist_ok=True)
|
|
172
|
+
|
|
173
|
+
image_extensions = get_image_extensions()
|
|
174
|
+
manuscript_extensions = get_manuscript_extensions()
|
|
175
|
+
|
|
176
|
+
processed_info = {
|
|
177
|
+
'data_files': [],
|
|
178
|
+
'image_files': [],
|
|
179
|
+
'manuscript_files': [],
|
|
180
|
+
'all_files': []
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
for file_path in data_files:
|
|
184
|
+
file_ext = file_path.suffix.lower()
|
|
185
|
+
file_name = file_path.name
|
|
186
|
+
|
|
187
|
+
# Determine destination based on file type
|
|
188
|
+
# CRITICAL: Manuscript files go to drafts/ folder for editing workflow
|
|
189
|
+
if file_ext in manuscript_extensions:
|
|
190
|
+
destination = drafts_output / file_name
|
|
191
|
+
file_type = 'manuscript'
|
|
192
|
+
processed_info['manuscript_files'].append({
|
|
193
|
+
'name': file_name,
|
|
194
|
+
'path': str(destination),
|
|
195
|
+
'original': str(file_path),
|
|
196
|
+
'extension': file_ext
|
|
197
|
+
})
|
|
198
|
+
elif file_ext in image_extensions:
|
|
199
|
+
destination = figures_output / file_name
|
|
200
|
+
file_type = 'image'
|
|
201
|
+
processed_info['image_files'].append({
|
|
202
|
+
'name': file_name,
|
|
203
|
+
'path': str(destination),
|
|
204
|
+
'original': str(file_path)
|
|
205
|
+
})
|
|
206
|
+
else:
|
|
207
|
+
destination = data_output / file_name
|
|
208
|
+
file_type = 'data'
|
|
209
|
+
processed_info['data_files'].append({
|
|
210
|
+
'name': file_name,
|
|
211
|
+
'path': str(destination),
|
|
212
|
+
'original': str(file_path)
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
# Copy the file
|
|
216
|
+
try:
|
|
217
|
+
shutil.copy2(file_path, destination)
|
|
218
|
+
processed_info['all_files'].append({
|
|
219
|
+
'name': file_name,
|
|
220
|
+
'type': file_type,
|
|
221
|
+
'destination': str(destination)
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
# Delete the original file after successful copy if requested
|
|
225
|
+
if delete_originals:
|
|
226
|
+
file_path.unlink()
|
|
227
|
+
|
|
228
|
+
except Exception as e:
|
|
229
|
+
print(f"Warning: Could not process {file_name}: {str(e)}")
|
|
230
|
+
|
|
231
|
+
return processed_info
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def create_data_context_message(processed_info: Optional[Dict[str, Any]]) -> str:
|
|
235
|
+
"""
|
|
236
|
+
Create a context message about available data files.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
processed_info: Dictionary with processed file information.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
Context message string.
|
|
243
|
+
"""
|
|
244
|
+
if not processed_info or not processed_info['all_files']:
|
|
245
|
+
return ""
|
|
246
|
+
|
|
247
|
+
context_parts = ["\n[DATA FILES AVAILABLE]"]
|
|
248
|
+
|
|
249
|
+
# CRITICAL: If manuscript files are present, this is an EDITING task
|
|
250
|
+
if processed_info.get('manuscript_files'):
|
|
251
|
+
context_parts.append("\nā ļø EDITING MODE - Manuscript files detected!")
|
|
252
|
+
context_parts.append("\nManuscript files (in drafts/ folder for editing):")
|
|
253
|
+
for file_info in processed_info['manuscript_files']:
|
|
254
|
+
context_parts.append(f" - {file_info['name']} ({file_info['extension']}): {file_info['path']}")
|
|
255
|
+
context_parts.append("\nš§ TASK: This is an EDITING task, not creating from scratch.")
|
|
256
|
+
context_parts.append(" ā Read the existing manuscript from drafts/")
|
|
257
|
+
context_parts.append(" ā Apply the requested changes/improvements")
|
|
258
|
+
context_parts.append(" ā Create new version following version numbering protocol")
|
|
259
|
+
context_parts.append(" ā Document changes in revision_notes.md")
|
|
260
|
+
|
|
261
|
+
if processed_info.get('data_files'):
|
|
262
|
+
context_parts.append("\nData files (in data/ folder):")
|
|
263
|
+
for file_info in processed_info['data_files']:
|
|
264
|
+
context_parts.append(f" - {file_info['name']}: {file_info['path']}")
|
|
265
|
+
|
|
266
|
+
if processed_info.get('image_files'):
|
|
267
|
+
context_parts.append("\nImage files (in figures/ folder):")
|
|
268
|
+
for file_info in processed_info['image_files']:
|
|
269
|
+
context_parts.append(f" - {file_info['name']}: {file_info['path']}")
|
|
270
|
+
context_parts.append("\nNote: These images can be referenced as figures in the paper.")
|
|
271
|
+
|
|
272
|
+
context_parts.append("[END DATA FILES]\n")
|
|
273
|
+
|
|
274
|
+
return "\n".join(context_parts)
|
|
275
|
+
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Data models for scientific writer API responses."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field, asdict
|
|
4
|
+
from typing import Optional, List, Dict, Any
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class ProgressUpdate:
|
|
10
|
+
"""Progress update during paper generation."""
|
|
11
|
+
type: str = "progress"
|
|
12
|
+
timestamp: str = field(default_factory=lambda: datetime.utcnow().isoformat() + "Z")
|
|
13
|
+
message: str = ""
|
|
14
|
+
stage: str = "initialization" # initialization|research|writing|compilation|complete
|
|
15
|
+
percentage: int = 0
|
|
16
|
+
|
|
17
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
18
|
+
"""Convert to dictionary for JSON serialization."""
|
|
19
|
+
return asdict(self)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class PaperMetadata:
|
|
24
|
+
"""Metadata about the generated paper."""
|
|
25
|
+
title: Optional[str] = None
|
|
26
|
+
created_at: str = field(default_factory=lambda: datetime.utcnow().isoformat() + "Z")
|
|
27
|
+
topic: str = ""
|
|
28
|
+
word_count: Optional[int] = None
|
|
29
|
+
|
|
30
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
31
|
+
"""Convert to dictionary for JSON serialization."""
|
|
32
|
+
return asdict(self)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class PaperFiles:
|
|
37
|
+
"""File paths for all generated paper artifacts."""
|
|
38
|
+
pdf_final: Optional[str] = None
|
|
39
|
+
tex_final: Optional[str] = None
|
|
40
|
+
pdf_drafts: List[str] = field(default_factory=list)
|
|
41
|
+
tex_drafts: List[str] = field(default_factory=list)
|
|
42
|
+
bibliography: Optional[str] = None
|
|
43
|
+
figures: List[str] = field(default_factory=list)
|
|
44
|
+
data: List[str] = field(default_factory=list)
|
|
45
|
+
progress_log: Optional[str] = None
|
|
46
|
+
summary: Optional[str] = None
|
|
47
|
+
|
|
48
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
49
|
+
"""Convert to dictionary for JSON serialization."""
|
|
50
|
+
return asdict(self)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class PaperResult:
|
|
55
|
+
"""Final result containing all information about the generated paper."""
|
|
56
|
+
type: str = "result"
|
|
57
|
+
status: str = "success" # success|partial|failed
|
|
58
|
+
paper_directory: str = ""
|
|
59
|
+
paper_name: str = ""
|
|
60
|
+
metadata: PaperMetadata = field(default_factory=PaperMetadata)
|
|
61
|
+
files: PaperFiles = field(default_factory=PaperFiles)
|
|
62
|
+
citations: Dict[str, Any] = field(default_factory=dict)
|
|
63
|
+
figures_count: int = 0
|
|
64
|
+
compilation_success: bool = False
|
|
65
|
+
errors: List[str] = field(default_factory=list)
|
|
66
|
+
|
|
67
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
68
|
+
"""Convert to dictionary for JSON serialization."""
|
|
69
|
+
result = asdict(self)
|
|
70
|
+
# Ensure nested objects are also dictionaries
|
|
71
|
+
if isinstance(self.metadata, PaperMetadata):
|
|
72
|
+
result['metadata'] = self.metadata.to_dict()
|
|
73
|
+
if isinstance(self.files, PaperFiles):
|
|
74
|
+
result['files'] = self.files.to_dict()
|
|
75
|
+
return result
|
|
76
|
+
|