python-hwpx 2.24.1__tar.gz → 2.29.1__tar.gz

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 (354) hide show
  1. {python_hwpx-2.24.1/src/python_hwpx.egg-info → python_hwpx-2.29.1}/PKG-INFO +3 -1
  2. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/pyproject.toml +4 -1
  3. python_hwpx-2.29.1/src/hwpx/agent/__init__.py +99 -0
  4. python_hwpx-2.29.1/src/hwpx/agent/blueprint/__init__.py +58 -0
  5. python_hwpx-2.29.1/src/hwpx/agent/blueprint/bundle.py +282 -0
  6. python_hwpx-2.29.1/src/hwpx/agent/blueprint/catalog.py +136 -0
  7. python_hwpx-2.29.1/src/hwpx/agent/blueprint/dump.py +521 -0
  8. python_hwpx-2.29.1/src/hwpx/agent/blueprint/mapping.py +312 -0
  9. python_hwpx-2.29.1/src/hwpx/agent/blueprint/model.py +626 -0
  10. python_hwpx-2.29.1/src/hwpx/agent/blueprint/native.py +622 -0
  11. python_hwpx-2.29.1/src/hwpx/agent/blueprint/replay.py +452 -0
  12. python_hwpx-2.29.1/src/hwpx/agent/catalog.py +167 -0
  13. python_hwpx-2.29.1/src/hwpx/agent/cli.py +631 -0
  14. python_hwpx-2.29.1/src/hwpx/agent/commands.py +1401 -0
  15. python_hwpx-2.29.1/src/hwpx/agent/document.py +769 -0
  16. python_hwpx-2.29.1/src/hwpx/agent/model.py +730 -0
  17. python_hwpx-2.29.1/src/hwpx/agent/path.py +155 -0
  18. python_hwpx-2.29.1/src/hwpx/agent/query.py +230 -0
  19. python_hwpx-2.29.1/src/hwpx/benchmark/__init__.py +25 -0
  20. python_hwpx-2.29.1/src/hwpx/benchmark/blind_eval.py +261 -0
  21. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/document.py +17 -1
  22. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/_document_impl.py +16 -14
  23. python_hwpx-2.29.1/src/hwpx/practice/__init__.py +277 -0
  24. python_hwpx-2.29.1/src/hwpx/practice/aggregate.py +947 -0
  25. python_hwpx-2.29.1/src/hwpx/practice/campaign.py +296 -0
  26. python_hwpx-2.29.1/src/hwpx/practice/domain.py +3137 -0
  27. python_hwpx-2.29.1/src/hwpx/practice/dossier.py +78 -0
  28. python_hwpx-2.29.1/src/hwpx/practice/evaluator.py +2359 -0
  29. python_hwpx-2.29.1/src/hwpx/practice/forge.py +436 -0
  30. python_hwpx-2.29.1/src/hwpx/practice/intake.py +230 -0
  31. python_hwpx-2.29.1/src/hwpx/practice/lineage.py +113 -0
  32. python_hwpx-2.29.1/src/hwpx/practice/mutations.py +168 -0
  33. python_hwpx-2.29.1/src/hwpx/practice/registry.py +322 -0
  34. python_hwpx-2.29.1/src/hwpx/practice/run.py +757 -0
  35. python_hwpx-2.29.1/src/hwpx/practice/sanitize.py +154 -0
  36. python_hwpx-2.29.1/src/hwpx/practice/scenario.py +146 -0
  37. python_hwpx-2.29.1/src/hwpx/practice/split.py +249 -0
  38. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/visual/__init__.py +38 -1
  39. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/visual/_render_hwpx_mac.applescript +24 -1
  40. python_hwpx-2.29.1/src/hwpx/visual/fixture_corpus.py +175 -0
  41. python_hwpx-2.29.1/src/hwpx/visual/hancom_worker.py +288 -0
  42. python_hwpx-2.29.1/src/hwpx/visual/page_qa.py +244 -0
  43. python_hwpx-2.29.1/src/hwpx/visual/qa_contracts.py +293 -0
  44. python_hwpx-2.29.1/src/hwpx/visual/qa_metrics.py +236 -0
  45. {python_hwpx-2.24.1 → python_hwpx-2.29.1/src/python_hwpx.egg-info}/PKG-INFO +3 -1
  46. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/python_hwpx.egg-info/SOURCES.txt +64 -1
  47. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/python_hwpx.egg-info/entry_points.txt +1 -0
  48. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/python_hwpx.egg-info/requires.txt +2 -0
  49. python_hwpx-2.29.1/tests/test_agent_blueprint_contracts.py +191 -0
  50. python_hwpx-2.29.1/tests/test_agent_blueprint_dump.py +321 -0
  51. python_hwpx-2.29.1/tests/test_agent_blueprint_replay.py +500 -0
  52. python_hwpx-2.29.1/tests/test_agent_catalog.py +38 -0
  53. python_hwpx-2.29.1/tests/test_agent_cli.py +525 -0
  54. python_hwpx-2.29.1/tests/test_agent_commands.py +1114 -0
  55. python_hwpx-2.29.1/tests/test_agent_contracts.py +239 -0
  56. python_hwpx-2.29.1/tests/test_agent_document.py +201 -0
  57. python_hwpx-2.29.1/tests/test_agent_path_query.py +128 -0
  58. python_hwpx-2.29.1/tests/test_blind_eval_fixture.py +155 -0
  59. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_builder_core.py +2 -8
  60. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_document_formatting.py +7 -24
  61. python_hwpx-2.29.1/tests/test_hancom_render_worker.py +140 -0
  62. python_hwpx-2.29.1/tests/test_practice_campaign_aggregate.py +870 -0
  63. python_hwpx-2.29.1/tests/test_practice_contracts.py +255 -0
  64. python_hwpx-2.29.1/tests/test_practice_domain_evaluator.py +2134 -0
  65. python_hwpx-2.29.1/tests/test_practice_evaluator.py +2100 -0
  66. python_hwpx-2.29.1/tests/test_practice_intake.py +214 -0
  67. python_hwpx-2.29.1/tests/test_practice_run_contracts.py +422 -0
  68. python_hwpx-2.29.1/tests/test_practice_sanitize.py +75 -0
  69. python_hwpx-2.29.1/tests/test_practice_scenario_forge.py +73 -0
  70. python_hwpx-2.29.1/tests/test_practice_scenario_pack.py +170 -0
  71. python_hwpx-2.29.1/tests/test_practice_source_integrity.py +128 -0
  72. python_hwpx-2.29.1/tests/test_practice_split.py +85 -0
  73. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_split_merged_cell.py +4 -0
  74. python_hwpx-2.29.1/tests/test_visual_fixture_corpus.py +88 -0
  75. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_visual_oracle.py +12 -0
  76. python_hwpx-2.29.1/tests/test_visual_qa_contracts.py +102 -0
  77. python_hwpx-2.29.1/tests/test_visual_qa_metrics.py +89 -0
  78. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/LICENSE +0 -0
  79. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/NOTICE +0 -0
  80. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/README.md +0 -0
  81. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/setup.cfg +0 -0
  82. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/__init__.py +0 -0
  83. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/authoring.py +0 -0
  84. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/body_patch.py +0 -0
  85. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/builder/__init__.py +0 -0
  86. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/builder/core.py +0 -0
  87. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/builder/report.py +0 -0
  88. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/conformance/__init__.py +0 -0
  89. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/conformance/badges.py +0 -0
  90. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/conformance/corpus/corpus.json +0 -0
  91. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/conformance/corpus/meeting_summary.hwpx +0 -0
  92. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/conformance/corpus/notice.hwpx +0 -0
  93. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/conformance/corpus/report_table.hwpx +0 -0
  94. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/conformance/corpus.py +0 -0
  95. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/conformance/report.py +0 -0
  96. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/conformance/roundtrip_batch.py +0 -0
  97. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/conformance/runner.py +0 -0
  98. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/data/Skeleton.hwpx +0 -0
  99. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/__init__.py +0 -0
  100. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/_support.py +0 -0
  101. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/composer.py +0 -0
  102. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/harvest.py +0 -0
  103. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/plan.py +0 -0
  104. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profile.py +0 -0
  105. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/application_form/fragments/body.xml +0 -0
  106. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/application_form/fragments/heading.xml +0 -0
  107. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/application_form/fragments/info_table.xml +0 -0
  108. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/application_form/fragments/title.xml +0 -0
  109. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/application_form/profile.json +0 -0
  110. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/application_form/template.hwpx +0 -0
  111. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/home_notice/fragments/body.xml +0 -0
  112. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/home_notice/fragments/heading.xml +0 -0
  113. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/home_notice/fragments/title.xml +0 -0
  114. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/home_notice/profile.json +0 -0
  115. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/home_notice/template.hwpx +0 -0
  116. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/official_notice/fragments/body.xml +0 -0
  117. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/official_notice/fragments/heading.xml +0 -0
  118. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/official_notice/fragments/info_table.xml +0 -0
  119. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/official_notice/fragments/title.xml +0 -0
  120. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/official_notice/profile.json +0 -0
  121. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/official_notice/template.hwpx +0 -0
  122. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/report/fragments/body.xml +0 -0
  123. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/report/fragments/heading.xml +0 -0
  124. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/report/fragments/info_table.xml +0 -0
  125. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/report/fragments/title.xml +0 -0
  126. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/report/profile.json +0 -0
  127. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/profiles/report/template.hwpx +0 -0
  128. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/design/validator.py +0 -0
  129. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/evalplan_fill.py +0 -0
  130. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/exam/__init__.py +0 -0
  131. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/exam/compose.py +0 -0
  132. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/exam/ir.py +0 -0
  133. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/exam/measure.py +0 -0
  134. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/exam/parser.py +0 -0
  135. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/exam/profile.py +0 -0
  136. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/fill_residue.py +0 -0
  137. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/form_fill.py +0 -0
  138. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/form_fit/__init__.py +0 -0
  139. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/form_fit/apply.py +0 -0
  140. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/form_fit/engine.py +0 -0
  141. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/form_fit/measure.py +0 -0
  142. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/form_fit/policy.py +0 -0
  143. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/form_fit/report.py +0 -0
  144. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/form_fit/seal.py +0 -0
  145. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/form_fit/wordbox.py +0 -0
  146. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/formfill_quality.py +0 -0
  147. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/guidance_scan.py +0 -0
  148. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/ingest/__init__.py +0 -0
  149. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/ingest/base.py +0 -0
  150. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/ingest/hwpx_converter.py +0 -0
  151. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/layout/__init__.py +0 -0
  152. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/layout/lint.py +0 -0
  153. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/layout/report.py +0 -0
  154. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/opc/package.py +0 -0
  155. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/opc/relationships.py +0 -0
  156. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/opc/security.py +0 -0
  157. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/opc/xml_utils.py +0 -0
  158. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/__init__.py +0 -0
  159. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/body.py +0 -0
  160. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/canonical_defaults.py +0 -0
  161. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/common.py +0 -0
  162. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/document.py +0 -0
  163. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/header.py +0 -0
  164. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/header_part.py +0 -0
  165. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/memo.py +0 -0
  166. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/namespaces.py +0 -0
  167. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/numbering.py +0 -0
  168. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/objects.py +0 -0
  169. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/paragraph.py +0 -0
  170. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/parser.py +0 -0
  171. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/run.py +0 -0
  172. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/schema.py +0 -0
  173. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/section.py +0 -0
  174. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/simple_parts.py +0 -0
  175. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/table.py +0 -0
  176. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/oxml/utils.py +0 -0
  177. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/package.py +0 -0
  178. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/patch.py +0 -0
  179. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/presets/__init__.py +0 -0
  180. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/presets/proposal.py +0 -0
  181. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/py.typed +0 -0
  182. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/quality/__init__.py +0 -0
  183. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/quality/ledger.py +0 -0
  184. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/quality/policy.py +0 -0
  185. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/quality/report.py +0 -0
  186. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/quality/save_pipeline.py +0 -0
  187. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/table_patch.py +0 -0
  188. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/template_formfit.py +0 -0
  189. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/templates.py +0 -0
  190. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/__init__.py +0 -0
  191. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/_schemas/header.xsd +0 -0
  192. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/_schemas/section.xsd +0 -0
  193. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/advanced_generators.py +0 -0
  194. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/archive_cli.py +0 -0
  195. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/doc_diff.py +0 -0
  196. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/exporter.py +0 -0
  197. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/fuzz/__init__.py +0 -0
  198. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/fuzz/__main__.py +0 -0
  199. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/fuzz/catalog.py +0 -0
  200. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/fuzz/generator.py +0 -0
  201. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/fuzz/minimize.py +0 -0
  202. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/fuzz/runner.py +0 -0
  203. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/generic_inventory.py +0 -0
  204. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/id_integrity.py +0 -0
  205. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/idempotence.py +0 -0
  206. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/ir_equality.py +0 -0
  207. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/layout_preview.py +0 -0
  208. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/mail_merge.py +0 -0
  209. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/markdown_export.py +0 -0
  210. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/object_finder.py +0 -0
  211. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/official_lint.py +0 -0
  212. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/package_reconcile.py +0 -0
  213. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/package_validator.py +0 -0
  214. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/page_guard.py +0 -0
  215. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/pii.py +0 -0
  216. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/read_fidelity.py +0 -0
  217. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/recover.py +0 -0
  218. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/redline.py +0 -0
  219. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/repair.py +0 -0
  220. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/report_parser.py +0 -0
  221. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/report_utils.py +0 -0
  222. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/roundtrip_diff.py +0 -0
  223. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/style_profile.py +0 -0
  224. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/table_cleanup.py +0 -0
  225. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/table_compute.py +0 -0
  226. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/table_navigation.py +0 -0
  227. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/template_analyzer.py +0 -0
  228. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/text_extract_cli.py +0 -0
  229. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/text_extractor.py +0 -0
  230. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/toc_author.py +0 -0
  231. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/toc_fidelity.py +0 -0
  232. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/tools/validator.py +0 -0
  233. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/visual/_hancom_open_rate.ps1 +0 -0
  234. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/visual/_refresh_hwpx_mac.applescript +0 -0
  235. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/visual/_render_hwpx.ps1 +0 -0
  236. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/visual/detectors.py +0 -0
  237. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/visual/diff.py +0 -0
  238. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/visual/masks.py +0 -0
  239. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/visual/oracle.py +0 -0
  240. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/hwpx/visual/report.py +0 -0
  241. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/python_hwpx.egg-info/dependency_links.txt +0 -0
  242. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/src/python_hwpx.egg-info/top_level.txt +0 -0
  243. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_advanced_generators.py +0 -0
  244. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_authoring_profile_routing.py +0 -0
  245. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_authoring_profile_routing_oracle.py +0 -0
  246. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_authoring_render_check.py +0 -0
  247. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_body_patch.py +0 -0
  248. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_builder_plan_v2.py +0 -0
  249. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_builder_vertical_slice.py +0 -0
  250. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_cell_line_spacing.py +0 -0
  251. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_comment_node_robustness.py +0 -0
  252. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_conformance.py +0 -0
  253. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_corpus_read_fidelity.py +0 -0
  254. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_coverage_promotion.py +0 -0
  255. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_coverage_targets.py +0 -0
  256. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_design_builder.py +0 -0
  257. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_deviations_registry.py +0 -0
  258. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_doc_diff.py +0 -0
  259. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_document_context_manager.py +0 -0
  260. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_document_plan.py +0 -0
  261. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_document_plan_computed_fields.py +0 -0
  262. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_document_save_api.py +0 -0
  263. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_evalplan_fill.py +0 -0
  264. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_exam_compose.py +0 -0
  265. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_exam_compose_oracle.py +0 -0
  266. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_exam_fixtures.py +0 -0
  267. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_exam_ir.py +0 -0
  268. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_exam_measure.py +0 -0
  269. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_exam_parser.py +0 -0
  270. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_exam_profile.py +0 -0
  271. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_existing_document_format_editing.py +0 -0
  272. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_fill_residue.py +0 -0
  273. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_form_fields.py +0 -0
  274. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_form_fill_split_run.py +0 -0
  275. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_form_fit.py +0 -0
  276. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_form_fit_integration.py +0 -0
  277. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_form_fit_seal.py +0 -0
  278. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_form_fit_seal_placement.py +0 -0
  279. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_form_fit_wordbox.py +0 -0
  280. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_formfill_quality.py +0 -0
  281. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_fuzz_loop.py +0 -0
  282. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_fuzz_regressions.py +0 -0
  283. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_gap_closure_tools.py +0 -0
  284. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_government_report_preset.py +0 -0
  285. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_government_table_profile.py +0 -0
  286. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_guidance_scan.py +0 -0
  287. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_hp_tab_support.py +0 -0
  288. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_hwpxlib_corpus_read.py +0 -0
  289. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_id_generator_range.py +0 -0
  290. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_id_integrity.py +0 -0
  291. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_image_object_workflow.py +0 -0
  292. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_ingest.py +0 -0
  293. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_inline_models.py +0 -0
  294. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_integration_hwpx_compatibility.py +0 -0
  295. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_integration_roundtrip.py +0 -0
  296. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_kordoc_absorption.py +0 -0
  297. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_layout_lint.py +0 -0
  298. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_layout_preview.py +0 -0
  299. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_mail_merge_fit.py +0 -0
  300. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_mail_merge_table_compute.py +0 -0
  301. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_mail_merge_xlsx.py +0 -0
  302. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_markdown_export.py +0 -0
  303. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_memo_and_style_editing.py +0 -0
  304. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_namespace_handling.py +0 -0
  305. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_new_features.py +0 -0
  306. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_official_document_style.py +0 -0
  307. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_official_lint_gongmun_gate.py +0 -0
  308. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_official_lint_tableaware.py +0 -0
  309. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_opc_package.py +0 -0
  310. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_open_safety_corpus.py +0 -0
  311. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_openrate.py +0 -0
  312. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_oxml_parsing.py +0 -0
  313. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_packaging_license_metadata.py +0 -0
  314. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_packaging_py_typed.py +0 -0
  315. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_paragraph_keep_together.py +0 -0
  316. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_paragraph_section_management.py +0 -0
  317. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_pii.py +0 -0
  318. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_pii_structural.py +0 -0
  319. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_pii_wiring.py +0 -0
  320. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_proposal_preset.py +0 -0
  321. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_question_split_detector.py +0 -0
  322. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_read_fidelity.py +0 -0
  323. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_recover_broken_zip.py +0 -0
  324. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_redline_authoring.py +0 -0
  325. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_redline_verify.py +0 -0
  326. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_repair_repack.py +0 -0
  327. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_report_parser.py +0 -0
  328. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_report_utils.py +0 -0
  329. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_repr_snapshots.py +0 -0
  330. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_rhwp_t1_gates.py +0 -0
  331. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_rhwp_t2_verification.py +0 -0
  332. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_roundtrip_fidelity.py +0 -0
  333. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_row_heights.py +0 -0
  334. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_save_pipeline.py +0 -0
  335. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_save_pipeline_no_bypass.py +0 -0
  336. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_section_headers.py +0 -0
  337. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_set_paragraph_format_keep.py +0 -0
  338. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_skeleton_template_ids.py +0 -0
  339. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_split_cell.py +0 -0
  340. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_style_profile.py +0 -0
  341. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_table_cleanup.py +0 -0
  342. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_table_navigation.py +0 -0
  343. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_table_patch.py +0 -0
  344. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_table_patch_dryrun.py +0 -0
  345. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_table_patch_m105.py +0 -0
  346. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_tables_default_border.py +0 -0
  347. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_template_analyzer_enrichment.py +0 -0
  348. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_template_formfit.py +0 -0
  349. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_text_extractor_annotations.py +0 -0
  350. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_toc_author.py +0 -0
  351. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_toc_fidelity.py +0 -0
  352. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_validation_severity.py +0 -0
  353. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_validator_comment_nodes.py +0 -0
  354. {python_hwpx-2.24.1 → python_hwpx-2.29.1}/tests/test_version_metadata.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-hwpx
