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,675 @@
1
+ """Message store for virtualized chat history.
2
+
3
+ This module provides data structures and management for message virtualization,
4
+ allowing the CLI to handle large message histories efficiently by keeping only
5
+ a sliding window of widgets in the DOM while storing all message data as
6
+ lightweight dataclasses.
7
+
8
+ The approach is inspired by Textual's `Log` widget, which only keeps `N` lines
9
+ in the DOM and recreates older ones on demand.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import logging
15
+ import uuid
16
+ from dataclasses import dataclass, field
17
+ from enum import StrEnum
18
+ from time import time
19
+ from typing import TYPE_CHECKING, Any
20
+
21
+ if TYPE_CHECKING:
22
+ from textual.widget import Widget
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+ # Fields on MessageData that callers are allowed to update via update_message().
27
+ # Prevents accidental overwriting of identity fields like id/type/timestamp.
28
+ _UPDATABLE_FIELDS: frozenset[str] = frozenset(
29
+ {
30
+ "content",
31
+ "tool_status",
32
+ "tool_output",
33
+ "tool_expanded",
34
+ "skill_expanded",
35
+ "is_streaming",
36
+ "height_hint",
37
+ }
38
+ )
39
+
40
+
41
+ class MessageType(StrEnum):
42
+ """Types of messages in the chat."""
43
+
44
+ USER = "user"
45
+ ASSISTANT = "assistant"
46
+ TOOL = "tool"
47
+ SKILL = "skill"
48
+ ERROR = "error"
49
+ APP = "app"
50
+ SUMMARIZATION = "summarization"
51
+ DIFF = "diff"
52
+
53
+
54
+ class ToolStatus(StrEnum):
55
+ """Status of a tool call."""
56
+
57
+ PENDING = "pending"
58
+ RUNNING = "running"
59
+ SUCCESS = "success"
60
+ ERROR = "error"
61
+ REJECTED = "rejected"
62
+ SKIPPED = "skipped"
63
+
64
+
65
+ @dataclass
66
+ class MessageData:
67
+ """In-memory message data for virtualization.
68
+
69
+ This dataclass holds all information needed to recreate a message widget.
70
+ It is designed to be lightweight so that thousands of messages can be
71
+ stored without meaningful memory overhead.
72
+ """
73
+
74
+ type: MessageType
75
+ """The kind of message (user, assistant, tool, etc.)."""
76
+
77
+ content: str
78
+ """Primary text content of the message.
79
+
80
+ For most message types this is the display text. For TOOL messages it is
81
+ typically empty because the tool's identity comes from `tool_name` /
82
+ `tool_args` instead.
83
+ """
84
+
85
+ id: str = field(default_factory=lambda: f"msg-{uuid.uuid4().hex[:8]}")
86
+ """Unique identifier used to match the dataclass to its DOM widget."""
87
+
88
+ timestamp: float = field(default_factory=time)
89
+ """Unix epoch timestamp of when the message was created."""
90
+
91
+ # TOOL message fields - only populated for TOOL messages
92
+ tool_name: str | None = None
93
+ """Name of the tool that was called."""
94
+
95
+ tool_args: dict[str, Any] | None = None
96
+ """Arguments passed to the tool call."""
97
+
98
+ tool_status: ToolStatus | None = None
99
+ """Current execution status of the tool call."""
100
+
101
+ tool_output: str | None = None
102
+ """Output returned by the tool after execution."""
103
+
104
+ tool_expanded: bool = False
105
+ """Whether the tool output section is expanded in the UI."""
106
+
107
+ # ---
108
+
109
+ diff_file_path: str | None = None
110
+ """File path associated with the diff (DIFF messages only)."""
111
+
112
+ # SKILL message fields - only populated for SKILL messages
113
+ skill_name: str | None = None
114
+ """Name of the skill that was invoked."""
115
+
116
+ skill_description: str | None = None
117
+ """Short description of the skill."""
118
+
119
+ skill_source: str | None = None
120
+ """Origin of the skill (e.g., `'built-in'`, `'user'`, `'project'`)."""
121
+
122
+ skill_args: str | None = None
123
+ """User-provided arguments to the skill invocation."""
124
+
125
+ skill_body: str | None = None
126
+ """Full SKILL.md content sent to the agent."""
127
+
128
+ skill_expanded: bool = False
129
+ """Whether the skill body is expanded in the UI."""
130
+
131
+ is_streaming: bool = False
132
+ """Whether the message is still being streamed.
133
+
134
+ While `True`, the corresponding widget is actively receiving content
135
+ chunks and should not be pruned or re-hydrated.
136
+ """
137
+
138
+ height_hint: int | None = None
139
+ """Cached widget height in terminal rows for scroll position estimation.
140
+
141
+ When `_hydrate_messages_above` inserts widgets above the viewport it needs
142
+ to adjust the scroll offset so the user's view doesn't jump. Currently this
143
+ uses a fixed estimate (5 rows per message). Caching the actual rendered
144
+ height here after first mount would make that estimate accurate, especially
145
+ for tall messages like diffs or long assistant responses.
146
+
147
+ Not yet populated — see `_hydrate_messages_above` in `app.py`.
148
+ """
149
+
150
+ def __post_init__(self) -> None:
151
+ """Validate type-field coherence after construction.
152
+
153
+ Raises:
154
+ ValueError: If a TOOL message is missing `tool_name` or a SKILL
155
+ message is missing `skill_name`.
156
+ """
157
+ if self.type == MessageType.TOOL and not self.tool_name:
158
+ msg = "TOOL messages must have a tool_name"
159
+ raise ValueError(msg)
160
+ if self.type == MessageType.SKILL and not self.skill_name:
161
+ msg = "SKILL messages must have a skill_name"
162
+ raise ValueError(msg)
163
+
164
+ def to_widget(self) -> Widget:
165
+ """Recreate a widget from this message data.
166
+
167
+ Returns:
168
+ The appropriate message widget for this data.
169
+ """
170
+ # Import here to avoid circular imports
171
+ from docagent_cli.widgets.messages import (
172
+ AppMessage,
173
+ AssistantMessage,
174
+ DiffMessage,
175
+ ErrorMessage,
176
+ SkillMessage,
177
+ SummarizationMessage,
178
+ ToolCallMessage,
179
+ UserMessage,
180
+ )
181
+
182
+ match self.type:
183
+ case MessageType.USER:
184
+ return UserMessage(self.content, id=self.id)
185
+
186
+ case MessageType.ASSISTANT:
187
+ return AssistantMessage(self.content, id=self.id)
188
+
189
+ case MessageType.TOOL:
190
+ widget = ToolCallMessage(
191
+ self.tool_name or "unknown",
192
+ self.tool_args,
193
+ id=self.id,
194
+ )
195
+ # Deferred state is restored automatically during on_mount
196
+ # via _restore_deferred_state
197
+ widget._deferred_status = self.tool_status
198
+ widget._deferred_output = self.tool_output
199
+ widget._deferred_expanded = self.tool_expanded
200
+ return widget
201
+
202
+ case MessageType.SKILL:
203
+ widget = SkillMessage(
204
+ skill_name=self.skill_name or "unknown",
205
+ description=self.skill_description or "",
206
+ source=self.skill_source or "",
207
+ body=self.skill_body or "",
208
+ args=self.skill_args or "",
209
+ id=self.id,
210
+ )
211
+ widget._deferred_expanded = self.skill_expanded
212
+ return widget
213
+
214
+ case MessageType.ERROR:
215
+ return ErrorMessage(self.content, id=self.id)
216
+
217
+ case MessageType.APP:
218
+ return AppMessage(self.content, id=self.id)
219
+
220
+ case MessageType.SUMMARIZATION:
221
+ return SummarizationMessage(self.content, id=self.id)
222
+
223
+ case MessageType.DIFF:
224
+ return DiffMessage(
225
+ self.content,
226
+ file_path=self.diff_file_path or "",
227
+ id=self.id,
228
+ )
229
+
230
+ case _:
231
+ logger.warning(
232
+ "Unknown MessageType %r for message %s, falling back to AppMessage",
233
+ self.type,
234
+ self.id,
235
+ )
236
+ return AppMessage(self.content, id=self.id)
237
+
238
+ @classmethod
239
+ def from_widget(cls, widget: Widget) -> MessageData:
240
+ """Create MessageData from an existing widget.
241
+
242
+ Args:
243
+ widget: The message widget to serialize.
244
+
245
+ Returns:
246
+ MessageData containing all the widget's state.
247
+ """
248
+ # Deferred: prevents import-order issue — both modules live in the
249
+ # widgets package, and messages is re-exported from widgets/__init__.
250
+ from docagent_cli.widgets.messages import (
251
+ AppMessage,
252
+ AssistantMessage,
253
+ DiffMessage,
254
+ ErrorMessage,
255
+ SkillMessage,
256
+ SummarizationMessage,
257
+ ToolCallMessage,
258
+ UserMessage,
259
+ )
260
+
261
+ widget_id = widget.id or f"msg-{uuid.uuid4().hex[:8]}"
262
+
263
+ if isinstance(widget, SkillMessage):
264
+ return cls(
265
+ type=MessageType.SKILL,
266
+ content="",
267
+ id=widget_id,
268
+ skill_name=widget._skill_name,
269
+ skill_description=widget._description,
270
+ skill_source=widget._source,
271
+ skill_body=widget._body,
272
+ skill_args=widget._args,
273
+ skill_expanded=widget._expanded,
274
+ )
275
+
276
+ if isinstance(widget, UserMessage):
277
+ return cls(
278
+ type=MessageType.USER,
279
+ content=widget._content,
280
+ id=widget_id,
281
+ )
282
+
283
+ if isinstance(widget, AssistantMessage):
284
+ return cls(
285
+ type=MessageType.ASSISTANT,
286
+ content=widget._content,
287
+ id=widget_id,
288
+ is_streaming=widget._stream is not None,
289
+ )
290
+
291
+ if isinstance(widget, ToolCallMessage):
292
+ tool_status: ToolStatus | None = None
293
+ if widget._status:
294
+ try:
295
+ tool_status = ToolStatus(widget._status)
296
+ except ValueError:
297
+ logger.warning(
298
+ "Unknown tool status %r for widget %s",
299
+ widget._status,
300
+ widget_id,
301
+ )
302
+
303
+ return cls(
304
+ type=MessageType.TOOL,
305
+ content="", # Tool messages don't have simple content
306
+ id=widget_id,
307
+ tool_name=widget._tool_name,
308
+ tool_args=widget._args,
309
+ tool_status=tool_status,
310
+ tool_output=widget._output,
311
+ tool_expanded=widget._expanded,
312
+ )
313
+
314
+ if isinstance(widget, ErrorMessage):
315
+ return cls(
316
+ type=MessageType.ERROR,
317
+ content=widget._content,
318
+ id=widget_id,
319
+ )
320
+
321
+ # Check specialized subclasses before AppMessage so we keep their type
322
+ # when serializing and can restore their specific styling later.
323
+ if isinstance(widget, DiffMessage):
324
+ return cls(
325
+ type=MessageType.DIFF,
326
+ content=widget._diff_content,
327
+ id=widget_id,
328
+ diff_file_path=widget._file_path,
329
+ )
330
+
331
+ if isinstance(widget, SummarizationMessage):
332
+ return cls(
333
+ type=MessageType.SUMMARIZATION,
334
+ content=str(widget._content),
335
+ id=widget_id,
336
+ )
337
+
338
+ if isinstance(widget, AppMessage):
339
+ return cls(
340
+ type=MessageType.APP,
341
+ content=str(widget._content),
342
+ id=widget_id,
343
+ )
344
+
345
+ logger.warning(
346
+ "Unknown widget type %s (id=%s), storing as APP message",
347
+ type(widget).__name__,
348
+ widget_id,
349
+ )
350
+ return cls(
351
+ type=MessageType.APP,
352
+ content=f"[Unknown widget: {type(widget).__name__}]",
353
+ id=widget_id,
354
+ )
355
+
356
+
357
+ class MessageStore:
358
+ """Manages message data and widget window for virtualization.
359
+
360
+ This class stores all messages as data and manages a sliding window
361
+ of widgets that are actually mounted in the DOM.
362
+
363
+ Attributes:
364
+ WINDOW_SIZE: Maximum number of widgets to keep in DOM.
365
+
366
+ Balances DOM performance with smooth scrolling experience.
367
+ HYDRATE_BUFFER: Number of messages to hydrate when scrolling near edge.
368
+
369
+ Provides enough buffer to avoid visible loading pauses.
370
+ """
371
+
372
+ WINDOW_SIZE: int = 50
373
+ HYDRATE_BUFFER: int = 15
374
+
375
+ def __init__(self) -> None:
376
+ """Initialize the message store."""
377
+ self._messages: list[MessageData] = []
378
+ self._visible_start: int = 0
379
+ self._visible_end: int = 0
380
+
381
+ # Track active streaming message - never archive this
382
+ self._active_message_id: str | None = None
383
+
384
+ @property
385
+ def total_count(self) -> int:
386
+ """Total number of messages stored."""
387
+ return len(self._messages)
388
+
389
+ @property
390
+ def visible_count(self) -> int:
391
+ """Number of messages currently visible (as widgets)."""
392
+ return self._visible_end - self._visible_start
393
+
394
+ @property
395
+ def has_messages_above(self) -> bool:
396
+ """Check if there are archived messages above the visible window."""
397
+ return self._visible_start > 0
398
+
399
+ @property
400
+ def has_messages_below(self) -> bool:
401
+ """Check if there are archived messages below the visible window."""
402
+ return self._visible_end < len(self._messages)
403
+
404
+ def append(self, message: MessageData) -> None:
405
+ """Add a new message to the store.
406
+
407
+ Args:
408
+ message: The message data to add.
409
+ """
410
+ self._messages.append(message)
411
+ self._visible_end = len(self._messages)
412
+
413
+ def bulk_load(
414
+ self, messages: list[MessageData]
415
+ ) -> tuple[list[MessageData], list[MessageData]]:
416
+ """Load many messages at once, keeping only the tail visible.
417
+
418
+ This is optimized for thread resumption: all messages are stored as
419
+ lightweight data, but only the last `WINDOW_SIZE` entries are marked
420
+ visible (i.e. will need DOM widgets).
421
+
422
+ Args:
423
+ messages: Ordered list of message data to load.
424
+
425
+ Returns:
426
+ Tuple of (archived, visible) message lists.
427
+ """
428
+ self._messages.extend(messages)
429
+ total = len(self._messages)
430
+
431
+ if total <= self.WINDOW_SIZE:
432
+ self._visible_start = 0
433
+ else:
434
+ self._visible_start = total - self.WINDOW_SIZE
435
+
436
+ self._visible_end = total
437
+
438
+ archived = self._messages[: self._visible_start]
439
+ visible = self._messages[self._visible_start : self._visible_end]
440
+ return archived, visible
441
+
442
+ def get_message(self, message_id: str) -> MessageData | None:
443
+ """Get a message by its ID.
444
+
445
+ Args:
446
+ message_id: The ID of the message to find.
447
+
448
+ Returns:
449
+ The message data, or None if not found.
450
+ """
451
+ for msg in self._messages:
452
+ if msg.id == message_id:
453
+ return msg
454
+ return None
455
+
456
+ def get_message_at_index(self, index: int) -> MessageData | None:
457
+ """Get a message by its index.
458
+
459
+ Args:
460
+ index: The index of the message.
461
+
462
+ Returns:
463
+ The message data, or None if index is out of bounds.
464
+ """
465
+ if 0 <= index < len(self._messages):
466
+ return self._messages[index]
467
+ return None
468
+
469
+ def update_message(self, message_id: str, **updates: Any) -> bool:
470
+ """Update a message's data.
471
+
472
+ Only fields in `_UPDATABLE_FIELDS` may be updated. Unknown field
473
+ names raise `ValueError` to catch typos early.
474
+
475
+ Args:
476
+ message_id: The ID of the message to update.
477
+ **updates: Fields to update.
478
+
479
+ Returns:
480
+ True if the message was found and updated.
481
+
482
+ Raises:
483
+ ValueError: If any key in `updates` is not in the updatable
484
+ allowlist.
485
+ """
486
+ unknown = set(updates) - _UPDATABLE_FIELDS
487
+ if unknown:
488
+ msg = f"Cannot update unknown or protected fields: {unknown}"
489
+ raise ValueError(msg)
490
+
491
+ for msg_data in self._messages:
492
+ if msg_data.id == message_id:
493
+ for key, value in updates.items():
494
+ setattr(msg_data, key, value)
495
+ return True
496
+ return False
497
+
498
+ def set_active_message(self, message_id: str | None) -> None:
499
+ """Set the currently active (streaming) message.
500
+
501
+ Active messages are never archived.
502
+
503
+ Args:
504
+ message_id: The ID of the active message, or None to clear.
505
+ """
506
+ self._active_message_id = message_id
507
+
508
+ def is_active(self, message_id: str) -> bool:
509
+ """Check if a message is the active streaming message.
510
+
511
+ Args:
512
+ message_id: The message ID to check.
513
+
514
+ Returns:
515
+ True if this is the active message.
516
+ """
517
+ return message_id == self._active_message_id
518
+
519
+ def window_exceeded(self) -> bool:
520
+ """Check if the visible window exceeds the maximum size.
521
+
522
+ Returns:
523
+ True if we should prune some widgets.
524
+ """
525
+ return self.visible_count > self.WINDOW_SIZE
526
+
527
+ def get_messages_to_prune(self, count: int | None = None) -> list[MessageData]:
528
+ """Get the oldest visible messages that should be pruned.
529
+
530
+ Returns a contiguous run of messages from the START of the visible
531
+ window. Stops at the active streaming message to avoid creating gaps
532
+ in the visible window (which would desync store state from the DOM).
533
+
534
+ Args:
535
+ count: Number of messages to prune, or None to prune
536
+ enough to get back to WINDOW_SIZE.
537
+
538
+ Returns:
539
+ List of messages to prune (remove widgets for).
540
+ """
541
+ if count is None:
542
+ count = max(0, self.visible_count - self.WINDOW_SIZE)
543
+
544
+ if count <= 0:
545
+ return []
546
+
547
+ to_prune: list[MessageData] = []
548
+ idx = self._visible_start
549
+
550
+ while len(to_prune) < count and idx < self._visible_end:
551
+ msg = self._messages[idx]
552
+ # Stop at the active message to keep the window contiguous
553
+ if msg.id == self._active_message_id:
554
+ break
555
+ to_prune.append(msg)
556
+ idx += 1
557
+
558
+ return to_prune
559
+
560
+ def mark_pruned(self, message_ids: list[str]) -> None:
561
+ """Mark messages as pruned (widgets removed).
562
+
563
+ Advances `_visible_start` past consecutive pruned messages at the front
564
+ of the window.
565
+
566
+ Args:
567
+ message_ids: IDs of messages that were pruned.
568
+ """
569
+ pruned_set = set(message_ids)
570
+ while (
571
+ self._visible_start < self._visible_end
572
+ and self._messages[self._visible_start].id in pruned_set
573
+ ):
574
+ self._visible_start += 1
575
+
576
+ def get_messages_to_hydrate(self, count: int | None = None) -> list[MessageData]:
577
+ """Get messages above the visible window to hydrate.
578
+
579
+ Args:
580
+ count: Number of messages to hydrate, or None for `HYDRATE_BUFFER`.
581
+
582
+ Returns:
583
+ List of messages to hydrate (create widgets for), in order.
584
+ """
585
+ if count is None:
586
+ count = self.HYDRATE_BUFFER
587
+
588
+ if self._visible_start <= 0:
589
+ return []
590
+
591
+ hydrate_start = max(0, self._visible_start - count)
592
+ return self._messages[hydrate_start : self._visible_start]
593
+
594
+ def mark_hydrated(self, count: int) -> None:
595
+ """Mark that messages above were hydrated.
596
+
597
+ Args:
598
+ count: Number of messages that were hydrated.
599
+ """
600
+ self._visible_start = max(0, self._visible_start - count)
601
+
602
+ def should_hydrate_above(
603
+ self, scroll_position: float, viewport_height: int
604
+ ) -> bool:
605
+ """Check if we should hydrate messages above the current view.
606
+
607
+ Args:
608
+ scroll_position: Current scroll Y position.
609
+ viewport_height: Height of the viewport.
610
+
611
+ Returns:
612
+ True if user is scrolling near the top and we have archived messages.
613
+ """
614
+ if not self.has_messages_above:
615
+ return False
616
+
617
+ # Hydrate when within 2x viewport height of the top
618
+ threshold = viewport_height * 2
619
+ return scroll_position < threshold
620
+
621
+ def should_prune_below(
622
+ self, scroll_position: float, viewport_height: int, content_height: int
623
+ ) -> bool:
624
+ """Check if we should prune messages below the current view.
625
+
626
+ Note:
627
+ Not yet integrated into the scroll handler. Intended for future
628
+ pruning of messages below the viewport when the user scrolls far up.
629
+
630
+ Args:
631
+ scroll_position: Current scroll Y position.
632
+ viewport_height: Height of the viewport.
633
+ content_height: Total height of all content.
634
+
635
+ Returns:
636
+ True if we have too many widgets and bottom ones are far from view.
637
+ """
638
+ if self.visible_count <= self.WINDOW_SIZE:
639
+ return False
640
+
641
+ # Only prune if user is far from the bottom
642
+ distance_from_bottom = content_height - scroll_position - viewport_height
643
+ threshold = viewport_height * 3
644
+ return distance_from_bottom > threshold
645
+
646
+ def clear(self) -> None:
647
+ """Clear all messages."""
648
+ self._messages.clear()
649
+ self._visible_start = 0
650
+ self._visible_end = 0
651
+ self._active_message_id = None
652
+
653
+ def get_visible_range(self) -> tuple[int, int]:
654
+ """Get the range of visible message indices.
655
+
656
+ Returns:
657
+ Tuple of (start_index, end_index).
658
+ """
659
+ return (self._visible_start, self._visible_end)
660
+
661
+ def get_all_messages(self) -> list[MessageData]:
662
+ """Get all stored messages.
663
+
664
+ Returns:
665
+ List of all message data (shallow copy).
666
+ """
667
+ return list(self._messages)
668
+
669
+ def get_visible_messages(self) -> list[MessageData]:
670
+ """Get messages in the visible window.
671
+
672
+ Returns:
673
+ List of visible message data.
674
+ """
675
+ return self._messages[self._visible_start : self._visible_end]