python-hwpx-automation 7.0.3__tar.gz → 7.1.0__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 (229) hide show
  1. {python_hwpx_automation-7.0.3/src/python_hwpx_automation.egg-info → python_hwpx_automation-7.1.0}/PKG-INFO +11 -12
  2. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/README.md +9 -10
  3. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/pyproject.toml +2 -2
  4. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/quality_render.py +55 -0
  5. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/read_export.py +3 -1
  6. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/identity.json +17 -10
  7. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/cli.py +14 -1
  8. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/document.py +30 -2
  9. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/__init__.py +1 -1
  10. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/wordbox.py +8 -8
  11. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/quality.py +2 -2
  12. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/_render_hwpx_mac.applescript +47 -35
  13. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/diff.py +2 -2
  14. python_hwpx_automation-7.1.0/src/hwpx_automation/office/rendering/mac_session.py +87 -0
  15. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/oracle.py +33 -42
  16. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/worker.py +56 -18
  17. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/public-modules.json +6 -4
  18. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/tool_contract.py +5 -4
  19. python_hwpx_automation-7.1.0/src/hwpx_automation/utils/read_budget.py +128 -0
  20. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/render_queue.py +17 -0
  21. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0/src/python_hwpx_automation.egg-info}/PKG-INFO +11 -12
  22. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/python_hwpx_automation.egg-info/SOURCES.txt +2 -0
  23. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/python_hwpx_automation.egg-info/requires.txt +1 -1
  24. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/LICENSE +0 -0
  25. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/MANIFEST.in +0 -0
  26. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/NOTICE +0 -0
  27. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/setup.cfg +0 -0
  28. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/__init__.py +0 -0
  29. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/__init__.pyi +0 -0
  30. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/__main__.py +0 -0
  31. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/agent_document.py +0 -0
  32. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/api.py +0 -0
  33. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/blind_eval.py +0 -0
  34. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/capabilities.py +0 -0
  35. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/compat.py +0 -0
  36. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/configuration.py +0 -0
  37. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/__init__.py +0 -0
  38. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/content.py +0 -0
  39. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/context.py +0 -0
  40. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/diff.py +0 -0
  41. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/document.py +0 -0
  42. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/formatting.py +0 -0
  43. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/handles.py +0 -0
  44. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/locations.py +0 -0
  45. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/locator.py +0 -0
  46. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/plan.py +0 -0
  47. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/resources.py +0 -0
  48. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/search.py +0 -0
  49. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/transactions.py +0 -0
  50. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/txn.py +0 -0
  51. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/document_state.py +0 -0
  52. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/errors.py +0 -0
  53. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/execution_lock.py +0 -0
  54. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/fastmcp_adapter.py +0 -0
  55. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/form_fill.py +0 -0
  56. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/form_output_models.py +0 -0
  57. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/__init__.py +0 -0
  58. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/_shared.py +0 -0
  59. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/agent_document.py +0 -0
  60. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/authoring.py +0 -0
  61. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/content_edit.py +0 -0
  62. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/form_fill.py +0 -0
  63. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/layout_style.py +0 -0
  64. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/specialized.py +0 -0
  65. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/tracked_changes.py +0 -0
  66. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/workflow.py +0 -0
  67. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/hwp_converter.py +0 -0
  68. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/hwp_support.py +0 -0
  69. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/hwpx_ops.py +0 -0
  70. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/identity.py +0 -0
  71. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ingest_adapters.py +0 -0
  72. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/markdown_plan.py +0 -0
  73. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/mcp_cli.py +0 -0
  74. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/metadata/tools_meta.py +0 -0
  75. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/mixed_form.py +0 -0
  76. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/mutation_models.py +0 -0
  77. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/network_policy.py +0 -0
  78. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/__init__.py +0 -0
  79. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/__init__.py +0 -0
  80. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/_batch_verification.py +0 -0
  81. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/__init__.py +0 -0
  82. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/bundle.py +0 -0
  83. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/catalog.py +0 -0
  84. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/dump.py +0 -0
  85. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/mapping.py +0 -0
  86. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/model.py +0 -0
  87. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/native.py +0 -0
  88. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/replay.py +0 -0
  89. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/catalog.py +0 -0
  90. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/commands.py +0 -0
  91. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/form_plan.py +0 -0
  92. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/model.py +0 -0
  93. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/path.py +0 -0
  94. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/query.py +0 -0
  95. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/story.py +0 -0
  96. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/advanced_generators.py +0 -0
  97. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/builder/__init__.py +0 -0
  98. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/builder/core.py +0 -0
  99. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/builder/report.py +0 -0
  100. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/__init__.py +0 -0
  101. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/_support.py +0 -0
  102. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/composer.py +0 -0
  103. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/harvest.py +0 -0
  104. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/plan.py +0 -0
  105. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profile.py +0 -0
  106. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/application_form/fragments/body.xml +0 -0
  107. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/application_form/fragments/heading.xml +0 -0
  108. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/application_form/fragments/info_table.xml +0 -0
  109. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/application_form/fragments/title.xml +0 -0
  110. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/application_form/profile.json +0 -0
  111. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/application_form/template.hwpx +0 -0
  112. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/home_notice/fragments/body.xml +0 -0
  113. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/home_notice/fragments/heading.xml +0 -0
  114. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/home_notice/fragments/title.xml +0 -0
  115. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/home_notice/profile.json +0 -0
  116. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/home_notice/template.hwpx +0 -0
  117. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/official_notice/fragments/body.xml +0 -0
  118. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/official_notice/fragments/heading.xml +0 -0
  119. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/official_notice/fragments/info_table.xml +0 -0
  120. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/official_notice/fragments/title.xml +0 -0
  121. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/official_notice/profile.json +0 -0
  122. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/official_notice/template.hwpx +0 -0
  123. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/report/fragments/body.xml +0 -0
  124. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/report/fragments/heading.xml +0 -0
  125. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/report/fragments/info_table.xml +0 -0
  126. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/report/fragments/title.xml +0 -0
  127. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/report/profile.json +0 -0
  128. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/report/template.hwpx +0 -0
  129. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/validator.py +0 -0
  130. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/presets/__init__.py +0 -0
  131. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/presets/proposal.py +0 -0
  132. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/report_parser.py +0 -0
  133. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/style_profile.py +0 -0
  134. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/template_analyzer.py +0 -0
  135. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/charting/__init__.py +0 -0
  136. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/compliance/__init__.py +0 -0
  137. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/compliance/official_lint.py +0 -0
  138. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/compliance/pii.py +0 -0
  139. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/document_ops/__init__.py +0 -0
  140. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/document_ops/comparison.py +0 -0
  141. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/document_ops/mail_merge.py +0 -0
  142. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/document_ops/redline.py +0 -0
  143. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/evalplan/__init__.py +0 -0
  144. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/evalplan/runtime.py +0 -0
  145. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/__init__.py +0 -0
  146. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/compose.py +0 -0
  147. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/ir.py +0 -0
  148. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/measure.py +0 -0
  149. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/parser.py +0 -0
  150. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/profile.py +0 -0
  151. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/__init__.py +0 -0
  152. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/classification.py +0 -0
  153. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fill_residue.py +0 -0
  154. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/__init__.py +0 -0
  155. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/apply.py +0 -0
  156. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/engine.py +0 -0
  157. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/measure.py +0 -0
  158. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/policy.py +0 -0
  159. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/report.py +0 -0
  160. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/seal.py +0 -0
  161. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/guidance.py +0 -0
  162. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/split_run.py +0 -0
  163. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/template_formfit.py +0 -0
  164. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/__init__.py +0 -0
  165. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/composition.py +0 -0
  166. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/data/bank.json +0 -0
  167. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/data/genres.json +0 -0
  168. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/gianmun.py +0 -0
  169. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/org_chart.py +0 -0
  170. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/quality/__init__.py +0 -0
  171. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/quality/page_guard.py +0 -0
  172. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/__init__.py +0 -0
  173. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/_hancom_open_rate.ps1 +0 -0
  174. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/_refresh_hwpx_mac.applescript +0 -0
  175. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/_render_hwpx.ps1 +0 -0
  176. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/block_splits.py +0 -0
  177. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/detectors.py +0 -0
  178. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/fixture_corpus.py +0 -0
  179. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/page_qa.py +0 -0
  180. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/qa_contracts.py +0 -0
  181. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/qa_metrics.py +0 -0
  182. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/utilities/__init__.py +0 -0
  183. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/utilities/table_compute.py +0 -0
  184. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/__init__.py +0 -0
  185. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/_border_fill.py +0 -0
  186. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/composition.py +0 -0
  187. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/content_layout.py +0 -0
  188. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/context.py +0 -0
  189. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/form_fields.py +0 -0
  190. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/media.py +0 -0
  191. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/memo_style.py +0 -0
  192. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/package_validation.py +0 -0
  193. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/planning.py +0 -0
  194. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/preview_export.py +0 -0
  195. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/read_query.py +0 -0
  196. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/save_policy.py +0 -0
  197. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/tables.py +0 -0
  198. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/transactions.py +0 -0
  199. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/preview_output_models.py +0 -0
  200. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/py.typed +0 -0
  201. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/quality.py +0 -0
  202. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/quality_generation.py +0 -0
  203. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/resources.py +0 -0
  204. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/runtime.py +0 -0
  205. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/runtime_services.py +0 -0
  206. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/server.py +0 -0
  207. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/storage.py +0 -0
  208. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/tool_bindings.py +0 -0
  209. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/upstream.py +0 -0
  210. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/utils/__init__.py +0 -0
  211. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/utils/helpers.py +0 -0
  212. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/visual_qa.py +0 -0
  213. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/__init__.py +0 -0
  214. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/adapters.py +0 -0
  215. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/dispatcher.py +0 -0
  216. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/models.py +0 -0
  217. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/policy.py +0 -0
  218. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/render_contracts.py +0 -0
  219. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/render_metrics.py +0 -0
  220. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/render_security.py +0 -0
  221. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/render_transport.py +0 -0
  222. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/rendering.py +0 -0
  223. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/service.py +0 -0
  224. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/state_machine.py +0 -0
  225. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/store.py +0 -0
  226. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workspace.py +0 -0
  227. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/python_hwpx_automation.egg-info/dependency_links.txt +0 -0
  228. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/python_hwpx_automation.egg-info/entry_points.txt +0 -0
  229. {python_hwpx_automation-7.0.3 → python_hwpx_automation-7.1.0}/src/python_hwpx_automation.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-hwpx-automation
