docagent-cli 0.0.35__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.
- docagent_cli/__init__.py +36 -0
- docagent_cli/__main__.py +6 -0
- docagent_cli/_ask_user_types.py +90 -0
- docagent_cli/_cli_context.py +27 -0
- docagent_cli/_debug.py +52 -0
- docagent_cli/_env_vars.py +56 -0
- docagent_cli/_server_config.py +352 -0
- docagent_cli/_session_stats.py +114 -0
- docagent_cli/_testing_models.py +144 -0
- docagent_cli/_version.py +17 -0
- docagent_cli/agent.py +1193 -0
- docagent_cli/app.py +4979 -0
- docagent_cli/app.tcss +283 -0
- docagent_cli/ask_user.py +301 -0
- docagent_cli/built_in_skills/__init__.py +5 -0
- docagent_cli/built_in_skills/doc-coauthoring/SKILL.md +375 -0
- docagent_cli/built_in_skills/docx/LICENSE.txt +30 -0
- docagent_cli/built_in_skills/docx/SKILL.md +590 -0
- docagent_cli/built_in_skills/docx/scripts/__init__.py +1 -0
- docagent_cli/built_in_skills/docx/scripts/accept_changes.py +135 -0
- docagent_cli/built_in_skills/docx/scripts/comment.py +318 -0
- docagent_cli/built_in_skills/docx/scripts/office/helpers/__init__.py +0 -0
- docagent_cli/built_in_skills/docx/scripts/office/helpers/merge_runs.py +199 -0
- docagent_cli/built_in_skills/docx/scripts/office/helpers/simplify_redlines.py +197 -0
- docagent_cli/built_in_skills/docx/scripts/office/pack.py +159 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/mce/mc.xsd +75 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
- docagent_cli/built_in_skills/docx/scripts/office/soffice.py +183 -0
- docagent_cli/built_in_skills/docx/scripts/office/unpack.py +132 -0
- docagent_cli/built_in_skills/docx/scripts/office/validate.py +111 -0
- docagent_cli/built_in_skills/docx/scripts/office/validators/__init__.py +15 -0
- docagent_cli/built_in_skills/docx/scripts/office/validators/base.py +847 -0
- docagent_cli/built_in_skills/docx/scripts/office/validators/docx.py +446 -0
- docagent_cli/built_in_skills/docx/scripts/office/validators/pptx.py +275 -0
- docagent_cli/built_in_skills/docx/scripts/office/validators/redlining.py +247 -0
- docagent_cli/built_in_skills/docx/scripts/templates/comments.xml +3 -0
- docagent_cli/built_in_skills/docx/scripts/templates/commentsExtended.xml +3 -0
- docagent_cli/built_in_skills/docx/scripts/templates/commentsExtensible.xml +3 -0
- docagent_cli/built_in_skills/docx/scripts/templates/commentsIds.xml +3 -0
- docagent_cli/built_in_skills/docx/scripts/templates/people.xml +3 -0
- docagent_cli/built_in_skills/pdf/LICENSE.txt +30 -0
- docagent_cli/built_in_skills/pdf/SKILL.md +314 -0
- docagent_cli/built_in_skills/pdf/forms.md +294 -0
- docagent_cli/built_in_skills/pdf/reference.md +612 -0
- docagent_cli/built_in_skills/pdf/scripts/check_bounding_boxes.py +65 -0
- docagent_cli/built_in_skills/pdf/scripts/check_fillable_fields.py +11 -0
- docagent_cli/built_in_skills/pdf/scripts/convert_pdf_to_images.py +33 -0
- docagent_cli/built_in_skills/pdf/scripts/create_validation_image.py +37 -0
- docagent_cli/built_in_skills/pdf/scripts/extract_form_field_info.py +122 -0
- docagent_cli/built_in_skills/pdf/scripts/extract_form_structure.py +115 -0
- docagent_cli/built_in_skills/pdf/scripts/fill_fillable_fields.py +98 -0
- docagent_cli/built_in_skills/pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
- docagent_cli/built_in_skills/pptx/LICENSE.txt +30 -0
- docagent_cli/built_in_skills/pptx/SKILL.md +232 -0
- docagent_cli/built_in_skills/pptx/editing.md +205 -0
- docagent_cli/built_in_skills/pptx/pptxgenjs.md +420 -0
- docagent_cli/built_in_skills/pptx/scripts/__init__.py +0 -0
- docagent_cli/built_in_skills/pptx/scripts/add_slide.py +195 -0
- docagent_cli/built_in_skills/pptx/scripts/clean.py +286 -0
- docagent_cli/built_in_skills/pptx/scripts/office/helpers/__init__.py +0 -0
- docagent_cli/built_in_skills/pptx/scripts/office/helpers/merge_runs.py +199 -0
- docagent_cli/built_in_skills/pptx/scripts/office/helpers/simplify_redlines.py +197 -0
- docagent_cli/built_in_skills/pptx/scripts/office/pack.py +159 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/mce/mc.xsd +75 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
- docagent_cli/built_in_skills/pptx/scripts/office/soffice.py +183 -0
- docagent_cli/built_in_skills/pptx/scripts/office/unpack.py +132 -0
- docagent_cli/built_in_skills/pptx/scripts/office/validate.py +111 -0
- docagent_cli/built_in_skills/pptx/scripts/office/validators/__init__.py +15 -0
- docagent_cli/built_in_skills/pptx/scripts/office/validators/base.py +847 -0
- docagent_cli/built_in_skills/pptx/scripts/office/validators/docx.py +446 -0
- docagent_cli/built_in_skills/pptx/scripts/office/validators/pptx.py +275 -0
- docagent_cli/built_in_skills/pptx/scripts/office/validators/redlining.py +247 -0
- docagent_cli/built_in_skills/pptx/scripts/thumbnail.py +289 -0
- docagent_cli/built_in_skills/remember/SKILL.md +118 -0
- docagent_cli/built_in_skills/skill-creator/LICENSE.txt +202 -0
- docagent_cli/built_in_skills/skill-creator/SKILL.md +485 -0
- docagent_cli/built_in_skills/skill-creator/agents/analyzer.md +274 -0
- docagent_cli/built_in_skills/skill-creator/agents/comparator.md +202 -0
- docagent_cli/built_in_skills/skill-creator/agents/grader.md +223 -0
- docagent_cli/built_in_skills/skill-creator/assets/eval_review.html +146 -0
- docagent_cli/built_in_skills/skill-creator/eval-viewer/generate_review.py +471 -0
- docagent_cli/built_in_skills/skill-creator/eval-viewer/viewer.html +1325 -0
- docagent_cli/built_in_skills/skill-creator/references/schemas.md +430 -0
- docagent_cli/built_in_skills/skill-creator/scripts/__init__.py +0 -0
- docagent_cli/built_in_skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- docagent_cli/built_in_skills/skill-creator/scripts/generate_report.py +326 -0
- docagent_cli/built_in_skills/skill-creator/scripts/improve_description.py +247 -0
- docagent_cli/built_in_skills/skill-creator/scripts/package_skill.py +136 -0
- docagent_cli/built_in_skills/skill-creator/scripts/quick_validate.py +103 -0
- docagent_cli/built_in_skills/skill-creator/scripts/run_eval.py +310 -0
- docagent_cli/built_in_skills/skill-creator/scripts/run_loop.py +328 -0
- docagent_cli/built_in_skills/skill-creator/scripts/utils.py +47 -0
- docagent_cli/built_in_skills/theme-factory/LICENSE.txt +202 -0
- docagent_cli/built_in_skills/theme-factory/SKILL.md +59 -0
- docagent_cli/built_in_skills/theme-factory/theme-showcase.pdf +0 -0
- docagent_cli/built_in_skills/theme-factory/themes/arctic-frost.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/botanical-garden.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/desert-rose.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/forest-canopy.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/golden-hour.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/midnight-galaxy.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/modern-minimalist.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/ocean-depths.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/sunset-boulevard.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/tech-innovation.md +19 -0
- docagent_cli/built_in_skills/xlsx/LICENSE.txt +30 -0
- docagent_cli/built_in_skills/xlsx/SKILL.md +292 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/helpers/__init__.py +0 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/helpers/merge_runs.py +199 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/helpers/simplify_redlines.py +197 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/pack.py +159 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/mce/mc.xsd +75 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/soffice.py +183 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/unpack.py +132 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/validate.py +111 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/validators/__init__.py +15 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/validators/base.py +847 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/validators/docx.py +446 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/validators/pptx.py +275 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/validators/redlining.py +247 -0
- docagent_cli/built_in_skills/xlsx/scripts/recalc.py +184 -0
- docagent_cli/clipboard.py +128 -0
- docagent_cli/command_registry.py +284 -0
- docagent_cli/config.py +2418 -0
- docagent_cli/configurable_model.py +162 -0
- docagent_cli/default_agent_prompt.md +12 -0
- docagent_cli/editor.py +142 -0
- docagent_cli/file_ops.py +473 -0
- docagent_cli/formatting.py +28 -0
- docagent_cli/hooks.py +206 -0
- docagent_cli/input.py +787 -0
- docagent_cli/integrations/__init__.py +1 -0
- docagent_cli/integrations/sandbox_factory.py +873 -0
- docagent_cli/integrations/sandbox_provider.py +71 -0
- docagent_cli/local_context.py +718 -0
- docagent_cli/main.py +1641 -0
- docagent_cli/mcp_tools.py +707 -0
- docagent_cli/mcp_trust.py +168 -0
- docagent_cli/media_utils.py +478 -0
- docagent_cli/model_config.py +1620 -0
- docagent_cli/non_interactive.py +948 -0
- docagent_cli/offload.py +371 -0
- docagent_cli/output.py +69 -0
- docagent_cli/project_utils.py +188 -0
- docagent_cli/py.typed +0 -0
- docagent_cli/remote_client.py +515 -0
- docagent_cli/server.py +520 -0
- docagent_cli/server_graph.py +196 -0
- docagent_cli/server_manager.py +365 -0
- docagent_cli/sessions.py +1262 -0
- docagent_cli/skills/__init__.py +18 -0
- docagent_cli/skills/commands.py +1090 -0
- docagent_cli/skills/load.py +192 -0
- docagent_cli/subagents.py +173 -0
- docagent_cli/system_prompt.md +247 -0
- docagent_cli/textual_adapter.py +1352 -0
- docagent_cli/theme.py +842 -0
- docagent_cli/token_state.py +31 -0
- docagent_cli/tool_display.py +298 -0
- docagent_cli/tools.py +236 -0
- docagent_cli/ui.py +420 -0
- docagent_cli/unicode_security.py +516 -0
- docagent_cli/update_check.py +454 -0
- docagent_cli/widgets/__init__.py +9 -0
- docagent_cli/widgets/_links.py +63 -0
- docagent_cli/widgets/approval.py +442 -0
- docagent_cli/widgets/ask_user.py +398 -0
- docagent_cli/widgets/autocomplete.py +691 -0
- docagent_cli/widgets/chat_input.py +1827 -0
- docagent_cli/widgets/diff.py +248 -0
- docagent_cli/widgets/history.py +188 -0
- docagent_cli/widgets/loading.py +177 -0
- docagent_cli/widgets/mcp_viewer.py +362 -0
- docagent_cli/widgets/message_store.py +675 -0
- docagent_cli/widgets/messages.py +1751 -0
- docagent_cli/widgets/model_selector.py +964 -0
- docagent_cli/widgets/status.py +372 -0
- docagent_cli/widgets/theme_selector.py +164 -0
- docagent_cli/widgets/thread_selector.py +1905 -0
- docagent_cli/widgets/tool_renderers.py +148 -0
- docagent_cli/widgets/tool_widgets.py +274 -0
- docagent_cli/widgets/welcome.py +339 -0
- docagent_cli-0.0.35.data/data/docagent_cli/default_agent_prompt.md +12 -0
- docagent_cli-0.0.35.dist-info/METADATA +200 -0
- docagent_cli-0.0.35.dist-info/RECORD +300 -0
- docagent_cli-0.0.35.dist-info/WHEEL +4 -0
- docagent_cli-0.0.35.dist-info/entry_points.txt +3 -0
docagent_cli/offload.py
ADDED
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
"""Business logic for the /offload command.
|
|
2
|
+
|
|
3
|
+
Extracts the core offload workflow from the UI layer so it can be
|
|
4
|
+
tested independently of the Textual app.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from datetime import UTC, datetime
|
|
12
|
+
from typing import TYPE_CHECKING, Any
|
|
13
|
+
|
|
14
|
+
from langchain_core.messages import get_buffer_string
|
|
15
|
+
from langchain_core.messages.utils import count_tokens_approximately
|
|
16
|
+
|
|
17
|
+
from docagent_cli.config import create_model
|
|
18
|
+
from docagent_cli.textual_adapter import format_token_count
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from deepagents.backends.protocol import BackendProtocol
|
|
22
|
+
from deepagents.middleware.summarization import (
|
|
23
|
+
SummarizationEvent,
|
|
24
|
+
SummarizationMiddleware,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
logger = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
# Result types
|
|
32
|
+
# ---------------------------------------------------------------------------
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass(frozen=True)
|
|
36
|
+
class OffloadResult:
|
|
37
|
+
"""Successful offload result."""
|
|
38
|
+
|
|
39
|
+
new_event: SummarizationEvent
|
|
40
|
+
"""The summarization event to write into agent state."""
|
|
41
|
+
|
|
42
|
+
messages_offloaded: int
|
|
43
|
+
"""Number of older messages that were offloaded."""
|
|
44
|
+
|
|
45
|
+
messages_kept: int
|
|
46
|
+
"""Number of recent messages retained in context."""
|
|
47
|
+
|
|
48
|
+
tokens_before: int
|
|
49
|
+
"""Approximate token count of the conversation before offloading."""
|
|
50
|
+
|
|
51
|
+
tokens_after: int
|
|
52
|
+
"""Approximate token count of the conversation after offloading."""
|
|
53
|
+
|
|
54
|
+
pct_decrease: int
|
|
55
|
+
"""Percentage decrease in token usage."""
|
|
56
|
+
|
|
57
|
+
offload_warning: str | None
|
|
58
|
+
"""Non-`None` when the backend write failed (non-fatal)."""
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass(frozen=True)
|
|
62
|
+
class OffloadThresholdNotMet:
|
|
63
|
+
"""Offload was a no-op — conversation is within the retention budget."""
|
|
64
|
+
|
|
65
|
+
conversation_tokens: int
|
|
66
|
+
"""Approximate token count of the conversation messages alone."""
|
|
67
|
+
|
|
68
|
+
total_context_tokens: int
|
|
69
|
+
"""Total context token count including system overhead, or `0` when no
|
|
70
|
+
token tracker is available."""
|
|
71
|
+
|
|
72
|
+
context_limit: int | None
|
|
73
|
+
"""Model context window limit, if available."""
|
|
74
|
+
|
|
75
|
+
budget_str: str
|
|
76
|
+
"""Human-readable retention budget (e.g. "20.0K tokens")."""
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class OffloadModelError(Exception):
|
|
80
|
+
"""Raised when the model cannot be created for offloading."""
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# ---------------------------------------------------------------------------
|
|
84
|
+
# Helpers
|
|
85
|
+
# ---------------------------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def format_offload_limit(
|
|
89
|
+
keep: tuple[str, int | float], context_limit: int | None
|
|
90
|
+
) -> str:
|
|
91
|
+
"""Format offload retention settings into a human-readable limit string.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
keep: Retention policy tuple `(type, value)` from summarization
|
|
95
|
+
defaults, where `type` is one of `"messages"`, `"tokens"`, or
|
|
96
|
+
`"fraction"`.
|
|
97
|
+
context_limit: Model context limit when available.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
A short display string describing the offload retention limit.
|
|
101
|
+
"""
|
|
102
|
+
keep_type, keep_value = keep
|
|
103
|
+
|
|
104
|
+
if keep_type == "messages":
|
|
105
|
+
count = int(keep_value)
|
|
106
|
+
noun = "message" if count == 1 else "messages"
|
|
107
|
+
return f"last {count} {noun}"
|
|
108
|
+
|
|
109
|
+
if keep_type == "tokens":
|
|
110
|
+
return f"{format_token_count(int(keep_value))} tokens"
|
|
111
|
+
|
|
112
|
+
if keep_type == "fraction":
|
|
113
|
+
percent = float(keep_value) * 100
|
|
114
|
+
if context_limit is not None:
|
|
115
|
+
token_limit = max(1, int(context_limit * float(keep_value)))
|
|
116
|
+
return f"{format_token_count(token_limit)} tokens"
|
|
117
|
+
return f"{percent:.0f}% of context window"
|
|
118
|
+
|
|
119
|
+
return "current retention threshold"
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
async def offload_messages_to_backend(
|
|
123
|
+
messages: list[Any],
|
|
124
|
+
middleware: SummarizationMiddleware,
|
|
125
|
+
*,
|
|
126
|
+
thread_id: str,
|
|
127
|
+
backend: BackendProtocol,
|
|
128
|
+
) -> str | None:
|
|
129
|
+
"""Write messages to backend storage before offloading.
|
|
130
|
+
|
|
131
|
+
Appends messages as a timestamped markdown section to the conversation
|
|
132
|
+
history file, matching the `SummarizationMiddleware` offload pattern.
|
|
133
|
+
|
|
134
|
+
Filters out prior summary messages using the middleware's
|
|
135
|
+
`_filter_summary_messages` to avoid storing summaries-of-summaries.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
messages: Messages to offload.
|
|
139
|
+
middleware: `SummarizationMiddleware` instance for filtering.
|
|
140
|
+
thread_id: Thread identifier used to derive the storage path.
|
|
141
|
+
backend: Backend to persist conversation history to.
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
File path where history was stored, `""` (empty string) if there were no
|
|
145
|
+
non-summary messages to offload (not an error), or `None` if the
|
|
146
|
+
write failed.
|
|
147
|
+
"""
|
|
148
|
+
path = f"/conversation_history/{thread_id}.md"
|
|
149
|
+
|
|
150
|
+
# Exclude prior summaries so the offloaded history contains only
|
|
151
|
+
# original messages
|
|
152
|
+
filtered = middleware._filter_summary_messages(messages)
|
|
153
|
+
if not filtered:
|
|
154
|
+
return ""
|
|
155
|
+
|
|
156
|
+
timestamp = datetime.now(UTC).isoformat()
|
|
157
|
+
buf = get_buffer_string(filtered)
|
|
158
|
+
new_section = f"## Offloaded at {timestamp}\n\n{buf}\n\n"
|
|
159
|
+
|
|
160
|
+
existing_content = ""
|
|
161
|
+
try:
|
|
162
|
+
responses = await backend.adownload_files([path])
|
|
163
|
+
resp = responses[0] if responses else None
|
|
164
|
+
if resp and resp.content is not None and resp.error is None:
|
|
165
|
+
existing_content = resp.content.decode("utf-8")
|
|
166
|
+
except Exception as exc: # abort write on read failure
|
|
167
|
+
logger.warning(
|
|
168
|
+
"Failed to read existing history at %s; aborting offload to "
|
|
169
|
+
"avoid overwriting prior history: %s",
|
|
170
|
+
path,
|
|
171
|
+
exc,
|
|
172
|
+
exc_info=True,
|
|
173
|
+
)
|
|
174
|
+
return None
|
|
175
|
+
|
|
176
|
+
combined = existing_content + new_section
|
|
177
|
+
|
|
178
|
+
try:
|
|
179
|
+
result = (
|
|
180
|
+
await backend.aedit(path, existing_content, combined)
|
|
181
|
+
if existing_content
|
|
182
|
+
else await backend.awrite(path, combined)
|
|
183
|
+
)
|
|
184
|
+
if result is None or result.error:
|
|
185
|
+
error_detail = result.error if result else "backend returned None"
|
|
186
|
+
logger.warning(
|
|
187
|
+
"Failed to offload conversation history to %s: %s",
|
|
188
|
+
path,
|
|
189
|
+
error_detail,
|
|
190
|
+
)
|
|
191
|
+
return None
|
|
192
|
+
except Exception as exc: # defensive: surface write failures gracefully
|
|
193
|
+
logger.warning(
|
|
194
|
+
"Exception offloading conversation history to %s: %s",
|
|
195
|
+
path,
|
|
196
|
+
exc,
|
|
197
|
+
exc_info=True,
|
|
198
|
+
)
|
|
199
|
+
return None
|
|
200
|
+
|
|
201
|
+
logger.debug("Offloaded %d messages to %s", len(filtered), path)
|
|
202
|
+
return path
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
# ---------------------------------------------------------------------------
|
|
206
|
+
# Core offload workflow
|
|
207
|
+
# ---------------------------------------------------------------------------
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
async def perform_offload(
|
|
211
|
+
*,
|
|
212
|
+
messages: list[Any],
|
|
213
|
+
prior_event: SummarizationEvent | None,
|
|
214
|
+
thread_id: str,
|
|
215
|
+
model_spec: str,
|
|
216
|
+
profile_overrides: dict[str, Any] | None,
|
|
217
|
+
context_limit: int | None,
|
|
218
|
+
total_context_tokens: int,
|
|
219
|
+
backend: BackendProtocol | None,
|
|
220
|
+
) -> OffloadResult | OffloadThresholdNotMet:
|
|
221
|
+
"""Execute the offload workflow: summarize old messages and free context.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
messages: Current conversation messages from agent state.
|
|
225
|
+
prior_event: Existing `_summarization_event` if any.
|
|
226
|
+
thread_id: Thread identifier for backend storage.
|
|
227
|
+
model_spec: Model specification string (e.g. "openai:gpt-4").
|
|
228
|
+
profile_overrides: Optional profile overrides from CLI flags.
|
|
229
|
+
context_limit: Model context limit from settings.
|
|
230
|
+
total_context_tokens: Current total context token count, or `0` when
|
|
231
|
+
no token tracker is available.
|
|
232
|
+
backend: Backend for persisting offloaded history.
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
`OffloadResult` on success, `OffloadThresholdNotMet` when the
|
|
236
|
+
conversation is within the retention budget.
|
|
237
|
+
|
|
238
|
+
Raises:
|
|
239
|
+
OffloadModelError: If the model cannot be created.
|
|
240
|
+
"""
|
|
241
|
+
from deepagents.middleware.summarization import (
|
|
242
|
+
SummarizationMiddleware,
|
|
243
|
+
compute_summarization_defaults,
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
try:
|
|
247
|
+
result = create_model(model_spec, profile_overrides=profile_overrides)
|
|
248
|
+
model = result.model
|
|
249
|
+
except Exception as exc:
|
|
250
|
+
msg = f"Offload requires a working model configuration: {exc}"
|
|
251
|
+
raise OffloadModelError(msg) from exc
|
|
252
|
+
|
|
253
|
+
# Patch context limit into model profile when it differs from the native
|
|
254
|
+
# value (e.g. set via --profile-override or runtime config).
|
|
255
|
+
if context_limit is not None:
|
|
256
|
+
profile = getattr(model, "profile", None)
|
|
257
|
+
native = profile.get("max_input_tokens") if isinstance(profile, dict) else None
|
|
258
|
+
if native != context_limit:
|
|
259
|
+
merged = (
|
|
260
|
+
{**profile, "max_input_tokens": context_limit}
|
|
261
|
+
if isinstance(profile, dict)
|
|
262
|
+
else {"max_input_tokens": context_limit}
|
|
263
|
+
)
|
|
264
|
+
try:
|
|
265
|
+
model.profile = merged # type: ignore[union-attr]
|
|
266
|
+
except (AttributeError, TypeError, ValueError):
|
|
267
|
+
logger.warning(
|
|
268
|
+
"Could not patch context limit (%d) into model profile; "
|
|
269
|
+
"offload budget will use the model's native context window",
|
|
270
|
+
context_limit,
|
|
271
|
+
exc_info=True,
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
defaults = compute_summarization_defaults(model)
|
|
275
|
+
offload_backend = backend
|
|
276
|
+
if offload_backend is None:
|
|
277
|
+
from deepagents.backends.filesystem import FilesystemBackend
|
|
278
|
+
|
|
279
|
+
offload_backend = FilesystemBackend()
|
|
280
|
+
logger.info("Using local FilesystemBackend for offload")
|
|
281
|
+
|
|
282
|
+
middleware = SummarizationMiddleware(
|
|
283
|
+
model=model,
|
|
284
|
+
backend=offload_backend,
|
|
285
|
+
keep=defaults["keep"],
|
|
286
|
+
trim_tokens_to_summarize=None,
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
# Rebuild the message list the model would see, accounting for
|
|
290
|
+
# any prior offload
|
|
291
|
+
effective = middleware._apply_event_to_messages(messages, prior_event)
|
|
292
|
+
cutoff = middleware._determine_cutoff_index(effective)
|
|
293
|
+
budget_str = format_offload_limit(defaults["keep"], context_limit)
|
|
294
|
+
|
|
295
|
+
if cutoff == 0:
|
|
296
|
+
return OffloadThresholdNotMet(
|
|
297
|
+
conversation_tokens=count_tokens_approximately(effective),
|
|
298
|
+
total_context_tokens=total_context_tokens,
|
|
299
|
+
context_limit=context_limit,
|
|
300
|
+
budget_str=budget_str,
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
to_summarize, to_keep = middleware._partition_messages(effective, cutoff)
|
|
304
|
+
|
|
305
|
+
tokens_summarized = count_tokens_approximately(to_summarize)
|
|
306
|
+
tokens_kept = count_tokens_approximately(to_keep)
|
|
307
|
+
tokens_before = tokens_summarized + tokens_kept
|
|
308
|
+
|
|
309
|
+
# Generate summary first so no side effects occur if the LLM fails
|
|
310
|
+
summary = await middleware._acreate_summary(to_summarize)
|
|
311
|
+
|
|
312
|
+
backend_path = await offload_messages_to_backend(
|
|
313
|
+
to_summarize,
|
|
314
|
+
middleware,
|
|
315
|
+
thread_id=thread_id,
|
|
316
|
+
backend=offload_backend,
|
|
317
|
+
)
|
|
318
|
+
offload_warning: str | None = None
|
|
319
|
+
if backend_path is None:
|
|
320
|
+
offload_warning = (
|
|
321
|
+
"Warning: conversation history could not be saved to "
|
|
322
|
+
"storage. Older messages will not be recoverable. "
|
|
323
|
+
"Check logs for details."
|
|
324
|
+
)
|
|
325
|
+
logger.error(
|
|
326
|
+
"Backend write failed for thread %s; offloading will proceed "
|
|
327
|
+
"but messages are not recoverable",
|
|
328
|
+
thread_id,
|
|
329
|
+
)
|
|
330
|
+
file_path = backend_path or None
|
|
331
|
+
|
|
332
|
+
summary_msg = middleware._build_new_messages_with_path(summary, file_path)[0]
|
|
333
|
+
|
|
334
|
+
# Append token savings note so the model is aware of how much context
|
|
335
|
+
# was reclaimed.
|
|
336
|
+
tokens_summary = count_tokens_approximately([summary_msg])
|
|
337
|
+
tokens_after = tokens_summary + tokens_kept
|
|
338
|
+
pct = (
|
|
339
|
+
round((tokens_before - tokens_after) / tokens_before * 100)
|
|
340
|
+
if tokens_before > 0
|
|
341
|
+
else 0
|
|
342
|
+
)
|
|
343
|
+
summarized_before = format_token_count(tokens_summarized)
|
|
344
|
+
summarized_after = format_token_count(tokens_summary)
|
|
345
|
+
savings_note = (
|
|
346
|
+
f"\n\n{len(to_summarize)} messages were offloaded "
|
|
347
|
+
f"({summarized_before} \u2192 {summarized_after} tokens). "
|
|
348
|
+
f"Total context: {format_token_count(tokens_before)} \u2192 "
|
|
349
|
+
f"{format_token_count(tokens_after)} tokens "
|
|
350
|
+
f"({pct}% decrease), "
|
|
351
|
+
f"{len(to_keep)} messages unchanged."
|
|
352
|
+
)
|
|
353
|
+
summary_msg.content += savings_note
|
|
354
|
+
|
|
355
|
+
state_cutoff = middleware._compute_state_cutoff(prior_event, cutoff)
|
|
356
|
+
|
|
357
|
+
new_event: SummarizationEvent = {
|
|
358
|
+
"cutoff_index": state_cutoff,
|
|
359
|
+
"summary_message": summary_msg, # ty: ignore[invalid-argument-type]
|
|
360
|
+
"file_path": file_path,
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return OffloadResult(
|
|
364
|
+
new_event=new_event,
|
|
365
|
+
messages_offloaded=len(to_summarize),
|
|
366
|
+
messages_kept=len(to_keep),
|
|
367
|
+
tokens_before=tokens_before,
|
|
368
|
+
tokens_after=tokens_after,
|
|
369
|
+
pct_decrease=pct,
|
|
370
|
+
offload_warning=offload_warning,
|
|
371
|
+
)
|
docagent_cli/output.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Machine-readable JSON output helpers for CLI subcommands.
|
|
2
|
+
|
|
3
|
+
This module deliberately stays stdlib-only so it can be imported from CLI
|
|
4
|
+
startup paths without pulling in unnecessary dependency trees.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
import json
|
|
11
|
+
import sys
|
|
12
|
+
from typing import Literal
|
|
13
|
+
|
|
14
|
+
OutputFormat = Literal["text", "json"]
|
|
15
|
+
"""Accepted internal output modes for CLI subcommands."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def add_json_output_arg(
|
|
19
|
+
parser: argparse.ArgumentParser, *, default: OutputFormat | None = None
|
|
20
|
+
) -> None:
|
|
21
|
+
"""Add a `--json` flag to an argparse parser.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
parser: Parser to update.
|
|
25
|
+
default: Default output format for this parser.
|
|
26
|
+
|
|
27
|
+
Pass `None` for subparsers so parent parser values are preserved.
|
|
28
|
+
"""
|
|
29
|
+
if default is None:
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"--json",
|
|
32
|
+
dest="output_format",
|
|
33
|
+
action="store_const",
|
|
34
|
+
const="json",
|
|
35
|
+
default=argparse.SUPPRESS,
|
|
36
|
+
help="Emit machine-readable JSON for this command",
|
|
37
|
+
)
|
|
38
|
+
else:
|
|
39
|
+
parser.add_argument(
|
|
40
|
+
"--json",
|
|
41
|
+
dest="output_format",
|
|
42
|
+
action="store_const",
|
|
43
|
+
const="json",
|
|
44
|
+
default=default,
|
|
45
|
+
help="Emit machine-readable JSON for this command",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def write_json(command: str, data: list | dict) -> None:
|
|
50
|
+
"""Write a JSON envelope to stdout and flush.
|
|
51
|
+
|
|
52
|
+
The envelope is a single-line JSON object with a stable schema:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{"schema_version": 1, "command": "...", "data": ...}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
command: Self-documenting command name (e.g. `'list'`,
|
|
60
|
+
`'threads list'`).
|
|
61
|
+
data: Payload — typically a list for listing commands or a dict
|
|
62
|
+
for action/info commands.
|
|
63
|
+
|
|
64
|
+
`default=str` is used so that `Path` and `datetime` objects
|
|
65
|
+
serialize without error.
|
|
66
|
+
"""
|
|
67
|
+
envelope = {"schema_version": 1, "command": command, "data": data}
|
|
68
|
+
sys.stdout.write(json.dumps(envelope, default=str) + "\n")
|
|
69
|
+
sys.stdout.flush()
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"""Utilities for project root detection and project-specific configuration."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
from docagent_cli._env_vars import SERVER_ENV_PREFIX
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from collections.abc import Mapping
|
|
14
|
+
|
|
15
|
+
import logging
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass(frozen=True)
|
|
21
|
+
class ProjectContext:
|
|
22
|
+
"""Explicit user/project path context for project-sensitive behavior.
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
user_cwd: Authoritative working directory from the CLI invocation.
|
|
26
|
+
project_root: Resolved project root for `user_cwd`, if one exists.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
user_cwd: Path
|
|
30
|
+
project_root: Path | None = None
|
|
31
|
+
|
|
32
|
+
def __post_init__(self) -> None:
|
|
33
|
+
"""Validate that path fields are absolute.
|
|
34
|
+
|
|
35
|
+
Raises:
|
|
36
|
+
ValueError: If `user_cwd` or `project_root` is not absolute.
|
|
37
|
+
"""
|
|
38
|
+
if not self.user_cwd.is_absolute():
|
|
39
|
+
msg = f"user_cwd must be absolute, got {self.user_cwd!r}"
|
|
40
|
+
raise ValueError(msg)
|
|
41
|
+
if self.project_root is not None and not self.project_root.is_absolute():
|
|
42
|
+
msg = f"project_root must be absolute, got {self.project_root!r}"
|
|
43
|
+
raise ValueError(msg)
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def from_user_cwd(cls, user_cwd: str | Path) -> ProjectContext:
|
|
47
|
+
"""Build a project context from an explicit user working directory.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
user_cwd: User invocation directory.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Resolved project context.
|
|
54
|
+
"""
|
|
55
|
+
resolved_cwd = Path(user_cwd).expanduser().resolve()
|
|
56
|
+
return cls(
|
|
57
|
+
user_cwd=resolved_cwd,
|
|
58
|
+
project_root=find_project_root(resolved_cwd),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
def resolve_user_path(self, path: str | Path) -> Path:
|
|
62
|
+
"""Resolve a path relative to the explicit user working directory.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
path: Absolute or relative user-facing path.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Absolute resolved path.
|
|
69
|
+
"""
|
|
70
|
+
candidate = Path(path).expanduser()
|
|
71
|
+
if candidate.is_absolute():
|
|
72
|
+
return candidate.resolve()
|
|
73
|
+
return (self.user_cwd / candidate).resolve()
|
|
74
|
+
|
|
75
|
+
def project_agent_md_paths(self) -> list[Path]:
|
|
76
|
+
"""Return project-level `AGENTS.md` files for this context."""
|
|
77
|
+
if self.project_root is None:
|
|
78
|
+
return []
|
|
79
|
+
return find_project_agent_md(self.project_root)
|
|
80
|
+
|
|
81
|
+
def project_skills_dir(self) -> Path | None:
|
|
82
|
+
"""Return the project `.docagent/skills` directory, if any."""
|
|
83
|
+
if self.project_root is None:
|
|
84
|
+
return None
|
|
85
|
+
return self.project_root / ".docagent" / "skills"
|
|
86
|
+
|
|
87
|
+
def project_agents_dir(self) -> Path | None:
|
|
88
|
+
"""Return the project `.docagent/agents` directory, if any."""
|
|
89
|
+
if self.project_root is None:
|
|
90
|
+
return None
|
|
91
|
+
return self.project_root / ".docagent" / "agents"
|
|
92
|
+
|
|
93
|
+
def project_agent_skills_dir(self) -> Path | None:
|
|
94
|
+
"""Return the project `.agents/skills` directory, if any."""
|
|
95
|
+
if self.project_root is None:
|
|
96
|
+
return None
|
|
97
|
+
return self.project_root / ".agents" / "skills"
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def get_server_project_context(
|
|
101
|
+
env: Mapping[str, str] | None = None,
|
|
102
|
+
) -> ProjectContext | None:
|
|
103
|
+
"""Read the server project context from environment transport data.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
env: Environment mapping to read from.
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
Reconstructed project context, or `None` if no server context exists.
|
|
110
|
+
"""
|
|
111
|
+
environment = os.environ if env is None else env
|
|
112
|
+
raw_cwd = environment.get(f"{SERVER_ENV_PREFIX}CWD")
|
|
113
|
+
if not raw_cwd:
|
|
114
|
+
return None
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
user_cwd = Path(raw_cwd).expanduser().resolve()
|
|
118
|
+
raw_project_root = environment.get(f"{SERVER_ENV_PREFIX}PROJECT_ROOT")
|
|
119
|
+
project_root = (
|
|
120
|
+
Path(raw_project_root).expanduser().resolve()
|
|
121
|
+
if raw_project_root
|
|
122
|
+
else find_project_root(user_cwd)
|
|
123
|
+
)
|
|
124
|
+
except OSError:
|
|
125
|
+
logger.warning(
|
|
126
|
+
"Could not resolve server project context from CWD=%s",
|
|
127
|
+
raw_cwd,
|
|
128
|
+
exc_info=True,
|
|
129
|
+
)
|
|
130
|
+
return None
|
|
131
|
+
|
|
132
|
+
return ProjectContext(user_cwd=user_cwd, project_root=project_root)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def find_project_root(start_path: str | Path | None = None) -> Path | None:
|
|
136
|
+
"""Find the project root by looking for .git directory.
|
|
137
|
+
|
|
138
|
+
Walks up the directory tree from start_path (or cwd) looking for a .git
|
|
139
|
+
directory, which indicates the project root.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
start_path: Directory to start searching from.
|
|
143
|
+
Defaults to current working directory.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
Path to the project root if found, None otherwise.
|
|
147
|
+
"""
|
|
148
|
+
current = Path(start_path or Path.cwd()).expanduser().resolve()
|
|
149
|
+
|
|
150
|
+
# Walk up the directory tree
|
|
151
|
+
for parent in [current, *list(current.parents)]:
|
|
152
|
+
git_dir = parent / ".git"
|
|
153
|
+
if git_dir.exists():
|
|
154
|
+
return parent
|
|
155
|
+
|
|
156
|
+
return None
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def find_project_agent_md(project_root: Path) -> list[Path]:
|
|
160
|
+
"""Find project-specific AGENTS.md file(s).
|
|
161
|
+
|
|
162
|
+
Checks two locations and returns ALL that exist:
|
|
163
|
+
1. project_root/.docagent/AGENTS.md
|
|
164
|
+
2. project_root/AGENTS.md
|
|
165
|
+
|
|
166
|
+
Both files will be loaded and combined if both exist.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
project_root: Path to the project root directory.
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
Existing AGENTS.md paths.
|
|
173
|
+
|
|
174
|
+
Empty if neither file exists, one entry if only one is present, or
|
|
175
|
+
two entries if both locations have the file.
|
|
176
|
+
"""
|
|
177
|
+
candidates = [
|
|
178
|
+
project_root / ".docagent" / "AGENTS.md",
|
|
179
|
+
project_root / "AGENTS.md",
|
|
180
|
+
]
|
|
181
|
+
paths: list[Path] = []
|
|
182
|
+
for candidate in candidates:
|
|
183
|
+
try:
|
|
184
|
+
if candidate.exists():
|
|
185
|
+
paths.append(candidate)
|
|
186
|
+
except OSError:
|
|
187
|
+
pass
|
|
188
|
+
return paths
|
docagent_cli/py.typed
ADDED
|
File without changes
|