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.
Files changed (300) hide show
  1. docagent_cli/__init__.py +36 -0
  2. docagent_cli/__main__.py +6 -0
  3. docagent_cli/_ask_user_types.py +90 -0
  4. docagent_cli/_cli_context.py +27 -0
  5. docagent_cli/_debug.py +52 -0
  6. docagent_cli/_env_vars.py +56 -0
  7. docagent_cli/_server_config.py +352 -0
  8. docagent_cli/_session_stats.py +114 -0
  9. docagent_cli/_testing_models.py +144 -0
  10. docagent_cli/_version.py +17 -0
  11. docagent_cli/agent.py +1193 -0
  12. docagent_cli/app.py +4979 -0
  13. docagent_cli/app.tcss +283 -0
  14. docagent_cli/ask_user.py +301 -0
  15. docagent_cli/built_in_skills/__init__.py +5 -0
  16. docagent_cli/built_in_skills/doc-coauthoring/SKILL.md +375 -0
  17. docagent_cli/built_in_skills/docx/LICENSE.txt +30 -0
  18. docagent_cli/built_in_skills/docx/SKILL.md +590 -0
  19. docagent_cli/built_in_skills/docx/scripts/__init__.py +1 -0
  20. docagent_cli/built_in_skills/docx/scripts/accept_changes.py +135 -0
  21. docagent_cli/built_in_skills/docx/scripts/comment.py +318 -0
  22. docagent_cli/built_in_skills/docx/scripts/office/helpers/__init__.py +0 -0
  23. docagent_cli/built_in_skills/docx/scripts/office/helpers/merge_runs.py +199 -0
  24. docagent_cli/built_in_skills/docx/scripts/office/helpers/simplify_redlines.py +197 -0
  25. docagent_cli/built_in_skills/docx/scripts/office/pack.py +159 -0
  26. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  27. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  28. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  29. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  30. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  31. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  32. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  33. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  34. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  35. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  36. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  37. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  38. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  39. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  40. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  41. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  42. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  43. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  44. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  45. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  46. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  47. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  48. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  49. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  50. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  51. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  52. docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  53. docagent_cli/built_in_skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  54. docagent_cli/built_in_skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  55. docagent_cli/built_in_skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  56. docagent_cli/built_in_skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  57. docagent_cli/built_in_skills/docx/scripts/office/schemas/mce/mc.xsd +75 -0
  58. docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  59. docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  60. docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  61. docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  62. docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  63. docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  64. docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  65. docagent_cli/built_in_skills/docx/scripts/office/soffice.py +183 -0
  66. docagent_cli/built_in_skills/docx/scripts/office/unpack.py +132 -0
  67. docagent_cli/built_in_skills/docx/scripts/office/validate.py +111 -0
  68. docagent_cli/built_in_skills/docx/scripts/office/validators/__init__.py +15 -0
  69. docagent_cli/built_in_skills/docx/scripts/office/validators/base.py +847 -0
  70. docagent_cli/built_in_skills/docx/scripts/office/validators/docx.py +446 -0
  71. docagent_cli/built_in_skills/docx/scripts/office/validators/pptx.py +275 -0
  72. docagent_cli/built_in_skills/docx/scripts/office/validators/redlining.py +247 -0
  73. docagent_cli/built_in_skills/docx/scripts/templates/comments.xml +3 -0
  74. docagent_cli/built_in_skills/docx/scripts/templates/commentsExtended.xml +3 -0
  75. docagent_cli/built_in_skills/docx/scripts/templates/commentsExtensible.xml +3 -0
  76. docagent_cli/built_in_skills/docx/scripts/templates/commentsIds.xml +3 -0
  77. docagent_cli/built_in_skills/docx/scripts/templates/people.xml +3 -0
  78. docagent_cli/built_in_skills/pdf/LICENSE.txt +30 -0
  79. docagent_cli/built_in_skills/pdf/SKILL.md +314 -0
  80. docagent_cli/built_in_skills/pdf/forms.md +294 -0
  81. docagent_cli/built_in_skills/pdf/reference.md +612 -0
  82. docagent_cli/built_in_skills/pdf/scripts/check_bounding_boxes.py +65 -0
  83. docagent_cli/built_in_skills/pdf/scripts/check_fillable_fields.py +11 -0
  84. docagent_cli/built_in_skills/pdf/scripts/convert_pdf_to_images.py +33 -0
  85. docagent_cli/built_in_skills/pdf/scripts/create_validation_image.py +37 -0
  86. docagent_cli/built_in_skills/pdf/scripts/extract_form_field_info.py +122 -0
  87. docagent_cli/built_in_skills/pdf/scripts/extract_form_structure.py +115 -0
  88. docagent_cli/built_in_skills/pdf/scripts/fill_fillable_fields.py +98 -0
  89. docagent_cli/built_in_skills/pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
  90. docagent_cli/built_in_skills/pptx/LICENSE.txt +30 -0
  91. docagent_cli/built_in_skills/pptx/SKILL.md +232 -0
  92. docagent_cli/built_in_skills/pptx/editing.md +205 -0
  93. docagent_cli/built_in_skills/pptx/pptxgenjs.md +420 -0
  94. docagent_cli/built_in_skills/pptx/scripts/__init__.py +0 -0
  95. docagent_cli/built_in_skills/pptx/scripts/add_slide.py +195 -0
  96. docagent_cli/built_in_skills/pptx/scripts/clean.py +286 -0
  97. docagent_cli/built_in_skills/pptx/scripts/office/helpers/__init__.py +0 -0
  98. docagent_cli/built_in_skills/pptx/scripts/office/helpers/merge_runs.py +199 -0
  99. docagent_cli/built_in_skills/pptx/scripts/office/helpers/simplify_redlines.py +197 -0
  100. docagent_cli/built_in_skills/pptx/scripts/office/pack.py +159 -0
  101. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  102. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  103. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  104. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  105. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  106. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  107. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  108. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  109. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  110. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  111. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  112. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  113. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  114. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  115. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  116. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  117. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  118. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  119. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  120. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  121. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  122. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  123. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  124. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  125. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  126. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  127. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  128. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  129. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  130. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  131. docagent_cli/built_in_skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  132. docagent_cli/built_in_skills/pptx/scripts/office/schemas/mce/mc.xsd +75 -0
  133. docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  134. docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  135. docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  136. docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  137. docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  138. docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  139. docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  140. docagent_cli/built_in_skills/pptx/scripts/office/soffice.py +183 -0
  141. docagent_cli/built_in_skills/pptx/scripts/office/unpack.py +132 -0
  142. docagent_cli/built_in_skills/pptx/scripts/office/validate.py +111 -0
  143. docagent_cli/built_in_skills/pptx/scripts/office/validators/__init__.py +15 -0
  144. docagent_cli/built_in_skills/pptx/scripts/office/validators/base.py +847 -0
  145. docagent_cli/built_in_skills/pptx/scripts/office/validators/docx.py +446 -0
  146. docagent_cli/built_in_skills/pptx/scripts/office/validators/pptx.py +275 -0
  147. docagent_cli/built_in_skills/pptx/scripts/office/validators/redlining.py +247 -0
  148. docagent_cli/built_in_skills/pptx/scripts/thumbnail.py +289 -0
  149. docagent_cli/built_in_skills/remember/SKILL.md +118 -0
  150. docagent_cli/built_in_skills/skill-creator/LICENSE.txt +202 -0
  151. docagent_cli/built_in_skills/skill-creator/SKILL.md +485 -0
  152. docagent_cli/built_in_skills/skill-creator/agents/analyzer.md +274 -0
  153. docagent_cli/built_in_skills/skill-creator/agents/comparator.md +202 -0
  154. docagent_cli/built_in_skills/skill-creator/agents/grader.md +223 -0
  155. docagent_cli/built_in_skills/skill-creator/assets/eval_review.html +146 -0
  156. docagent_cli/built_in_skills/skill-creator/eval-viewer/generate_review.py +471 -0
  157. docagent_cli/built_in_skills/skill-creator/eval-viewer/viewer.html +1325 -0
  158. docagent_cli/built_in_skills/skill-creator/references/schemas.md +430 -0
  159. docagent_cli/built_in_skills/skill-creator/scripts/__init__.py +0 -0
  160. docagent_cli/built_in_skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  161. docagent_cli/built_in_skills/skill-creator/scripts/generate_report.py +326 -0
  162. docagent_cli/built_in_skills/skill-creator/scripts/improve_description.py +247 -0
  163. docagent_cli/built_in_skills/skill-creator/scripts/package_skill.py +136 -0
  164. docagent_cli/built_in_skills/skill-creator/scripts/quick_validate.py +103 -0
  165. docagent_cli/built_in_skills/skill-creator/scripts/run_eval.py +310 -0
  166. docagent_cli/built_in_skills/skill-creator/scripts/run_loop.py +328 -0
  167. docagent_cli/built_in_skills/skill-creator/scripts/utils.py +47 -0
  168. docagent_cli/built_in_skills/theme-factory/LICENSE.txt +202 -0
  169. docagent_cli/built_in_skills/theme-factory/SKILL.md +59 -0
  170. docagent_cli/built_in_skills/theme-factory/theme-showcase.pdf +0 -0
  171. docagent_cli/built_in_skills/theme-factory/themes/arctic-frost.md +19 -0
  172. docagent_cli/built_in_skills/theme-factory/themes/botanical-garden.md +19 -0
  173. docagent_cli/built_in_skills/theme-factory/themes/desert-rose.md +19 -0
  174. docagent_cli/built_in_skills/theme-factory/themes/forest-canopy.md +19 -0
  175. docagent_cli/built_in_skills/theme-factory/themes/golden-hour.md +19 -0
  176. docagent_cli/built_in_skills/theme-factory/themes/midnight-galaxy.md +19 -0
  177. docagent_cli/built_in_skills/theme-factory/themes/modern-minimalist.md +19 -0
  178. docagent_cli/built_in_skills/theme-factory/themes/ocean-depths.md +19 -0
  179. docagent_cli/built_in_skills/theme-factory/themes/sunset-boulevard.md +19 -0
  180. docagent_cli/built_in_skills/theme-factory/themes/tech-innovation.md +19 -0
  181. docagent_cli/built_in_skills/xlsx/LICENSE.txt +30 -0
  182. docagent_cli/built_in_skills/xlsx/SKILL.md +292 -0
  183. docagent_cli/built_in_skills/xlsx/scripts/office/helpers/__init__.py +0 -0
  184. docagent_cli/built_in_skills/xlsx/scripts/office/helpers/merge_runs.py +199 -0
  185. docagent_cli/built_in_skills/xlsx/scripts/office/helpers/simplify_redlines.py +197 -0
  186. docagent_cli/built_in_skills/xlsx/scripts/office/pack.py +159 -0
  187. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  188. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  189. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  190. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  191. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  192. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  193. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  194. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  195. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  196. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  197. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  198. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  199. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  200. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  201. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  202. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  203. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  204. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  205. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  206. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  207. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  208. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  209. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  210. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  211. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  212. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  213. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  214. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  215. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  216. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  217. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  218. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/mce/mc.xsd +75 -0
  219. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  220. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  221. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  222. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  223. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  224. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  225. docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  226. docagent_cli/built_in_skills/xlsx/scripts/office/soffice.py +183 -0
  227. docagent_cli/built_in_skills/xlsx/scripts/office/unpack.py +132 -0
  228. docagent_cli/built_in_skills/xlsx/scripts/office/validate.py +111 -0
  229. docagent_cli/built_in_skills/xlsx/scripts/office/validators/__init__.py +15 -0
  230. docagent_cli/built_in_skills/xlsx/scripts/office/validators/base.py +847 -0
  231. docagent_cli/built_in_skills/xlsx/scripts/office/validators/docx.py +446 -0
  232. docagent_cli/built_in_skills/xlsx/scripts/office/validators/pptx.py +275 -0
  233. docagent_cli/built_in_skills/xlsx/scripts/office/validators/redlining.py +247 -0
  234. docagent_cli/built_in_skills/xlsx/scripts/recalc.py +184 -0
  235. docagent_cli/clipboard.py +128 -0
  236. docagent_cli/command_registry.py +284 -0
  237. docagent_cli/config.py +2418 -0
  238. docagent_cli/configurable_model.py +162 -0
  239. docagent_cli/default_agent_prompt.md +12 -0
  240. docagent_cli/editor.py +142 -0
  241. docagent_cli/file_ops.py +473 -0
  242. docagent_cli/formatting.py +28 -0
  243. docagent_cli/hooks.py +206 -0
  244. docagent_cli/input.py +787 -0
  245. docagent_cli/integrations/__init__.py +1 -0
  246. docagent_cli/integrations/sandbox_factory.py +873 -0
  247. docagent_cli/integrations/sandbox_provider.py +71 -0
  248. docagent_cli/local_context.py +718 -0
  249. docagent_cli/main.py +1641 -0
  250. docagent_cli/mcp_tools.py +707 -0
  251. docagent_cli/mcp_trust.py +168 -0
  252. docagent_cli/media_utils.py +478 -0
  253. docagent_cli/model_config.py +1620 -0
  254. docagent_cli/non_interactive.py +948 -0
  255. docagent_cli/offload.py +371 -0
  256. docagent_cli/output.py +69 -0
  257. docagent_cli/project_utils.py +188 -0
  258. docagent_cli/py.typed +0 -0
  259. docagent_cli/remote_client.py +515 -0
  260. docagent_cli/server.py +520 -0
  261. docagent_cli/server_graph.py +196 -0
  262. docagent_cli/server_manager.py +365 -0
  263. docagent_cli/sessions.py +1262 -0
  264. docagent_cli/skills/__init__.py +18 -0
  265. docagent_cli/skills/commands.py +1090 -0
  266. docagent_cli/skills/load.py +192 -0
  267. docagent_cli/subagents.py +173 -0
  268. docagent_cli/system_prompt.md +247 -0
  269. docagent_cli/textual_adapter.py +1352 -0
  270. docagent_cli/theme.py +842 -0
  271. docagent_cli/token_state.py +31 -0
  272. docagent_cli/tool_display.py +298 -0
  273. docagent_cli/tools.py +236 -0
  274. docagent_cli/ui.py +420 -0
  275. docagent_cli/unicode_security.py +516 -0
  276. docagent_cli/update_check.py +454 -0
  277. docagent_cli/widgets/__init__.py +9 -0
  278. docagent_cli/widgets/_links.py +63 -0
  279. docagent_cli/widgets/approval.py +442 -0
  280. docagent_cli/widgets/ask_user.py +398 -0
  281. docagent_cli/widgets/autocomplete.py +691 -0
  282. docagent_cli/widgets/chat_input.py +1827 -0
  283. docagent_cli/widgets/diff.py +248 -0
  284. docagent_cli/widgets/history.py +188 -0
  285. docagent_cli/widgets/loading.py +177 -0
  286. docagent_cli/widgets/mcp_viewer.py +362 -0
  287. docagent_cli/widgets/message_store.py +675 -0
  288. docagent_cli/widgets/messages.py +1751 -0
  289. docagent_cli/widgets/model_selector.py +964 -0
  290. docagent_cli/widgets/status.py +372 -0
  291. docagent_cli/widgets/theme_selector.py +164 -0
  292. docagent_cli/widgets/thread_selector.py +1905 -0
  293. docagent_cli/widgets/tool_renderers.py +148 -0
  294. docagent_cli/widgets/tool_widgets.py +274 -0
  295. docagent_cli/widgets/welcome.py +339 -0
  296. docagent_cli-0.0.35.data/data/docagent_cli/default_agent_prompt.md +12 -0
  297. docagent_cli-0.0.35.dist-info/METADATA +200 -0
  298. docagent_cli-0.0.35.dist-info/RECORD +300 -0
  299. docagent_cli-0.0.35.dist-info/WHEEL +4 -0
  300. docagent_cli-0.0.35.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,454 @@