3
- Version: 2.24.1
3
+ Version: 2.29.1
4
4
  Summary: 한글 없이 HWPX 문서를 열고, 편집하고, 생성하고, 검증하는 Python 자동화 라이브러리
5
5
  Author: python-hwpx Maintainers
6
6
  License-Expression: Apache-2.0
@@ -33,6 +33,8 @@ Requires-Dist: twine>=4.0; extra == "dev"
33
33
  Requires-Dist: pytest>=7.4; extra == "dev"
34
34
  Provides-Extra: test
35
35
  Requires-Dist: build>=1.0; extra == "test"
36
+ Requires-Dist: numpy>=1.26; extra == "test"
37
+ Requires-Dist: pillow>=10.0; extra == "test"
36
38
  Requires-Dist: pytest>=7.4; extra == "test"
37
39
  Requires-Dist: pytest-cov>=5.0; extra == "test"
38
40
  Provides-Extra: typecheck
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-hwpx"
7
- version = "2.24.1"
7
+ version = "2.29.1"
8
8
  description = "한글 없이 HWPX 문서를 열고, 편집하고, 생성하고, 검증하는 Python 자동화 라이브러리"
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  license = "Apache-2.0"
@@ -45,6 +45,8 @@ dev = [
45
45
  ]
46
46
  test = [
47
47
  "build>=1.0",
48
+ "numpy>=1.26",
49
+ "pillow>=10.0",
48
50
  "pytest>=7.4",
49
51
  "pytest-cov>=5.0",
50
52
  ]