3
- Version: 7.0.3
3
+ Version: 7.1.0
4
4
  Summary: Task-oriented HWPX document automation for Python, with an optional MCP adapter.
5
5
  Author: Kohkyuhyun
6
6
  License-Expression: Apache-2.0
@@ -20,7 +20,7 @@ Requires-Python: >=3.10
20
20
  Description-Content-Type: text/markdown
21
21
  License-File: LICENSE
22
22
  License-File: NOTICE
23
- Requires-Dist: python-hwpx<7,>=6.3.0
23
+ Requires-Dist: python-hwpx<7,>=6.4.0
24
24
  Requires-Dist: pydantic<3,>=2.11
25
25
  Requires-Dist: cryptography>=42.0
26
26
  Requires-Dist: anyio>=4.0
@@ -74,15 +74,12 @@ Dynamic: license-file
74
74
 
75
75
  <!-- release-state: release-approved -->
76
76
  > [!NOTE]
77
- > 공개 트레인: `python-hwpx 6.2.1 python-hwpx-automation 7.0.2
78
- > hwpx-plugin 2.0.1` 7.0.3 트레인(core 6.3.0 · plugin 2.0.2)은 오너 발행
79
- > 승인 완료(`release-approved`), 원격 관찰 대기 중.
80
- > (automation 7.0.2 · plugin 2.0.1 released 2026-08-16,
81
- > Windows 저장 수리 패치 트레인 — 저장 수리 #98·업로드 경로 안내
82
- > #75, core와 계약 `34a91560759dc47a` 불변).
83
- > 공개 좌표는 원격 진실(core·automation PyPI와 plugin GitHub
84
- > Release·marketplace·실제 marketplace 설치) 관찰 후에만
85
- > 승격됩니다 — [릴리스 runbook](docs/release-runbook.md)
77
+ > 소스는 발행 승인된(release-approved) 7.1.0 후보입니다. 원격 발행과 실제 설치 관찰 전까지 공개 좌표는 유지합니다.
78
+ > 후보: `python-hwpx 6.4.0 python-hwpx-automation 7.1.0 hwpx-plugin 2.2.0` (`ba0211fc854a0a97`).
79
+ > 공개 트레인: `python-hwpx 6.3.0 python-hwpx-automation 7.0.4 → hwpx-plugin 2.1.0` (`8c278ebd5becba08`).
80
+ > 공개 좌표는 core·automation PyPI와 plugin GitHub
81
+ > Release·marketplace·실제 marketplace 설치 관찰 후에만 승격합니다.
82
+ > [릴리스 runbook](docs/release-runbook.md)
86
83
 
87
84
  [python-hwpx](https://github.com/airmang/python-hwpx) 엔진 위에서 문서 저작·
88
85
  양식 채움·시험지 조판·안전한 에이전트 워크플로를 제공하는 응용 계층입니다.
@@ -136,7 +133,7 @@ Gemini CLI는 `~/.gemini/settings.json`, Cursor·Windsurf는 각 에디터의 MC
136
133
  "command": "uvx",
137
134
  "args": [
138
135
  "--from",
139
- "python-hwpx-automation[mcp]==7.0.3",
136
+ "python-hwpx-automation[mcp]==7.0.4",
140
137
  "hwpx-automation-mcp"
141
138
  ],
142
139
  "env": {
@@ -243,3 +240,5 @@ python scripts/run_conformance.py run \
243
240
  ## License · Maintainer
244
241
 
245
242
  Apache-2.0 ([LICENSE](LICENSE) · [NOTICE](NOTICE)) — **Kohkyuhyun** [@airmang](https://github.com/airmang) · [kokyuhyun@hotmail.com](mailto:kokyuhyun@hotmail.com)
243
+
244
+ 기존 문서 수정은 [조회·대상 확정·보존 저장·검증 안내](docs/existing-edit-navigation.md)를 먼저 확인하세요. 새 문서는 document-plan, 에이전트 연결은 선택 MCP와 호스트 플러그인을 사용합니다.
@@ -14,15 +14,12 @@
14
14
 
15
15
  <!-- release-state: release-approved -->
16
16
  > [!NOTE]
17
- > 공개 트레인: `python-hwpx 6.2.1 python-hwpx-automation 7.0.2
18
- > hwpx-plugin 2.0.1` 7.0.3 트레인(core 6.3.0 · plugin 2.0.2)은 오너 발행
19
- > 승인 완료(`release-approved`), 원격 관찰 대기 중.
20
- > (automation 7.0.2 · plugin 2.0.1 released 2026-08-16,
21
- > Windows 저장 수리 패치 트레인 — 저장 수리 #98·업로드 경로 안내
22
- > #75, core와 계약 `34a91560759dc47a` 불변).
23
- > 공개 좌표는 원격 진실(core·automation PyPI와 plugin GitHub
24
- > Release·marketplace·실제 marketplace 설치) 관찰 후에만
25
- > 승격됩니다 — [릴리스 runbook](docs/release-runbook.md)
17
+ > 소스는 발행 승인된(release-approved) 7.1.0 후보입니다. 원격 발행과 실제 설치 관찰 전까지 공개 좌표는 유지합니다.
18
+ > 후보: `python-hwpx 6.4.0 python-hwpx-automation 7.1.0 hwpx-plugin 2.2.0` (`ba0211fc854a0a97`).
19
+ > 공개 트레인: `python-hwpx 6.3.0 python-hwpx-automation 7.0.4 → hwpx-plugin 2.1.0` (`8c278ebd5becba08`).
20
+ > 공개 좌표는 core·automation PyPI와 plugin GitHub
21
+ > Release·marketplace·실제 marketplace 설치 관찰 후에만 승격합니다.
22
+ > [릴리스 runbook](docs/release-runbook.md)
26
23
 
27
24
  [python-hwpx](https://github.com/airmang/python-hwpx) 엔진 위에서 문서 저작·
28
25
  양식 채움·시험지 조판·안전한 에이전트 워크플로를 제공하는 응용 계층입니다.
@@ -76,7 +73,7 @@ Gemini CLI는 `~/.gemini/settings.json`, Cursor·Windsurf는 각 에디터의 MC
76
73
  "command": "uvx",
77
74
  "args": [
78
75
  "--from",
79
- "python-hwpx-automation[mcp]==7.0.3",
76
+ "python-hwpx-automation[mcp]==7.0.4",
80
77
  "hwpx-automation-mcp"
81
78
  ],
82
79
  "env": {
@@ -183,3 +180,5 @@ python scripts/run_conformance.py run \
183
180
  ## License · Maintainer
184
181
 
185
182
  Apache-2.0 ([LICENSE](LICENSE) · [NOTICE](NOTICE)) — **Kohkyuhyun** [@airmang](https://github.com/airmang) · [kokyuhyun@hotmail.com](mailto:kokyuhyun@hotmail.com)
183
+
184
+ 기존 문서 수정은 [조회·대상 확정·보존 저장·검증 안내](docs/existing-edit-navigation.md)를 먼저 확인하세요. 새 문서는 document-plan, 에이전트 연결은 선택 MCP와 호스트 플러그인을 사용합니다.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-hwpx-automation"
7
- version = "7.0.3"
7
+ version = "7.1.0"
8
8
  description = "Task-oriented HWPX document automation for Python, with an optional MCP adapter."
9
9
  readme = "README.md"
10
10
  authors = [{ name = "Kohkyuhyun" }]
@@ -31,7 +31,7 @@ dependencies = [
31
31
  # breaking an already-published automation line. WP-F (engine surface 6.0):
32
32
  # this line adapted to the new namespace surface (design §9 WP-F) — the dev0
33
33
  # pre-release qualifier tracks core's own not-yet-tagged 6.0 identity.
34
- "python-hwpx>=6.3.0,<7", # HWPX object model, OXML/OPC, format-native primitives
34
+ "python-hwpx>=6.4.0,<7", # HWPX object model, OXML/OPC, format-native primitives
35
35
 
36
36
  "pydantic>=2.11,<3",
37
37
  "cryptography>=42.0",
@@ -272,6 +272,60 @@ def describe_capabilities(domain: str | None = None) -> dict:
272
272
  return report
273
273
 
274
274
 
275
+ _STACK_UPDATE_STATE_SCHEMA = "hwpx.stack-update-state.v1"
276
+
277
+
278
+ def _stack_update_block() -> dict[str, Any]:
279
+ """Launcher-managed runtime update state (hwpx-plugins Feature 066).
280
+
281
+ The bundled launcher writes update-state.json and passes its path as
282
+ HWPX_STACK_UPDATE_STATE. Without it the runtime is not launcher-managed
283
+ (pip install, editable checkout, plain uvx) and the block says so; it
284
+ never guesses.
285
+ """
286
+ path = os.environ.get("HWPX_STACK_UPDATE_STATE")
287
+ if not path:
288
+ return {"available": False, "reason": "NOT_MANAGED"}
289
+ try:
290
+ with open(path, encoding="utf-8") as handle:
291
+ state = json.load(handle)
292
+ except FileNotFoundError:
293
+ return {"available": False, "reason": "STATE_MISSING", "path": path}
294
+ except (OSError, UnicodeDecodeError, json.JSONDecodeError) as exc:
295
+ return {"available": False, "reason": "STATE_UNREADABLE", "path": path, "detail": str(exc)}
296
+ if not isinstance(state, dict) or state.get("schemaVersion") != _STACK_UPDATE_STATE_SCHEMA:
297
+ return {"available": False, "reason": "STATE_SCHEMA_UNKNOWN", "path": path}
298
+ runtime = state.get("runtime")
299
+ if not isinstance(runtime, dict):
300
+ return {"available": False, "reason": "STATE_INVALID", "path": path}
301
+ installed = runtime.get("installed")
302
+ if (
303
+ not isinstance(installed, dict)
304
+ or set(installed) != {"python-hwpx", "python-hwpx-automation"}
305
+ or not all(isinstance(value, str) and value for value in installed.values())
306
+ ):
307
+ return {"available": False, "reason": "STATE_INVALID", "path": path}
308
+ running = {
309
+ "python-hwpx": _package_version("python-hwpx"),
310
+ "python-hwpx-automation": _package_version("python-hwpx-automation"),
311
+ }
312
+ runtime = {
313
+ **runtime,
314
+ "running": running,
315
+ "restartRequired": runtime["installed"] != running,
316
+ }
317
+ return {
318
+ "available": True,
319
+ "path": path,
320
+ "checkedAt": state.get("checkedAt"),
321
+ "autoUpdate": state.get("autoUpdate"),
322
+ "channel": state.get("channel"),
323
+ "runtime": runtime,
324
+ "pluginBundle": state.get("pluginBundle"),
325
+ "lastError": state.get("lastError"),
326
+ }
327
+
328
+
275
329
  def mcp_server_health() -> dict:
276
330
  """MCP 서버 transport와 timeout/keepalive 점검 정보를 반환합니다."""
277
331
  transport = env_value("TRANSPORT", "stdio")
@@ -386,6 +440,7 @@ def mcp_server_health() -> dict:
386
440
  ),
387
441
  },
388
442
  "capability": _capability_block(skew_detected, surface_details),
443
+ "stackUpdate": _stack_update_block(),
389
444
  "unitPolicy": {
390
445
  "status": "audited",
391
446
  "fontSize": "points",
@@ -38,6 +38,7 @@ from ..upstream import (
38
38
  open_document,
39
39
  )
40
40
  from ..utils.helpers import default_max_chars, resolve_path, truncate_response
41
+ from ..utils.read_budget import bound_document_summary
41
42
  from ._shared import _with_document_state
42
43
 
43
44
  _OUTPUT_MODES = {"full", "chunks"}
@@ -920,7 +921,8 @@ def get_document_map(
920
921
  "hwpx_extract_json",
921
922
  ],
922
923
  }
923
- return _with_document_state(result, path)
924
+ result = _with_document_state(result, path)
925
+ return bound_document_summary(result) if summary_mode else result
924
926
 
925
927
 
926
928
  def hwpx_to_markdown(
@@ -5,22 +5,29 @@
5
5
  "releaseState": {
6
6
  "status": "release-approved",
7
7
  "candidate": {
8
- "pythonHwpx": "6.3.0",
8
+ "pythonHwpx": "6.4.0",
9
9
  "canonicalDistribution": "python-hwpx-automation",
10
- "canonicalAutomation": "7.0.3",
10
+ "canonicalAutomation": "7.1.0",
11
11
  "compatibilityDistribution": "hwpx-mcp-server",
12
- "compatibility": "7.0.3",
13
- "plugin": "2.0.2",
14
- "contractHash": "8c278ebd5becba08"
12
+ "compatibility": "7.1.0",
13
+ "plugin": "2.2.0",
14
+ "contractHash": "ba0211fc854a0a97"
15
15
  },
16
16
  "currentPublic": {
17
- "pythonHwpx": "6.2.1",
17
+ "pythonHwpx": "6.3.0",
18
18
  "primaryDistribution": "python-hwpx-automation",
19
- "primaryApplication": "7.0.2",
20
- "plugin": "2.0.1",
21
- "contractHash": "34a91560759dc47a"
19
+ "primaryApplication": "7.0.4",
20
+ "plugin": "2.1.0",
21
+ "contractHash": "8c278ebd5becba08"
22
22
  },
23
- "promotionGate": "Three states are mandatory: unreleased-candidate while auditing; release-approved only after separate owner approval and while currentPublic still names the previously observed coherent stack; released only in a follow-up commit after remote truth is observed for core, canonical automation, the compatibility distribution, the plugin GitHub release, the marketplace entry, and a real marketplace install. The automation tag workflow publishes only release-approved, leaves currentPublic unchanged, and hands an attached receipt to plugin publication."
23
+ "promotionGate": "Three states are mandatory: unreleased-candidate while auditing; release-approved only after separate owner approval and while currentPublic still names the previously observed coherent stack; released only in a follow-up commit after remote truth is observed for core, canonical automation, the compatibility distribution, the plugin GitHub release, the marketplace entry, and a real marketplace install. The automation tag workflow publishes only release-approved, leaves currentPublic unchanged, and hands an attached receipt to plugin publication.",
24
+ "previousPublic": {
25
+ "pythonHwpx": "6.3.0",
26
+ "primaryDistribution": "python-hwpx-automation",
27
+ "primaryApplication": "7.0.4",
28
+ "plugin": "2.1.0",
29
+ "contractHash": "8c278ebd5becba08"
30
+ }
24
31
  },
25
32
  "releaseFloors": {
26
33
  "description": "Frozen historical coordinates. Unlike releaseState these do not advance train by train; they pin the pre-6.0 legacy compatibility cap that every core 5 resolution must be observed against. They live here so the release path has no version literal that is not declared data.",
@@ -23,6 +23,10 @@ from .blueprint import (
23
23
  )
24
24
  from .commands import apply_document_commands
25
25
  from .document import HwpxAgentDocument
26
+ from .form_plan import (
27
+ MIXED_FORM_PLAN_SCHEMA, MIXED_FORM_COMPILED_PLAN_SCHEMA,
28
+ apply_mixed_form_fill, apply_mixed_form_plan,
29
+ )
26
30
  from .model import (
27
31
  AGENT_BATCH_SCHEMA,
28
32
  AgentBatchResult,
@@ -536,6 +540,15 @@ def _run_replay(args: argparse.Namespace, *, stdin: TextIO, stdout: TextIO) -> i
536
540
  return _exit_code(result.error)
537
541
 
538
542
 
543
+ def _apply_batch_request(request: Mapping[str, Any], store: dict[str, Any]) -> AgentBatchResult:
544
+ schema = request.get("schemaVersion")
545
+ if schema == MIXED_FORM_PLAN_SCHEMA:
546
+ return apply_mixed_form_fill(request, idempotency_store=store)
547
+ if schema == MIXED_FORM_COMPILED_PLAN_SCHEMA:
548
+ return apply_mixed_form_plan(request, idempotency_store=store)
549
+ return apply_document_commands(request, idempotency_store=store)
550
+
551
+
539
552
  def _run_mutation(
540
553
  args: argparse.Namespace,
541
554
  *,
@@ -550,7 +563,7 @@ def _run_mutation(
550
563
  exit_code = EXIT_OK
551
564
  results: list[AgentBatchResult] = []
552
565
  for request in requests:
553
- result = apply_document_commands(request, idempotency_store=store)
566
+ result = _apply_batch_request(request, store)
554
567
  results.append(result)
555
568
  exit_code = max(exit_code, _exit_code(result.error))
556
569
  if args.output_format == "human":
@@ -21,7 +21,7 @@ from .model import (
21
21
  AgentNode,
22
22
  NODE_PROPERTY_CATALOG_V1,
23
23
  )
24
- from .path import SemanticPath, canonicalize_path, identified_segment, indexed_segment
24
+ from .path import SemanticPath, canonicalize_path, identified_segment, indexed_segment, parse_path
25
25
  from .query import QueryRecord as _QueryRecord
26
26
  from .query import QueryResult, evaluate_selector, parse_selector
27
27
  from .story import (
@@ -804,9 +804,37 @@ class HwpxAgentDocument:
804
804
  f"childLimit must be 1..{MAX_CHILDREN_PER_NODE}",
805
805
  target="childLimit",
806
806
  )
807
- record = self.resolve_record(path, expected_revision=expected_revision)
807
+ try:
808
+ record = self.resolve_record(path, expected_revision=expected_revision)
809
+ except AgentContractError as exc:
810
+ if exc.code != "not_found":
811
+ raise
812
+ record = self._resolve_indexed_read_path(path, expected_revision)
808
813
  return self._public_node(record, depth=depth, child_limit=child_limit)
809
814
 
815
+ def _resolve_indexed_read_path(self, path: str, revision: str | None) -> NodeRecord:
816
+ """Navigate omitted children; return a canonical path for subsequent edits.
817
+
818
+ Only get() calls this helper. Commands continue to require the exact
819
+ canonical path, so a navigation alias never silently retargets a write.
820
+ """
821
+ record = self._records["/"]
822
+ for segment in parse_path(path).segments:
823
+ direct = record.path.rstrip("/") + "/" + segment.canonical()
824
+ if direct in record.child_paths:
825
+ record = self.resolve_record(direct, expected_revision=revision)
826
+ continue
827
+ children = [self._records[p] for p in record.child_paths
828
+ if self._records[p].kind == segment.kind]
829
+ if segment.index is None or segment.index > len(children):
830
+ raise AgentContractError("not_found", "indexed read target not found", target=path)
831
+ if revision is None:
832
+ raise AgentContractError(
833
+ "volatile_target", "indexed navigation requires the current revision", target=path
834
+ )
835
+ record = self.resolve_record(children[segment.index - 1].path, expected_revision=revision)
836
+ return record
837
+
810
838
  def query(
811
839
  self,
812
840
  selector: str,
@@ -1292,7 +1292,7 @@ def inspect_document_authoring_quality(
1292
1292
  _rendered = _mac.render_pdf(str(_hwpx), str(_pdf))
1293
1293
  if _rendered and Path(_rendered).exists():
1294
1294
  try:
1295
- import fitz as _fitz
1295
+ import pymupdf as _fitz
1296
1296
 
1297
1297
  _doc = _fitz.open(_rendered)
1298
1298
  _has_text = any(
@@ -185,7 +185,7 @@ def fitz_available() -> bool:
185
185
  """True when PyMuPDF (``fitz``) can be imported (the extraction backend)."""
186
186
 
187
187
  try: # pragma: no cover - trivial import probe
188
- import fitz # noqa: F401
188
+ import pymupdf as fitz # noqa: F401
189
189
  except Exception:
190
190
  return False
191
191
  return True
@@ -205,7 +205,7 @@ def extract_word_boxes(pdf_path: str, *, page: int | None = None) -> list[WordBo
205
205
 
206
206
  if not fitz_available():
207
207
  raise OracleUnavailable("PyMuPDF (fitz) is not installed")
208
- import fitz
208
+ import pymupdf as fitz
209
209
 
210
210
  boxes: list[WordBox] = []
211
211
  try:
@@ -255,7 +255,7 @@ def extract_glyph_boxes(pdf_path: str, *, page: int | None = None) -> list[WordB
255
255
 
256
256
  if not fitz_available():
257
257
  raise OracleUnavailable("PyMuPDF (fitz) is not installed")
258
- import fitz
258
+ import pymupdf as fitz
259
259
 
260
260
  boxes: list[WordBox] = []
261
261
  try:
@@ -709,7 +709,7 @@ def render_glyph_boxes(
709
709
  if not pdf or not os.path.exists(pdf) or os.path.getsize(pdf) == 0:
710
710
  raise OracleUnavailable("Hancom render produced no PDF")
711
711
  boxes = extract_glyph_boxes(pdf, page=page)
712
- import fitz
712
+ import pymupdf as fitz
713
713
 
714
714
  with fitz.open(pdf) as doc:
715
715
  if len(doc) == 0: # a 0-page render is a failed render, not a clean pass
@@ -742,7 +742,7 @@ def extract_cell_clips(pdf_path: str, *, page: int | None = None) -> list[Rect]:
742
742
 
743
743
  if not fitz_available():
744
744
  raise OracleUnavailable("PyMuPDF (fitz) is not installed")
745
- import fitz
745
+ import pymupdf as fitz
746
746
 
747
747
  clips: list[Rect] = []
748
748
  try:
@@ -785,7 +785,7 @@ def extract_image_boxes(pdf_path: str, *, page: int | None = None) -> list[Rect]
785
785
 
786
786
  if not fitz_available():
787
787
  raise OracleUnavailable("PyMuPDF (fitz) is not installed")
788
- import fitz
788
+ import pymupdf as fitz
789
789
 
790
790
  boxes: list[Rect] = []
791
791
  try:
@@ -843,7 +843,7 @@ def render_form_geometry(
843
843
  raise OracleUnavailable("Hancom render produced no PDF")
844
844
  glyphs = extract_glyph_boxes(rendered, page=page)
845
845
  clips = extract_cell_clips(rendered, page=page)
846
- import fitz
846
+ import pymupdf as fitz
847
847
 
848
848
  with fitz.open(rendered) as doc:
849
849
  if len(doc) == 0:
@@ -957,7 +957,7 @@ def extract_layout_signature(pdf_path: str) -> LayoutSignature:
957
957
 
958
958
  if not fitz_available():
959
959
  raise OracleUnavailable("PyMuPDF (fitz) is not installed")
960
- import fitz
960
+ import pymupdf as fitz
961
961
 
962
962
  try:
963
963
  doc = fitz.open(pdf_path)
@@ -180,7 +180,7 @@ def detect_overflow_crossings(
180
180
  PyMuPDF; raises ``RuntimeError`` if unavailable (caller degrades to unverified).
181
181
  """
182
182
  try:
183
- import fitz
183
+ import pymupdf as fitz
184
184
  except Exception as exc: # pragma: no cover - env probe
185
185
  raise RuntimeError(f"PyMuPDF unavailable: {exc}") from exc
186
186
 
@@ -266,7 +266,7 @@ def score_render(
266
266
  [f"render imaging deps unavailable: {exc}"],
267
267
  )
268
268
 
269
- import fitz # already importable if we got here
269
+ import pymupdf as fitz # already importable if we got here
270
270
 
271
271
  doc = fitz.open(pdf)
272
272
  pages = doc.page_count
@@ -30,6 +30,10 @@ property closeDocPrefix : "문서 닫기"
30
30
 
31
31
  on run argv
32
32
  if (count of argv) < 2 then return "ERR: usage: <input.hwpx> <out.pdf> [timeoutSecs]"
33
+ if item 1 of argv is "--close-owned" then
34
+ closeOwnedDocument(item 2 of argv)
35
+ return "CLEANUP"
36
+ end if
33
37
  set inputPath to item 1 of argv
34
38
  set outPdf to item 2 of argv
35
39
  set timeoutSecs to 90
@@ -41,6 +45,18 @@ on run argv
41
45
 
42
46
  set inputBase to do shell script "basename " & quoted form of inputPath
43
47
 
48
+ if listContains(windowNames(), inputBase) then return "ERR: staged document already open"
49
+ if listContains(windowNames(), pdfDialogTitle) then return "ERR: existing PDF dialog"
50
+ -- Do not drive menus while another document owns a modal sheet.
51
+ tell application "System Events"
52
+ if exists process procName then
53
+ tell process procName
54
+ repeat with w in windows
55
+ if (count of sheets of w) > 0 then return "ERR: existing modal sheet"
56
+ end repeat
57
+ end tell
58
+ end if
59
+ end tell
44
60
  try
45
61
  -- 1) Open the staged input. LaunchServices focuses Hancom (launching it
46
62
  -- if needed) and opens the document.
@@ -61,7 +77,7 @@ on run argv
61
77
 
62
78
  -- 4) Wait for the export dialog.
63
79
  if not (waitForWindowNamed(pdfDialogTitle, 30)) then
64
- return "ERR: PDF save dialog did not appear"
80
+ error "PDF save dialog did not appear"
65
81
  end if
66
82
  delay 1.0
67
83
 
@@ -94,19 +110,14 @@ on run argv
94
110
  -- 8) Always close the document so the next render starts from a clean
95
111
  -- session, even if the wait above was noisy. Discard any save-changes
96
112
  -- prompt (we only exported; the doc content is unmodified).
97
- try
98
- clickFileMenuItemByPrefix(closeDocPrefix)
99
- dismissCloseSheetIfPresent()
100
- end try
113
+ set closed to closeOwnedDocument(inputBase)
114
+ if not closed then return "ERR: owned document cleanup incomplete"
101
115
 
102
116
  if not wrote then return "ERR: PDF not written to " & outPdf
103
117
  return "OK"
104
118
  on error errMsg number errNum
105
119
  -- Best-effort cleanup so a mid-flow error doesn't leak an open document.
106
- try
107
- clickFileMenuItemByPrefix(closeDocPrefix)
108
- dismissCloseSheetIfPresent()
109
- end try
120
+ closeOwnedDocument(inputBase)
110
121
  return "ERR: " & errMsg & " (" & errNum & ")"
111
122
  end try
112
123
  end run
@@ -221,29 +232,30 @@ on dismissOverwriteSheetIfPresent()
221
232
  return false
222
233
  end dismissOverwriteSheetIfPresent
223
234
 
224
- -- If closing surfaces a save-changes sheet, discard (저장 / 함). We only
225
- -- exported a PDF, so the document content is unchanged.
226
- on dismissCloseSheetIfPresent()
227
- repeat 6 times
228
- set handled to false
229
- try
230
- tell application "System Events" to tell process procName
231
- repeat with wn in windowNames()
232
- set w to (first window whose name is (wn as string))
233
- if (count of sheets of w) > 0 then
234
- repeat with b in buttons of (sheet 1 of w)
235
- set bn to (name of b as string)
236
- if bn contains "안 함" or bn contains "안함" then
237
- click b
238
- set handled to true
239
- end if
240
- end repeat
241
- end if
242
- end repeat
243
- end tell
244
- end try
245
- if handled then return true
246
- delay 0.3
247
- end repeat
248
- return false
249
- end dismissCloseSheetIfPresent
235
+ -- Never discard a sheet belonging to any other document. If ownership cannot
236
+ -- be proved, leave the GUI for the user and report failure rather than kill it.
237
+ on closeOwnedDocument(winName)
238
+ if not listContains(windowNames(), winName) then return false
239
+ if listContains(windowNames(), pdfDialogTitle) then return false
240
+ try
241
+ raiseWindowNamed(winName)
242
+ tell application "System Events" to tell process procName
243
+ if name of front window is not winName then return false
244
+ end tell
245
+ clickFileMenuItemByPrefix(closeDocPrefix)
246
+ tell application "System Events" to tell process procName
247
+ if exists (first window whose name is winName) then
248
+ set owned to (first window whose name is winName)
249
+ if (count of sheets of owned) > 0 then
250
+ repeat with b in buttons of sheet 1 of owned
251
+ set bn to name of b as string
252
+ if bn contains "안 함" or bn contains "안함" then click b
253
+ end repeat
254
+ end if
255
+ end if
256
+ end tell
257
+ return waitForWindowGone(winName, 2)
258
+ on error
259
+ return false
260
+ end try
261
+ end closeOwnedDocument
@@ -27,7 +27,7 @@ _TALL_BAND_REL = 1.0
27
27
 
28
28
  def pymupdf_available() -> bool:
29
29
  try: # pragma: no cover - trivial import probe
30
- import fitz # noqa: F401
30
+ import pymupdf as fitz # noqa: F401
31
31
  except Exception:
32
32
  return False
33
33
  return True
@@ -36,7 +36,7 @@ def pymupdf_available() -> bool:
36
36
  def render_pdf_to_images(pdf_path: str | Path, dpi: int = 150) -> list["Image.Image"]:
37
37
  """Rasterize every page of ``pdf_path`` to a list of RGB ``PIL.Image``."""
38
38
 
39
- import fitz # pymupdf
39
+ import pymupdf as fitz # pymupdf
40
40
  from PIL import Image
41
41
 
42
42
  pages: list[Image.Image] = []
@@ -0,0 +1,87 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Owned, cancellable Mac GUI adapter for the existing serialized worker."""
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import plistlib
7
+ import subprocess
8
+ import tempfile
9
+ import threading
10
+ from pathlib import Path
11
+
12
+ from .oracle import MacHancomOracle
13
+
14
+
15
+ class _OwnedMacOracle(MacHancomOracle):
16
+ def __init__(self, *, timeout: float) -> None:
17
+ super().__init__(timeout=timeout, budget_seconds=timeout)
18
+ self.guard = threading.Lock()
19
+ self.process: subprocess.Popen[str] | None = None
20
+ self.cancelled = threading.Event()
21
+
22
+ def _run_render_script(self, cmd: list[str], timeout: float) -> subprocess.CompletedProcess[str]:
23
+ with self.guard:
24
+ if self.cancelled.is_set():
25
+ raise OSError("render cancelled before launch")
26
+ process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
27
+ self.process = process
28
+ try:
29
+ try:
30
+ stdout, stderr = process.communicate(timeout=timeout)
31
+ except subprocess.TimeoutExpired:
32
+ process.kill()
33
+ process.communicate()
34
+ raise
35
+ if self.cancelled.is_set():
36
+ raise OSError("render cancelled")
37
+ return subprocess.CompletedProcess(cmd, process.returncode, stdout, stderr)
38
+ finally:
39
+ with self.guard:
40
+ self.process = None
41
+
42
+ def abort(self) -> None:
43
+ self.cancelled.set()
44
+ with self.guard:
45
+ if self.process is not None and self.process.poll() is None:
46
+ self.process.kill() # our osascript only; never the user's app
47
+
48
+
49
+ class MacHancomSession:
50
+ real_hancom = True
51
+ backend = "mac-gui-worker"
52
+
53
+ def __init__(self, *, timeout_seconds: float = 120) -> None:
54
+ self.oracle = _OwnedMacOracle(timeout=timeout_seconds)
55
+ app = self.oracle._app_path()
56
+ if app is None or not self.oracle.available():
57
+ raise RuntimeError("MAC_HANCOM_UNAVAILABLE")
58
+ with (Path(app) / "Contents/Info.plist").open("rb") as handle:
59
+ info = plistlib.load(handle)
60
+ version, build = info.get("CFBundleShortVersionString"), info.get("CFBundleVersion")
61
+ if not version or not build:
62
+ raise RuntimeError("MAC_HANCOM_BUILD_UNKNOWN")
63
+ self.hancom_build = f"{version} ({build})"
64
+
65
+ def render_pdf(self, source: Path, target: Path) -> Path | None:
66
+ from hwpx_automation.workflow.render_queue import inspect_hwpx
67
+ inspect_hwpx(source.read_bytes(), filename=source.name, principal_id="local-worker")
68
+ # The Mac desktop is shared even across worker roots/processes. flock
69
+ # lives until the rendering/owned cleanup exits, including watchdogs.
70
+ import fcntl
71
+ lock = Path(tempfile.gettempdir()) / f"hwpx-hancom-gui-{os.getuid()}.lock"
72
+ with lock.open("a") as handle:
73
+ try:
74
+ fcntl.flock(handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
75
+ except BlockingIOError:
76
+ raise RuntimeError("MAC_GUI_BUSY") from None
77
+ try:
78
+ result = self.oracle.render_pdf(str(source), str(target))
79
+ return Path(result) if result else None
80
+ finally:
81
+ fcntl.flock(handle, fcntl.LOCK_UN)
82
+
83
+ def abort(self) -> None:
84
+ self.oracle.abort()
85
+
86
+ def close(self) -> None:
87
+ self.abort()