1
+ """Update lifecycle for `docagent-cli`.
2
+
3
+ Handles version checking against PyPI (with caching), install-method detection,
4
+ auto-upgrade execution, config-driven opt-in/out, and "what's new" tracking.
5
+
6
+ Most public entry points absorb errors and return sentinel values.
7
+ `set_auto_update` raises on write failures so callers can surface
8
+ actionable feedback.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import asyncio
14
+ import json
15
+ import logging
16
+ import os
17
+ import shutil
18
+ import sys
19
+ import time
20
+ import tomllib
21
+ from typing import TYPE_CHECKING, Literal
22
+
23
+ from packaging.version import InvalidVersion, Version
24
+
25
+ from docagent_cli._version import PYPI_URL, USER_AGENT, __version__
26
+
27
+ if TYPE_CHECKING:
28
+ from pathlib import Path
29
+
30
+ from docagent_cli.model_config import DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_PATH
31
+
32
+ logger = logging.getLogger(__name__)
33
+
34
+ CACHE_FILE: Path = DEFAULT_CONFIG_DIR / "latest_version.json"
35
+ SEEN_VERSION_FILE: Path = DEFAULT_CONFIG_DIR / "seen_version.json"
36
+ CACHE_TTL = 86_400 # 24 hours
37
+
38
+ InstallMethod = Literal["uv", "pip", "brew", "unknown"]
39
+
40
+ _UPGRADE_COMMANDS: dict[InstallMethod, str] = {
41
+ "uv": "uv tool upgrade docagent-cli",
42
+ "brew": "brew upgrade docagent-cli",
43
+ "pip": "pip install --upgrade docagent-cli",
44
+ }
45
+ """Upgrade commands keyed by install method.
46
+
47
+ `perform_upgrade` runs only the command matching the detected install method;
48
+ no fallback chain.
49
+ """
50
+
51
+ _UPGRADE_TIMEOUT = 120 # seconds
52
+
53
+
54
+ def _parse_version(v: str) -> Version:
55
+ """Parse a PEP 440 version string into a comparable `Version` object.
56
+
57
+ Supports stable (`1.2.3`) and pre-release (`1.2.3a1`, `1.2.3rc2`) versions.
58
+
59
+ Args:
60
+ v: Version string like `'1.2.3'` or `'1.2.3a1'`.
61
+
62
+ Returns:
63
+ A `packaging.version.Version` instance.
64
+ """
65
+ return Version(v.strip()) # raises InvalidVersion for non-PEP 440 strings
66
+
67
+
68
+ def _latest_from_releases(
69
+ releases: dict[str, list[object]],
70
+ *,
71
+ include_prereleases: bool,
72
+ ) -> str | None:
73
+ """Pick the newest version from a PyPI `releases` mapping.
74
+
75
+ Skips versions with no uploaded files (empty entries) and, when
76
+ *include_prereleases* is `False`, skips pre-release versions.
77
+
78
+ Args:
79
+ releases: The `releases` dict from the PyPI JSON API.
80
+ include_prereleases: Whether to consider pre-release versions.
81
+
82
+ Returns:
83
+ The highest matching version string, or `None` if none qualify.
84
+ """
85
+ best: Version | None = None
86
+ best_str: str | None = None
87
+ for ver_str, files in releases.items():
88
+ if not files:
89
+ continue
90
+ try:
91
+ ver = Version(ver_str)
92
+ except InvalidVersion:
93
+ logger.debug("Skipping unparseable release key: %s", ver_str)
94
+ continue
95
+ if not include_prereleases and ver.is_prerelease:
96
+ continue
97
+ if best is None or ver > best:
98
+ best = ver
99
+ best_str = ver_str
100
+ return best_str
101
+
102
+
103
+ def get_latest_version(
104
+ *,
105
+ bypass_cache: bool = False,
106
+ include_prereleases: bool = False,
107
+ ) -> str | None:
108
+ """Fetch the latest docagent-cli version from PyPI, with caching.
109
+
110
+ Results are cached to `CACHE_FILE` to avoid repeated network calls.
111
+ The cache stores both the latest stable and pre-release versions so a
112
+ single PyPI request serves both code paths.
113
+
114
+ Args:
115
+ bypass_cache: Skip the cache and always hit PyPI.
116
+ include_prereleases: When `True`, consider pre-release versions
117
+ (alpha, beta, rc). Stable users should leave this `False`.
118
+
119
+ Returns:
120
+ The latest version string, or `None` on any failure.
121
+ """
122
+ cache_key = "version_prerelease" if include_prereleases else "version"
123
+
124
+ try:
125
+ if not bypass_cache and CACHE_FILE.exists():
126
+ data = json.loads(CACHE_FILE.read_text(encoding="utf-8"))
127
+ fresh = time.time() - data.get("checked_at", 0) < CACHE_TTL
128
+ if fresh and cache_key in data:
129
+ return data[cache_key]
130
+ except (OSError, json.JSONDecodeError, TypeError):
131
+ logger.debug("Failed to read update-check cache", exc_info=True)
132
+
133
+ try:
134
+ import requests
135
+ except ImportError:
136
+ logger.warning(
137
+ "requests package not installed — update checks disabled. "
138
+ "Install with: pip install requests"
139
+ )
140
+ return None
141
+
142
+ try:
143
+ resp = requests.get(
144
+ PYPI_URL,
145
+ headers={"User-Agent": USER_AGENT},
146
+ timeout=3,
147
+ )
148
+ resp.raise_for_status()
149
+ payload = resp.json()
150
+ stable: str = payload["info"]["version"]
151
+ releases: dict[str, list[object]] = payload.get("releases", {})
152
+ if not releases:
153
+ logger.debug("PyPI response missing or empty 'releases' key")
154
+ prerelease = _latest_from_releases(releases, include_prereleases=True)
155
+ except (requests.RequestException, OSError, KeyError, json.JSONDecodeError):
156
+ logger.debug("Failed to fetch latest version from PyPI", exc_info=True)
157
+ return None
158
+
159
+ try:
160
+ CACHE_FILE.parent.mkdir(parents=True, exist_ok=True)
161
+ CACHE_FILE.write_text(
162
+ json.dumps(
163
+ {
164
+ "version": stable,
165
+ "version_prerelease": prerelease,
166
+ "checked_at": time.time(),
167
+ }
168
+ ),
169
+ encoding="utf-8",
170
+ )
171
+ except OSError:
172
+ logger.debug("Failed to write update-check cache", exc_info=True)
173
+
174
+ return prerelease if include_prereleases else stable
175
+
176
+
177
+ def is_update_available(*, bypass_cache: bool = False) -> tuple[bool, str | None]:
178
+ """Check whether a newer version of docagent-cli is available.
179
+
180
+ When the installed version is a pre-release (e.g. `0.0.35a1`),
181
+ pre-release versions on PyPI are included in the comparison so alpha
182
+ testers are notified of newer alphas and the eventual stable release.
183
+ Stable installs only compare against stable PyPI releases.
184
+
185
+ Args:
186
+ bypass_cache: Skip the cache and always hit PyPI.
187
+
188
+ Returns:
189
+ A `(available, latest)` tuple.
190
+
191
+ `available` is `True` when the PyPI version is strictly newer than
192
+ the installed version; `latest` is the version string (or `None`
193
+ when the check fails).
194
+ """
195
+ try:
196
+ installed = _parse_version(__version__)
197
+ except InvalidVersion:
198
+ logger.warning(
199
+ "Installed version %r is not PEP 440 compliant; "
200
+ "update checks disabled for this install",
201
+ __version__,
202
+ )
203
+ return False, None
204
+
205
+ include_prereleases = installed.is_prerelease
206
+ latest = get_latest_version(
207
+ bypass_cache=bypass_cache,
208
+ include_prereleases=include_prereleases,
209
+ )
210
+ if latest is None:
211
+ return False, None
212
+
213
+ try:
214
+ if _parse_version(latest) > installed:
215
+ return True, latest
216
+ except InvalidVersion:
217
+ logger.debug("Failed to compare versions", exc_info=True)
218
+
219
+ return False, None
220
+
221
+
222
+ # ---------------------------------------------------------------------------
223
+ # Install method detection
224
+ # ---------------------------------------------------------------------------
225
+
226
+
227
+ def detect_install_method() -> InstallMethod:
228
+ """Detect how `docagent-cli` was installed.
229
+
230
+ Checks `sys.prefix` against known paths for uv and Homebrew.
231
+
232
+ Returns:
233
+ The detected install method: `'uv'`, `'brew'`, `'pip'`, or `'unknown'`
234
+ (editable/dev installs).
235
+ """
236
+ from docagent_cli.config import _is_editable_install
237
+
238
+ prefix = sys.prefix
239
+ # uv tool installs live under ~/.local/share/uv/tools/
240
+ if "/uv/tools/" in prefix or "\\uv\\tools\\" in prefix:
241
+ return "uv"
242
+ # Homebrew prefixes
243
+ if any(
244
+ prefix.startswith(p)
245
+ for p in ("/opt/homebrew", "/usr/local/Cellar", "/home/linuxbrew")
246
+ ):
247
+ return "brew"
248
+ # Editable / dev installs — don't auto-upgrade
249
+ if _is_editable_install():
250
+ return "unknown"
251
+ return "pip"
252
+
253
+
254
+ def upgrade_command(method: InstallMethod | None = None) -> str:
255
+ """Return the shell command to upgrade `docagent-cli`.
256
+
257
+ Falls back to the pip command for unrecognized install methods.
258
+
259
+ Args:
260
+ method: Install method override.
261
+
262
+ Auto-detected if `None`.
263
+ """
264
+ if method is None:
265
+ method = detect_install_method()
266
+ return _UPGRADE_COMMANDS.get(method, _UPGRADE_COMMANDS["pip"])
267
+
268
+
269
+ async def perform_upgrade() -> tuple[bool, str]:
270
+ """Attempt to upgrade `docagent-cli` using the detected install method.
271
+
272
+ Only tries the detected method — does not fall back to other package
273
+ managers to avoid cross-environment contamination.
274
+
275
+ Returns:
276
+ `(success, output)` — *output* is the combined stdout/stderr.
277
+ """
278
+ method = detect_install_method()
279
+ if method == "unknown":
280
+ return False, "Editable install detected — skipping auto-update."
281
+
282
+ cmd = _UPGRADE_COMMANDS.get(method)
283
+ if cmd is None:
284
+ return False, f"No upgrade command for install method: {method}"
285
+
286
+ # Skip brew if binary not on PATH
287
+ if method == "brew" and not shutil.which("brew"):
288
+ return False, "brew not found on PATH."
289
+
290
+ try:
291
+ proc = await asyncio.create_subprocess_shell(
292
+ cmd,
293
+ stdout=asyncio.subprocess.PIPE,
294
+ stderr=asyncio.subprocess.PIPE,
295
+ stdin=asyncio.subprocess.DEVNULL,
296
+ )
297
+ stdout, stderr = await asyncio.wait_for(
298
+ proc.communicate(), timeout=_UPGRADE_TIMEOUT
299
+ )
300
+ output = (stdout or b"").decode() + (stderr or b"").decode()
301
+ if proc.returncode == 0:
302
+ return True, output.strip()
303
+ logger.warning(
304
+ "Upgrade via %s exited with code %d: %s",
305
+ method,
306
+ proc.returncode,
307
+ output.strip(),
308
+ )
309
+ return False, output.strip()
310
+ except TimeoutError:
311
+ proc.kill()
312
+ await proc.wait()
313
+ msg = f"Upgrade command timed out after {_UPGRADE_TIMEOUT}s: {cmd}"
314
+ logger.warning(msg)
315
+ return False, msg
316
+ except OSError:
317
+ logger.warning("Failed to execute upgrade command: %s", cmd, exc_info=True)
318
+ return False, f"Failed to execute: {cmd}"
319
+
320
+
321
+ # ---------------------------------------------------------------------------
322
+ # Config helpers
323
+ # ---------------------------------------------------------------------------
324
+
325
+
326
+ def is_update_check_enabled() -> bool:
327
+ """Return whether update checks are enabled.
328
+
329
+ Checks `DEEPAGENTS_CLI_NO_UPDATE_CHECK` env var and the `[update].check` key
330
+ in `config.toml`.
331
+
332
+ Defaults to enabled.
333
+ """
334
+ from docagent_cli._env_vars import NO_UPDATE_CHECK
335
+
336
+ if os.environ.get(NO_UPDATE_CHECK):
337
+ return False
338
+ return _read_update_config().get("check", True)
339
+
340
+
341
+ def is_auto_update_enabled() -> bool:
342
+ """Return whether auto-update is enabled.
343
+
344
+ Opt-in via `DEEPAGENTS_CLI_AUTO_UPDATE=1` env var or
345
+ `[update].auto_update = true` in `config.toml`.
346
+
347
+ Defaults to `False`.
348
+
349
+ Always disabled for editable installs.
350
+ """
351
+ from docagent_cli._env_vars import AUTO_UPDATE
352
+ from docagent_cli.config import _is_editable_install
353
+
354
+ if _is_editable_install():
355
+ return False
356
+ if os.environ.get(AUTO_UPDATE, "").lower() in {"1", "true", "yes"}:
357
+ return True
358
+ return _read_update_config().get("auto_update", False)
359
+
360
+
361
+ def set_auto_update(enabled: bool) -> None:
362
+ """Persist the auto-update preference to `config.toml`.
363
+
364
+ Writes `[update].auto_update` so the setting survives across sessions.
365
+
366
+ Args:
367
+ enabled: Whether auto-update should be enabled.
368
+ """
369
+ import contextlib
370
+ import tempfile
371
+ from pathlib import Path
372
+
373
+ import tomli_w
374
+
375
+ DEFAULT_CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
376
+ if DEFAULT_CONFIG_PATH.exists():
377
+ with DEFAULT_CONFIG_PATH.open("rb") as f:
378
+ data = tomllib.load(f)
379
+ else:
380
+ data = {}
381
+
382
+ if "update" not in data:
383
+ data["update"] = {}
384
+ data["update"]["auto_update"] = enabled
385
+
386
+ fd, tmp_path = tempfile.mkstemp(dir=DEFAULT_CONFIG_PATH.parent, suffix=".tmp")
387
+ try:
388
+ with os.fdopen(fd, "wb") as f:
389
+ tomli_w.dump(data, f)
390
+ Path(tmp_path).replace(DEFAULT_CONFIG_PATH)
391
+ except BaseException:
392
+ with contextlib.suppress(OSError):
393
+ Path(tmp_path).unlink()
394
+ raise
395
+
396
+
397
+ def _read_update_config() -> dict[str, bool]:
398
+ """Read `[update]` section from `config.toml`.
399
+
400
+ Returns:
401
+ A dict of boolean config values, empty on missing/unreadable file.
402
+ """
403
+ try:
404
+ if not DEFAULT_CONFIG_PATH.exists():
405
+ return {}
406
+ with DEFAULT_CONFIG_PATH.open("rb") as f:
407
+ data = tomllib.load(f)
408
+ section = data.get("update", {})
409
+ return {k: v for k, v in section.items() if isinstance(v, bool)}
410
+ except (OSError, tomllib.TOMLDecodeError):
411
+ logger.warning("Could not read [update] config — using defaults", exc_info=True)
412
+ return {}
413
+
414
+
415
+ # ---------------------------------------------------------------------------
416
+ # "What's new" tracking
417
+ # ---------------------------------------------------------------------------
418
+
419
+
420
+ def get_seen_version() -> str | None:
421
+ """Return the last version the user saw the "what's new" banner for."""
422
+ try:
423
+ if SEEN_VERSION_FILE.exists():
424
+ data = json.loads(SEEN_VERSION_FILE.read_text(encoding="utf-8"))
425
+ return data.get("version")
426
+ except (OSError, json.JSONDecodeError, KeyError, TypeError):
427
+ logger.debug("Failed to read seen-version file", exc_info=True)
428
+ return None
429
+
430
+
431
+ def mark_version_seen(version: str) -> None:
432
+ """Record that the user has seen the "what's new" banner for *version*."""
433
+ try:
434
+ SEEN_VERSION_FILE.parent.mkdir(parents=True, exist_ok=True)
435
+ SEEN_VERSION_FILE.write_text(
436
+ json.dumps({"version": version, "seen_at": time.time()}),
437
+ encoding="utf-8",
438
+ )
439
+ except OSError:
440
+ logger.debug("Failed to write seen-version file", exc_info=True)
441
+
442
+
443
+ def should_show_whats_new() -> bool:
444
+ """Return `True` if this is the first launch on a newer version."""
445
+ seen = get_seen_version()
446
+ if seen is None:
447
+ # First run ever — mark current as seen, don't show banner.
448
+ mark_version_seen(__version__)
449
+ return False
450
+ try:
451
+ return _parse_version(__version__) > _parse_version(seen)
452
+ except InvalidVersion:
453
+ logger.debug("Failed to compare versions for what's-new check", exc_info=True)
454
+ return False
@@ -0,0 +1,9 @@
1
+ """Textual widgets for docagent-cli.
2
+
3
+ Import directly from submodules, e.g.:
4
+
5
+ ```python
6
+ from docagent_cli.widgets.chat_input import ChatInput
7
+ from docagent_cli.widgets.messages import AssistantMessage
8
+ ```
9
+ """
@@ -0,0 +1,63 @@
1
+ """Shared link-click handling for Textual widgets."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import webbrowser
7
+ from typing import TYPE_CHECKING
8
+
9
+ from docagent_cli.unicode_security import check_url_safety, strip_dangerous_unicode
10
+
11
+ if TYPE_CHECKING:
12
+ from textual.events import Click
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ def open_style_link(event: Click) -> None:
18
+ """Open the URL from a Rich link style on click, if present.
19
+
20
+ Rich `Style(link=...)` embeds OSC 8 terminal hyperlinks, but Textual's
21
+ mouse capture intercepts normal clicks before the terminal can act on them.
22
+ By handling the Textual click event directly we open the URL with a single
23
+ click, matching the behavior of links in the Markdown widget.
24
+
25
+ URLs that fail the safety check (e.g. containing hidden Unicode or
26
+ homograph domains) are blocked and not opened; the event bubbles and a
27
+ warning is logged and displayed as a Textual notification.
28
+
29
+ On success the event is stopped so it does not bubble further. On failure
30
+ (e.g. no browser available in a headless environment) the error is logged at
31
+ debug level and the event bubbles normally.
32
+
33
+ Args:
34
+ event: The Textual click event to inspect.
35
+ """
36
+ url = event.style.link
37
+ if not url:
38
+ return
39
+
40
+ safety = check_url_safety(url)
41
+ if not safety.safe:
42
+ detail = safety.warnings[0] if safety.warnings else "Suspicious URL"
43
+ logger.warning("Blocked suspicious URL: %s (%s)", url, detail)
44
+ try:
45
+ app = getattr(event, "app", None)
46
+ notify = getattr(app, "notify", None)
47
+ if callable(notify):
48
+ safe_url = strip_dangerous_unicode(url)
49
+ notify(
50
+ f"Blocked suspicious URL: {safe_url}\n{detail}",
51
+ severity="warning",
52
+ markup=False,
53
+ )
54
+ except (AttributeError, TypeError):
55
+ logger.debug("Could not send URL-blocked notification", exc_info=True)
56
+ return
57
+
58
+ try:
59
+ webbrowser.open(url)
60
+ except Exception:
61
+ logger.debug("Could not open browser for URL: %s", url, exc_info=True)
62
+ return
63
+ event.stop()