@@ -59,6 +61,7 @@ Documentation = "https://airmang.github.io/python-hwpx/"
59
61
  Issues = "https://github.com/airmang/python-hwpx/issues"
60
62
 
61
63
  [project.scripts]
64
+ hwpx = "hwpx.agent.cli:main"
62
65
  hwpx-unpack = "hwpx.tools.archive_cli:unpack_main"
63
66
  hwpx-pack = "hwpx.tools.archive_cli:pack_main"
64
67
  hwpx-validate = "hwpx.tools.validator:main"
@@ -0,0 +1,99 @@
1
+ """Versioned semantic contracts for the HWPX agent document interface."""
2
+
3
+ from .model import (
4
+ AGENT_BATCH_RESULT_SCHEMA,
5
+ AGENT_BATCH_SCHEMA,
6
+ AGENT_CATALOG_SCHEMA,
7
+ AGENT_COMMAND_SCHEMA,
8
+ AGENT_ERROR_SCHEMA,
9
+ AGENT_NODE_SCHEMA,
10
+ AgentBatchResult,
11
+ AgentContractError,
12
+ AgentError,
13
+ AgentNode,
14
+ agent_contract_manifest,
15
+ validate_agent_batch,
16
+ validate_agent_command,
17
+ )
18
+ from .catalog import agent_catalog, agent_json_schemas, catalog_hash, human_help, node_help
19
+ from .commands import apply_document_commands
20
+ from .document import HwpxAgentDocument, NodeRecord
21
+ from .path import PathSegment, SemanticPath, canonicalize_path, parse_path
22
+ from .query import QueryResult, SemanticSelector, parse_selector
23
+ from .blueprint import (
24
+ BLUEPRINT_CATALOG_SCHEMA,
25
+ BLUEPRINT_REPLAY_RESULT_SCHEMA,
26
+ BLUEPRINT_REPLAY_SCHEMA,
27
+ BLUEPRINT_SCHEMA,
28
+ BlueprintBundle,
29
+ BlueprintDumpResult,
30
+ BlueprintReplayResult,
31
+ ReplayPlan,
32
+ blueprint_catalog,
33
+ blueprint_catalog_hash,
34
+ blueprint_hash,
35
+ blueprint_human_help,
36
+ blueprint_json_schemas,
37
+ blueprint_limits,
38
+ build_blueprint_bundle,
39
+ dump_document_blueprint,
40
+ read_blueprint_bundle,
41
+ repack_blueprint_bundle,
42
+ replay_document_blueprint,
43
+ validate_blueprint_manifest,
44
+ validate_replay_request,
45
+ write_blueprint_bundle,
46
+ )
47
+
48
+ __all__ = [
49
+ "AGENT_BATCH_RESULT_SCHEMA",
50
+ "AGENT_BATCH_SCHEMA",
51
+ "AGENT_CATALOG_SCHEMA",
52
+ "AGENT_COMMAND_SCHEMA",
53
+ "AGENT_ERROR_SCHEMA",
54
+ "AGENT_NODE_SCHEMA",
55
+ "BLUEPRINT_CATALOG_SCHEMA",
56
+ "BLUEPRINT_REPLAY_RESULT_SCHEMA",
57
+ "BLUEPRINT_REPLAY_SCHEMA",
58
+ "BLUEPRINT_SCHEMA",
59
+ "AgentBatchResult",
60
+ "AgentContractError",
61
+ "AgentError",
62
+ "AgentNode",
63
+ "BlueprintReplayResult",
64
+ "ReplayPlan",
65
+ "BlueprintBundle",
66
+ "BlueprintDumpResult",
67
+ "HwpxAgentDocument",
68
+ "NodeRecord",
69
+ "PathSegment",
70
+ "QueryResult",
71
+ "SemanticPath",
72
+ "SemanticSelector",
73
+ "agent_catalog",
74
+ "agent_json_schemas",
75
+ "agent_contract_manifest",
76
+ "apply_document_commands",
77
+ "blueprint_catalog",
78
+ "blueprint_catalog_hash",
79
+ "blueprint_hash",
80
+ "blueprint_human_help",
81
+ "blueprint_json_schemas",
82
+ "blueprint_limits",
83
+ "build_blueprint_bundle",
84
+ "canonicalize_path",
85
+ "catalog_hash",
86
+ "human_help",
87
+ "node_help",
88
+ "parse_path",
89
+ "parse_selector",
90
+ "dump_document_blueprint",
91
+ "read_blueprint_bundle",
92
+ "repack_blueprint_bundle",
93
+ "replay_document_blueprint",
94
+ "validate_agent_batch",
95
+ "validate_agent_command",
96
+ "validate_blueprint_manifest",
97
+ "validate_replay_request",
98
+ "write_blueprint_bundle",
99
+ ]
@@ -0,0 +1,58 @@
1
+ """Typed semantic HWPX blueprint contracts."""
2
+
3
+ from .catalog import (
4
+ blueprint_catalog,
5
+ blueprint_catalog_hash,
6
+ blueprint_human_help,
7
+ blueprint_json_schemas,
8
+ )
9
+ from .bundle import (
10
+ BlueprintBundle,
11
+ build_blueprint_bundle,
12
+ read_blueprint_bundle,
13
+ repack_blueprint_bundle,
14
+ write_blueprint_bundle,
15
+ )
16
+ from .dump import BlueprintDumpResult, dump_document_blueprint
17
+ from .mapping import ReplayPlan
18
+ from .replay import replay_document_blueprint
19
+ from .model import (
20
+ BLUEPRINT_CATALOG_SCHEMA,
21
+ BLUEPRINT_REPLAY_RESULT_SCHEMA,
22
+ BLUEPRINT_REPLAY_SCHEMA,
23
+ BLUEPRINT_SCHEMA,
24
+ BlueprintReplayResult,
25
+ blueprint_hash,
26
+ blueprint_limits,
27
+ canonical_manifest_bytes,
28
+ validate_blueprint_manifest,
29
+ validate_replay_request,
30
+ with_blueprint_hash,
31
+ )
32
+
33
+ __all__ = [
34
+ "BLUEPRINT_CATALOG_SCHEMA",
35
+ "BLUEPRINT_REPLAY_RESULT_SCHEMA",
36
+ "BLUEPRINT_REPLAY_SCHEMA",
37
+ "BLUEPRINT_SCHEMA",
38
+ "BlueprintBundle",
39
+ "BlueprintDumpResult",
40
+ "BlueprintReplayResult",
41
+ "ReplayPlan",
42
+ "blueprint_catalog",
43
+ "blueprint_catalog_hash",
44
+ "blueprint_hash",
45
+ "blueprint_human_help",
46
+ "blueprint_json_schemas",
47
+ "blueprint_limits",
48
+ "build_blueprint_bundle",
49
+ "canonical_manifest_bytes",
50
+ "dump_document_blueprint",
51
+ "read_blueprint_bundle",
52
+ "repack_blueprint_bundle",
53
+ "replay_document_blueprint",
54
+ "validate_blueprint_manifest",
55
+ "validate_replay_request",
56
+ "with_blueprint_hash",
57
+ "write_blueprint_bundle",
58
+ ]
@@ -0,0 +1,282 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Deterministic and fail-closed ``.hwpxbp`` bundle I/O."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import hashlib
7
+ import io
8
+ import json
9
+ import os
10
+ import stat
11
+ import tempfile
12
+ import zipfile
13
+ from collections.abc import Mapping
14
+ from dataclasses import dataclass
15
+ from pathlib import Path, PurePosixPath
16
+ from typing import Any
17
+
18
+ from ..model import AgentContractError
19
+ from .model import (
20
+ ASSET_PATH_PATTERN,
21
+ MAX_ASSETS,
22
+ MAX_ASSET_BYTES,
23
+ MAX_MANIFEST_BYTES,
24
+ MAX_TOTAL_ASSET_BYTES,
25
+ canonical_manifest_bytes,
26
+ validate_blueprint_manifest,
27
+ with_blueprint_hash,
28
+ )
29
+
30
+ MANIFEST_PATH = "blueprint.json"
31
+ MAX_BUNDLE_BYTES = MAX_MANIFEST_BYTES + MAX_TOTAL_ASSET_BYTES + 2 * 1024 * 1024
32
+ MAX_COMPRESSION_RATIO = 100
33
+
34
+ ALLOWED_MEDIA_TYPES: dict[str, tuple[str, ...]] = {
35
+ "image/png": ("png",),
36
+ "image/jpeg": ("jpg", "jpeg"),
37
+ "image/gif": ("gif",),
38
+ "image/bmp": ("bmp",),
39
+ "image/tiff": ("tif", "tiff"),
40
+ "image/webp": ("webp",),
41
+ }
42
+
43
+
44
+ @dataclass(frozen=True, slots=True)
45
+ class BlueprintBundle:
46
+ """A fully validated manifest and detached content-addressed assets."""
47
+
48
+ manifest: Mapping[str, Any]
49
+ assets: Mapping[str, bytes]
50
+ bundle_sha256: str
51
+ size: int
52
+
53
+
54
+ def _error(code: str, message: str, *, target: str = "bundle") -> AgentContractError:
55
+ return AgentContractError(code, message, target=target)
56
+
57
+
58
+ def _json_without_duplicate_keys(data: bytes) -> dict[str, Any]:
59
+ def pairs_hook(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
60
+ result: dict[str, Any] = {}
61
+ for key, value in pairs:
62
+ if key in result:
63
+ raise _error("invariant_violation", f"duplicate JSON field: {key}", target=MANIFEST_PATH)
64
+ result[key] = value
65
+ return result
66
+
67
+ try:
68
+ value = json.loads(data.decode("utf-8"), object_pairs_hook=pairs_hook)
69
+ except AgentContractError:
70
+ raise
71
+ except (UnicodeDecodeError, json.JSONDecodeError) as exc:
72
+ raise _error("invalid_syntax", "blueprint.json is not strict UTF-8 JSON", target=MANIFEST_PATH) from exc
73
+ if not isinstance(value, dict):
74
+ raise _error("invalid_syntax", "blueprint.json must contain one object", target=MANIFEST_PATH)
75
+ return value
76
+
77
+
78
+ def _validate_entry_name(name: str) -> None:
79
+ if not name or "\\" in name or "\x00" in name:
80
+ raise _error("verification_failed", "bundle entry path is not normalized", target=name or "bundle")
81
+ path = PurePosixPath(name)
82
+ if path.is_absolute() or name.startswith("/") or any(part in {"", ".", ".."} for part in path.parts):
83
+ raise _error("verification_failed", "bundle entry path is unsafe", target=name)
84
+ if name != MANIFEST_PATH and not ASSET_PATH_PATTERN.fullmatch(name):
85
+ raise _error("unsupported_content", "bundle contains an unknown or forbidden entry", target=name)
86
+
87
+
88
+ def _validate_zip_info(info: zipfile.ZipInfo) -> None:
89
+ _validate_entry_name(info.filename)
90
+ if info.is_dir():
91
+ raise _error("unsupported_content", "directory entries are forbidden", target=info.filename)
92
+ mode = (info.external_attr >> 16) & 0xFFFF
93
+ if mode and stat.S_ISLNK(mode):
94
+ raise _error("unsupported_content", "symlink entries are forbidden", target=info.filename)
95
+ if info.flag_bits & 0x1:
96
+ raise _error("unsupported_content", "encrypted bundle entries are forbidden", target=info.filename)
97
+ if info.compress_type not in {zipfile.ZIP_STORED, zipfile.ZIP_DEFLATED}:
98
+ raise _error("unsupported_content", "bundle compression method is forbidden", target=info.filename)
99
+ limit = MAX_MANIFEST_BYTES if info.filename == MANIFEST_PATH else MAX_ASSET_BYTES
100
+ if info.file_size > limit:
101
+ raise _error("resource_limit", "bundle entry exceeds its byte limit", target=info.filename)
102
+ if info.file_size and info.compress_size == 0:
103
+ raise _error("resource_limit", "bundle entry has an invalid compression ratio", target=info.filename)
104
+ if info.compress_size and info.file_size / info.compress_size > MAX_COMPRESSION_RATIO:
105
+ raise _error("resource_limit", "bundle entry exceeds the decompression-ratio limit", target=info.filename)
106
+
107
+
108
+ def _sniff_media_type(data: bytes) -> str | None:
109
+ if data.startswith(b"\x89PNG\r\n\x1a\n"):
110
+ return "image/png"
111
+ if data.startswith(b"\xff\xd8\xff"):
112
+ return "image/jpeg"
113
+ if data.startswith((b"GIF87a", b"GIF89a")):
114
+ return "image/gif"
115
+ if data.startswith(b"BM"):
116
+ return "image/bmp"
117
+ if data.startswith((b"II*\x00", b"MM\x00*")):
118
+ return "image/tiff"
119
+ if len(data) >= 12 and data[:4] == b"RIFF" and data[8:12] == b"WEBP":
120
+ return "image/webp"
121
+ return None
122
+
123
+
124
+ def _validated_assets(
125
+ manifest: Mapping[str, Any], assets: Mapping[str, bytes]
126
+ ) -> dict[str, bytes]:
127
+ declared = {str(item["assetPath"]): dict(item) for item in manifest["resources"]}
128
+ if set(assets) != set(declared):
129
+ raise _error(
130
+ "invariant_violation",
131
+ "bundle assets do not exactly match manifest resources",
132
+ target="resources",
133
+ )
134
+ if len(assets) > MAX_ASSETS:
135
+ raise _error("resource_limit", "asset count exceeds limit", target="resources")
136
+ total = 0
137
+ detached: dict[str, bytes] = {}
138
+ for path in sorted(assets):
139
+ _validate_entry_name(path)
140
+ payload = assets[path]
141
+ if not isinstance(payload, bytes):
142
+ raise _error("invalid_syntax", "asset payload must be bytes", target=path)
143
+ total += len(payload)
144
+ if len(payload) > MAX_ASSET_BYTES or total > MAX_TOTAL_ASSET_BYTES:
145
+ raise _error("resource_limit", "asset bytes exceed limit", target=path)
146
+ record = declared[path]
147
+ digest = "sha256:" + hashlib.sha256(payload).hexdigest()
148
+ if digest != record["sha256"] or len(payload) != record["size"]:
149
+ raise _error("verification_failed", "asset hash or size mismatch", target=path)
150
+ media_type = str(record["mediaType"])
151
+ suffix = path.rsplit(".", 1)[-1]
152
+ if media_type not in ALLOWED_MEDIA_TYPES or suffix not in ALLOWED_MEDIA_TYPES[media_type]:
153
+ raise _error("unsupported_content", "asset extension/MIME is not allow-listed", target=path)
154
+ if _sniff_media_type(payload) != media_type:
155
+ raise _error("verification_failed", "asset bytes do not match declared MIME", target=path)
156
+ detached[path] = bytes(payload)
157
+ return detached
158
+
159
+
160
+ def _zip_info(name: str) -> zipfile.ZipInfo:
161
+ info = zipfile.ZipInfo(name, date_time=(1980, 1, 1, 0, 0, 0))
162
+ info.compress_type = zipfile.ZIP_STORED
163
+ info.create_system = 0
164
+ info.external_attr = 0
165
+ info.internal_attr = 0
166
+ info.flag_bits = 0
167
+ return info
168
+
169
+
170
+ def build_blueprint_bundle(
171
+ manifest: Mapping[str, Any], assets: Mapping[str, bytes] | None = None
172
+ ) -> bytes:
173
+ """Return canonical bundle bytes for an already hashed manifest."""
174
+
175
+ checked = validate_blueprint_manifest(manifest)
176
+ checked_assets = _validated_assets(checked, assets or {})
177
+ manifest_bytes = canonical_manifest_bytes(checked, include_hash=True)
178
+ stream = io.BytesIO()
179
+ with zipfile.ZipFile(stream, "w", allowZip64=False) as archive:
180
+ archive.writestr(_zip_info(MANIFEST_PATH), manifest_bytes)
181
+ for name, payload in checked_assets.items():
182
+ archive.writestr(_zip_info(name), payload)
183
+ result = stream.getvalue()
184
+ if len(result) > MAX_BUNDLE_BYTES:
185
+ raise _error("resource_limit", "blueprint bundle exceeds total byte limit")
186
+ return result
187
+
188
+
189
+ def write_blueprint_bundle(
190
+ destination: str | os.PathLike[str],
191
+ manifest: Mapping[str, Any],
192
+ assets: Mapping[str, bytes] | None = None,
193
+ *,
194
+ overwrite: bool = False,
195
+ ) -> BlueprintBundle:
196
+ """Atomically write one deterministic bundle and return its validated view."""
197
+
198
+ path = Path(destination)
199
+ if path.suffix.casefold() != ".hwpxbp":
200
+ raise _error("invalid_syntax", "blueprint output must use .hwpxbp", target="output")
201
+ if path.exists() and not overwrite:
202
+ raise _error("identity_collision", "blueprint output already exists", target=str(path))
203
+ data = build_blueprint_bundle(manifest, assets)
204
+ path.parent.mkdir(parents=True, exist_ok=True)
205
+ descriptor, temp_name = tempfile.mkstemp(prefix=f".{path.name}.", suffix=".tmp", dir=path.parent)
206
+ try:
207
+ with os.fdopen(descriptor, "wb") as handle:
208
+ handle.write(data)
209
+ handle.flush()
210
+ os.fsync(handle.fileno())
211
+ if path.exists() and not overwrite:
212
+ raise _error("identity_collision", "blueprint output already exists", target=str(path))
213
+ os.replace(temp_name, path)
214
+ except Exception:
215
+ try:
216
+ os.unlink(temp_name)
217
+ except FileNotFoundError:
218
+ pass
219
+ raise
220
+ return read_blueprint_bundle(data)
221
+
222
+
223
+ def read_blueprint_bundle(source: str | os.PathLike[str] | bytes) -> BlueprintBundle:
224
+ """Validate a complete bundle in memory before returning any materialized data."""
225
+
226
+ data = bytes(source) if isinstance(source, bytes) else Path(source).read_bytes()
227
+ if len(data) > MAX_BUNDLE_BYTES:
228
+ raise _error("resource_limit", "blueprint bundle exceeds total byte limit")
229
+ try:
230
+ with zipfile.ZipFile(io.BytesIO(data), "r") as archive:
231
+ infos = archive.infolist()
232
+ names = [info.filename for info in infos]
233
+ if len(names) != len(set(names)):
234
+ raise _error("invariant_violation", "bundle contains duplicate entry paths")
235
+ if names.count(MANIFEST_PATH) != 1:
236
+ raise _error("invariant_violation", "bundle must contain exactly one blueprint.json")
237
+ if len(infos) > MAX_ASSETS + 1:
238
+ raise _error("resource_limit", "bundle entry count exceeds limit")
239
+ for info in infos:
240
+ _validate_zip_info(info)
241
+ if sum(info.file_size for info in infos if info.filename != MANIFEST_PATH) > MAX_TOTAL_ASSET_BYTES:
242
+ raise _error("resource_limit", "bundle assets exceed total byte limit", target="resources")
243
+ manifest_data = archive.read(MANIFEST_PATH)
244
+ manifest = validate_blueprint_manifest(_json_without_duplicate_keys(manifest_data))
245
+ asset_names = sorted(name for name in names if name != MANIFEST_PATH)
246
+ assets = {name: archive.read(name) for name in asset_names}
247
+ except AgentContractError:
248
+ raise
249
+ except (OSError, zipfile.BadZipFile, zipfile.LargeZipFile, RuntimeError) as exc:
250
+ raise _error("invalid_syntax", "invalid .hwpxbp ZIP container") from exc
251
+ checked_assets = _validated_assets(manifest, assets)
252
+ return BlueprintBundle(
253
+ manifest=manifest,
254
+ assets=checked_assets,
255
+ bundle_sha256="sha256:" + hashlib.sha256(data).hexdigest(),
256
+ size=len(data),
257
+ )
258
+
259
+
260
+ def repack_blueprint_bundle(
261
+ source: str | os.PathLike[str] | bytes,
262
+ destination: str | os.PathLike[str],
263
+ manifest: Mapping[str, Any],
264
+ *,
265
+ overwrite: bool = False,
266
+ ) -> BlueprintBundle:
267
+ """Safely repack edited typed JSON while preserving only validated assets."""
268
+
269
+ original = read_blueprint_bundle(source)
270
+ rehashed = with_blueprint_hash(manifest)
271
+ return write_blueprint_bundle(destination, rehashed, original.assets, overwrite=overwrite)
272
+
273
+
274
+ __all__ = [
275
+ "ALLOWED_MEDIA_TYPES",
276
+ "BlueprintBundle",
277
+ "MANIFEST_PATH",
278
+ "build_blueprint_bundle",
279
+ "read_blueprint_bundle",
280
+ "repack_blueprint_bundle",
281
+ "write_blueprint_bundle",
282
+ ]
@@ -0,0 +1,136 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Shared blueprint capability, limit, schema, and help catalog."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import hashlib
7
+ import json
8
+ from typing import Any
9
+
10
+ from ..model import AGENT_CATALOG_SCHEMA, NODE_KINDS
11
+ from .model import (
12
+ BLUEPRINT_CATALOG_SCHEMA,
13
+ BLUEPRINT_MODES,
14
+ BLUEPRINT_REPLAY_RESULT_SCHEMA,
15
+ BLUEPRINT_REPLAY_SCHEMA,
16
+ BLUEPRINT_SCHEMA,
17
+ FIDELITY_LEVELS,
18
+ blueprint_limits,
19
+ )
20
+
21
+
22
+ def blueprint_catalog() -> dict[str, Any]:
23
+ return {
24
+ "schemaVersion": BLUEPRINT_CATALOG_SCHEMA,
25
+ "agentCatalogVersion": AGENT_CATALOG_SCHEMA,
26
+ "schemas": {
27
+ "blueprint": BLUEPRINT_SCHEMA,
28
+ "replay": BLUEPRINT_REPLAY_SCHEMA,
29
+ "replayResult": BLUEPRINT_REPLAY_RESULT_SCHEMA,
30
+ },
31
+ "modes": list(BLUEPRINT_MODES),
32
+ "fidelity": list(FIDELITY_LEVELS),
33
+ "kinds": [kind for kind in NODE_KINDS if kind != "unsupported"],
34
+ "bundle": {
35
+ "extension": ".hwpxbp",
36
+ "manifest": "blueprint.json",
37
+ "assetPattern": "assets/<sha256>.<safe-extension>",
38
+ "allowedMediaPrefixes": ["image/"],
39
+ "forbidden": ["xml", "script", "symlink", "nested-archive", "absolute-path", "parent-path"],
40
+ },
41
+ "limits": blueprint_limits(),
42
+ "surfaces": {"cli": ["dump", "replay"], "mcpMaximumTools": 2},
43
+ }
44
+
45
+
46
+ def blueprint_catalog_hash() -> str:
47
+ encoded = json.dumps(
48
+ blueprint_catalog(), ensure_ascii=False, sort_keys=True, separators=(",", ":")
49
+ ).encode("utf-8")
50
+ return "sha256:" + hashlib.sha256(encoded).hexdigest()
51
+
52
+
53
+ def blueprint_json_schemas() -> dict[str, Any]:
54
+ catalog = blueprint_catalog()
55
+ return {
56
+ "blueprint": {
57
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
58
+ "title": "HwpxBlueprint v1",
59
+ "type": "object",
60
+ "required": [
61
+ "schemaVersion",
62
+ "catalogVersion",
63
+ "catalogHash",
64
+ "source",
65
+ "mode",
66
+ "root",
67
+ "nodes",
68
+ "styles",
69
+ "numbering",
70
+ "resources",
71
+ "references",
72
+ "unsupported",
73
+ "capabilities",
74
+ "limits",
75
+ "fidelity",
76
+ "blueprintHash",
77
+ ],
78
+ "additionalProperties": False,
79
+ "properties": {
80
+ "schemaVersion": {"const": BLUEPRINT_SCHEMA},
81
+ "catalogVersion": {"const": AGENT_CATALOG_SCHEMA},
82
+ "catalogHash": {"type": "string", "pattern": "^sha256:[a-f0-9]{64}$"},
83
+ "mode": {"enum": list(BLUEPRINT_MODES)},
84
+ "nodes": {"type": "array", "minItems": 1, "maxItems": catalog["limits"]["maxNodes"]},
85
+ "resources": {"type": "array", "maxItems": catalog["limits"]["maxAssets"]},
86
+ "blueprintHash": {"type": "string", "pattern": "^sha256:[a-f0-9]{64}$"},
87
+ },
88
+ },
89
+ "replay": {
90
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
91
+ "title": "HwpxBlueprintReplay v1",
92
+ "type": "object",
93
+ "required": [
94
+ "schemaVersion",
95
+ "bundle",
96
+ "target",
97
+ "targetParent",
98
+ "position",
99
+ "mode",
100
+ "mappingPolicy",
101
+ "expectedRevision",
102
+ "idempotencyKey",
103
+ "dryRun",
104
+ "quality",
105
+ "verificationRequirements",
106
+ ],
107
+ "additionalProperties": False,
108
+ "properties": {
109
+ "schemaVersion": {"const": BLUEPRINT_REPLAY_SCHEMA},
110
+ "mode": {"enum": list(BLUEPRINT_MODES)},
111
+ "targetParent": {"type": "string"},
112
+ "dryRun": {"type": "boolean"},
113
+ },
114
+ },
115
+ }
116
+
117
+
118
+ def blueprint_human_help() -> str:
119
+ limits = blueprint_limits()
120
+ return (
121
+ "HWPX typed blueprint v1\n"
122
+ " dump: revision-bound document/subtree -> deterministic .hwpxbp\n"
123
+ " replay: source-bound|portable -> one atomic SavePipeline commit\n"
124
+ " fidelity: exact, mapped; strict replay rejects degraded/unsupported\n"
125
+ f" limits: nodes={limits['maxNodes']}, assets={limits['maxAssets']}, "
126
+ f"manifest={limits['maxManifestBytes']} bytes\n"
127
+ " raw XML, package parts, resident sessions, watch, and OfficeCLI are unavailable\n"
128
+ )
129
+
130
+
131
+ __all__ = [
132
+ "blueprint_catalog",
133
+ "blueprint_catalog_hash",
134
+ "blueprint_human_help",
135
+ "blueprint_json_schemas",
136
+ ]