python-hwpx-automation 7.0.4__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.4/src/python_hwpx_automation.egg-info → python_hwpx_automation-7.1.0}/PKG-INFO +8 -7
  2. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/README.md +6 -5
  3. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/pyproject.toml +2 -2
  4. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/read_export.py +3 -1
  5. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/identity.json +15 -8
  6. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/cli.py +14 -1
  7. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/document.py +30 -2
  8. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/_render_hwpx_mac.applescript +47 -35
  9. python_hwpx_automation-7.1.0/src/hwpx_automation/office/rendering/mac_session.py +87 -0
  10. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/oracle.py +33 -42
  11. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/worker.py +55 -17
  12. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/public-modules.json +6 -4
  13. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/tool_contract.py +5 -4
  14. python_hwpx_automation-7.1.0/src/hwpx_automation/utils/read_budget.py +128 -0
  15. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/render_queue.py +17 -0
  16. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0/src/python_hwpx_automation.egg-info}/PKG-INFO +8 -7
  17. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/python_hwpx_automation.egg-info/SOURCES.txt +2 -0
  18. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/python_hwpx_automation.egg-info/requires.txt +1 -1
  19. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/LICENSE +0 -0
  20. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/MANIFEST.in +0 -0
  21. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/NOTICE +0 -0
  22. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/setup.cfg +0 -0
  23. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/__init__.py +0 -0
  24. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/__init__.pyi +0 -0
  25. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/__main__.py +0 -0
  26. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/agent_document.py +0 -0
  27. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/api.py +0 -0
  28. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/blind_eval.py +0 -0
  29. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/capabilities.py +0 -0
  30. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/compat.py +0 -0
  31. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/configuration.py +0 -0
  32. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/__init__.py +0 -0
  33. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/content.py +0 -0
  34. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/context.py +0 -0
  35. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/diff.py +0 -0
  36. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/document.py +0 -0
  37. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/formatting.py +0 -0
  38. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/handles.py +0 -0
  39. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/locations.py +0 -0
  40. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/locator.py +0 -0
  41. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/plan.py +0 -0
  42. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/resources.py +0 -0
  43. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/search.py +0 -0
  44. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/transactions.py +0 -0
  45. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/txn.py +0 -0
  46. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/document_state.py +0 -0
  47. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/errors.py +0 -0
  48. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/execution_lock.py +0 -0
  49. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/fastmcp_adapter.py +0 -0
  50. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/form_fill.py +0 -0
  51. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/form_output_models.py +0 -0
  52. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/__init__.py +0 -0
  53. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/_shared.py +0 -0
  54. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/agent_document.py +0 -0
  55. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/authoring.py +0 -0
  56. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/content_edit.py +0 -0
  57. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/form_fill.py +0 -0
  58. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/layout_style.py +0 -0
  59. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/quality_render.py +0 -0
  60. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/specialized.py +0 -0
  61. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/tracked_changes.py +0 -0
  62. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/workflow.py +0 -0
  63. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/hwp_converter.py +0 -0
  64. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/hwp_support.py +0 -0
  65. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/hwpx_ops.py +0 -0
  66. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/identity.py +0 -0
  67. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ingest_adapters.py +0 -0
  68. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/markdown_plan.py +0 -0
  69. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/mcp_cli.py +0 -0
  70. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/metadata/tools_meta.py +0 -0
  71. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/mixed_form.py +0 -0
  72. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/mutation_models.py +0 -0
  73. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/network_policy.py +0 -0
  74. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/__init__.py +0 -0
  75. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/__init__.py +0 -0
  76. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/_batch_verification.py +0 -0
  77. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/__init__.py +0 -0
  78. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/bundle.py +0 -0
  79. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/catalog.py +0 -0
  80. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/dump.py +0 -0
  81. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/mapping.py +0 -0
  82. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/model.py +0 -0
  83. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/native.py +0 -0
  84. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/replay.py +0 -0
  85. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/catalog.py +0 -0
  86. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/commands.py +0 -0
  87. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/form_plan.py +0 -0
  88. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/model.py +0 -0
  89. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/path.py +0 -0
  90. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/query.py +0 -0
  91. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/story.py +0 -0
  92. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/__init__.py +0 -0
  93. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/advanced_generators.py +0 -0
  94. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/builder/__init__.py +0 -0
  95. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/builder/core.py +0 -0
  96. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/builder/report.py +0 -0
  97. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/__init__.py +0 -0
  98. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/_support.py +0 -0
  99. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/composer.py +0 -0
  100. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/harvest.py +0 -0
  101. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/plan.py +0 -0
  102. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profile.py +0 -0
  103. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/application_form/fragments/body.xml +0 -0
  104. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/application_form/fragments/heading.xml +0 -0
  105. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/application_form/fragments/info_table.xml +0 -0
  106. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/application_form/fragments/title.xml +0 -0
  107. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/application_form/profile.json +0 -0
  108. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/application_form/template.hwpx +0 -0
  109. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/home_notice/fragments/body.xml +0 -0
  110. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/home_notice/fragments/heading.xml +0 -0
  111. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/home_notice/fragments/title.xml +0 -0
  112. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/home_notice/profile.json +0 -0
  113. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/home_notice/template.hwpx +0 -0
  114. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/official_notice/fragments/body.xml +0 -0
  115. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/official_notice/fragments/heading.xml +0 -0
  116. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/official_notice/fragments/info_table.xml +0 -0
  117. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/official_notice/fragments/title.xml +0 -0
  118. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/official_notice/profile.json +0 -0
  119. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/official_notice/template.hwpx +0 -0
  120. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/report/fragments/body.xml +0 -0
  121. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/report/fragments/heading.xml +0 -0
  122. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/report/fragments/info_table.xml +0 -0
  123. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/report/fragments/title.xml +0 -0
  124. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/report/profile.json +0 -0
  125. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/report/template.hwpx +0 -0
  126. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/validator.py +0 -0
  127. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/presets/__init__.py +0 -0
  128. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/presets/proposal.py +0 -0
  129. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/report_parser.py +0 -0
  130. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/style_profile.py +0 -0
  131. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/template_analyzer.py +0 -0
  132. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/charting/__init__.py +0 -0
  133. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/compliance/__init__.py +0 -0
  134. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/compliance/official_lint.py +0 -0
  135. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/compliance/pii.py +0 -0
  136. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/document_ops/__init__.py +0 -0
  137. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/document_ops/comparison.py +0 -0
  138. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/document_ops/mail_merge.py +0 -0
  139. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/document_ops/redline.py +0 -0
  140. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/evalplan/__init__.py +0 -0
  141. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/evalplan/runtime.py +0 -0
  142. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/__init__.py +0 -0
  143. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/compose.py +0 -0
  144. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/ir.py +0 -0
  145. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/measure.py +0 -0
  146. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/parser.py +0 -0
  147. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/profile.py +0 -0
  148. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/__init__.py +0 -0
  149. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/classification.py +0 -0
  150. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fill_residue.py +0 -0
  151. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/__init__.py +0 -0
  152. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/apply.py +0 -0
  153. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/engine.py +0 -0
  154. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/measure.py +0 -0
  155. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/policy.py +0 -0
  156. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/report.py +0 -0
  157. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/seal.py +0 -0
  158. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/wordbox.py +0 -0
  159. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/guidance.py +0 -0
  160. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/quality.py +0 -0
  161. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/split_run.py +0 -0
  162. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/template_formfit.py +0 -0
  163. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/__init__.py +0 -0
  164. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/composition.py +0 -0
  165. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/data/bank.json +0 -0
  166. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/data/genres.json +0 -0
  167. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/gianmun.py +0 -0
  168. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/org_chart.py +0 -0
  169. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/quality/__init__.py +0 -0
  170. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/quality/page_guard.py +0 -0
  171. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/__init__.py +0 -0
  172. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/_hancom_open_rate.ps1 +0 -0
  173. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/_refresh_hwpx_mac.applescript +0 -0
  174. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/_render_hwpx.ps1 +0 -0
  175. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/block_splits.py +0 -0
  176. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/detectors.py +0 -0
  177. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/diff.py +0 -0
  178. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/fixture_corpus.py +0 -0
  179. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/page_qa.py +0 -0
  180. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/qa_contracts.py +0 -0
  181. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/qa_metrics.py +0 -0
  182. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/utilities/__init__.py +0 -0
  183. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/utilities/table_compute.py +0 -0
  184. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/__init__.py +0 -0
  185. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/_border_fill.py +0 -0
  186. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/composition.py +0 -0
  187. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/content_layout.py +0 -0
  188. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/context.py +0 -0
  189. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/form_fields.py +0 -0
  190. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/media.py +0 -0
  191. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/memo_style.py +0 -0
  192. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/package_validation.py +0 -0
  193. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/planning.py +0 -0
  194. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/preview_export.py +0 -0
  195. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/read_query.py +0 -0
  196. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/save_policy.py +0 -0
  197. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/tables.py +0 -0
  198. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/transactions.py +0 -0
  199. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/preview_output_models.py +0 -0
  200. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/py.typed +0 -0
  201. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/quality.py +0 -0
  202. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/quality_generation.py +0 -0
  203. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/resources.py +0 -0
  204. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/runtime.py +0 -0
  205. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/runtime_services.py +0 -0
  206. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/server.py +0 -0
  207. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/storage.py +0 -0
  208. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/tool_bindings.py +0 -0
  209. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/upstream.py +0 -0
  210. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/utils/__init__.py +0 -0
  211. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/utils/helpers.py +0 -0
  212. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/visual_qa.py +0 -0
  213. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/__init__.py +0 -0
  214. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/adapters.py +0 -0
  215. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/dispatcher.py +0 -0
  216. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/models.py +0 -0
  217. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/policy.py +0 -0
  218. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/render_contracts.py +0 -0
  219. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/render_metrics.py +0 -0
  220. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/render_security.py +0 -0
  221. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/render_transport.py +0 -0
  222. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/rendering.py +0 -0
  223. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/service.py +0 -0
  224. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/state_machine.py +0 -0
  225. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/store.py +0 -0
  226. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workspace.py +0 -0
  227. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/python_hwpx_automation.egg-info/dependency_links.txt +0 -0
  228. {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/python_hwpx_automation.egg-info/entry_points.txt +0 -0
  229. {python_hwpx_automation-7.0.4 → 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.4
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,10 +74,9 @@ Dynamic: license-file
74
74
 
75
75
  <!-- release-state: release-approved -->
76
76
  > [!NOTE]
77
- > 아직 공개되지 않은 7.0.4 후보입니다.
78
- > 후보 조합: `python-hwpx 6.3.0 → python-hwpx-automation 7.0.4 → hwpx-plugin 2.1.0`.
79
- > 공개 트레인: `python-hwpx 6.3.0 → python-hwpx-automation 7.0.3 → hwpx-plugin 2.0.3`.
80
- > 계약은 `8c278ebd5becba08`이며 도구 표면과 최소 호환 버전은 유지합니다.
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`).
81
80
  > 공개 좌표는 core·automation PyPI와 plugin GitHub
82
81
  > Release·marketplace·실제 marketplace 설치 관찰 후에만 승격합니다.
83
82
  > [릴리스 runbook](docs/release-runbook.md)
@@ -134,7 +133,7 @@ Gemini CLI는 `~/.gemini/settings.json`, Cursor·Windsurf는 각 에디터의 MC
134
133
  "command": "uvx",
135
134
  "args": [
136
135
  "--from",
137
- "python-hwpx-automation[mcp]==7.0.3",
136
+ "python-hwpx-automation[mcp]==7.0.4",
138
137
  "hwpx-automation-mcp"
139
138
  ],
140
139
  "env": {
@@ -241,3 +240,5 @@ python scripts/run_conformance.py run \
241
240
  ## License · Maintainer
242
241
 
243
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,10 +14,9 @@
14
14
 
15
15
  <!-- release-state: release-approved -->
16
16
  > [!NOTE]
17
- > 아직 공개되지 않은 7.0.4 후보입니다.
18
- > 후보 조합: `python-hwpx 6.3.0 → python-hwpx-automation 7.0.4 → hwpx-plugin 2.1.0`.
19
- > 공개 트레인: `python-hwpx 6.3.0 → python-hwpx-automation 7.0.3 → hwpx-plugin 2.0.3`.
20
- > 계약은 `8c278ebd5becba08`이며 도구 표면과 최소 호환 버전은 유지합니다.
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`).
21
20
  > 공개 좌표는 core·automation PyPI와 plugin GitHub
22
21
  > Release·marketplace·실제 marketplace 설치 관찰 후에만 승격합니다.
23
22
  > [릴리스 runbook](docs/release-runbook.md)
@@ -74,7 +73,7 @@ Gemini CLI는 `~/.gemini/settings.json`, Cursor·Windsurf는 각 에디터의 MC
74
73
  "command": "uvx",
75
74
  "args": [
76
75
  "--from",
77
- "python-hwpx-automation[mcp]==7.0.3",
76
+ "python-hwpx-automation[mcp]==7.0.4",
78
77
  "hwpx-automation-mcp"
79
78
  ],
80
79
  "env": {
@@ -181,3 +180,5 @@ python scripts/run_conformance.py run \
181
180
  ## License · Maintainer
182
181
 
183
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.4"
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",
@@ -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.4",
10
+ "canonicalAutomation": "7.1.0",
11
11
  "compatibilityDistribution": "hwpx-mcp-server",
12
- "compatibility": "7.0.4",
13
- "plugin": "2.1.0",
14
- "contractHash": "8c278ebd5becba08"
12
+ "compatibility": "7.1.0",
13
+ "plugin": "2.2.0",
14
+ "contractHash": "ba0211fc854a0a97"
15
15
  },
16
16
  "currentPublic": {
17
17
  "pythonHwpx": "6.3.0",
18
18
  "primaryDistribution": "python-hwpx-automation",
19
- "primaryApplication": "7.0.3",
20
- "plugin": "2.0.3",
19
+ "primaryApplication": "7.0.4",
20
+ "plugin": "2.1.0",
21
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,
@@ -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
@@ -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()
@@ -500,11 +500,10 @@ class MacHancomOracle(RenderBackend):
500
500
  open <input> → 파일 (File) > "PDF로 저장하기..." → NSSavePanel (Return = 저장)
501
501
  → 파일 > "문서 닫기"
502
502
 
503
- The save panel is *document-relative* (it pre-fills 위치 = the input's
504
- directory and the name field = the input's stem), so :meth:`render_pdf`
505
- stages the input as ``<out_dir>/<out_stem>.hwpx`` and the panel writes exactly
506
- ``<out_dir>/<out_stem>.pdf`` with no path typing. The target is pre-deleted so
507
- no overwrite sheet appears.
503
+ The save panel is document-relative. Each render stages a uniquely named
504
+ copy in a private temporary directory, exports beside it, closes only that
505
+ owned document, then promotes a complete PDF to the caller's output path.
506
+ Existing caller files survive a failed render.
508
507
 
509
508
  Operational notes: the GUI is a single shared session, so renders MUST be
510
509
  serialized (the default serial :meth:`render_many` does this). Requires a
@@ -599,57 +598,49 @@ class MacHancomOracle(RenderBackend):
599
598
  src = os.path.abspath(hwpx_path)
600
599
  out_pdf = os.path.abspath(out_pdf)
601
600
  out_dir = os.path.dirname(out_pdf)
602
- out_stem = os.path.splitext(os.path.basename(out_pdf))[0]
603
601
  os.makedirs(out_dir, exist_ok=True)
604
602
 
605
- # Stage the input next to the target, named as the target stem, so the
606
- # document-relative save panel needs no typing (see class docstring).
607
- staged = os.path.join(out_dir, out_stem + ".hwpx")
608
- staged_is_source = os.path.abspath(staged) == src
609
-
610
- try: # pre-delete target -> the overwrite ("대치?") sheet never appears
611
- if os.path.exists(out_pdf):
612
- os.remove(out_pdf)
613
- except OSError:
614
- pass
615
-
616
603
  deadline = _deadline_from(self.budget_seconds)
617
604
  run_timeout = _clamped_timeout(self.timeout + 60.0, deadline)
618
605
  if run_timeout is None:
619
606
  return None
620
- # The AppleScript receives its own internal wait limit; keep it inside
621
- # the clamped subprocess timeout so the script never outlives the budget.
622
607
  script_timeout = max(1, int(min(self.timeout, run_timeout)))
623
-
624
- cleanup_staged = False
625
- try:
626
- if not staged_is_source:
627
- shutil.copyfile(src, staged)
628
- cleanup_staged = True
608
+ # Unique owned document name: a prior render or user document can never
609
+ # be mistaken for this job. Never pre-delete or stage over caller files.
610
+ with tempfile.TemporaryDirectory(prefix="hwpx-render-", dir=out_dir) as folder:
611
+ name = Path(folder).name
612
+ staged = Path(folder) / (name + ".hwpx")
613
+ staged_pdf = staged.with_suffix(".pdf")
614
+ shutil.copyfile(src, staged)
629
615
  with resources.as_file(
630
- resources.files("hwpx_automation.office.rendering").joinpath(
631
- _MAC_BACKEND_SCRIPT
632
- )
616
+ resources.files("hwpx_automation.office.rendering").joinpath(_MAC_BACKEND_SCRIPT)
633
617
  ) as script:
634
- cmd = [
635
- self._osascript, str(script), staged, out_pdf, str(script_timeout),
636
- ]
618
+ cmd = [self._osascript, str(script), str(staged), str(staged_pdf), str(script_timeout)]
637
619
  try:
638
- subprocess.run(
639
- cmd, capture_output=True, text=True,
640
- timeout=run_timeout, check=False,
641
- )
620
+ proc = self._run_render_script(cmd, run_timeout)
642
621
  except (subprocess.TimeoutExpired, OSError):
622
+ # Best-effort cleanup is restricted to our uniquely named
623
+ # document. The worker adapter also handles cancellation.
624
+ self._close_owned_document(script, staged.name)
643
625
  return None
644
- if os.path.exists(out_pdf) and os.path.getsize(out_pdf) > 0:
626
+ if proc.returncode != 0 or (proc.stdout or "").strip() != "OK":
627
+ return None
628
+ if staged_pdf.is_file() and staged_pdf.read_bytes().rstrip().endswith(b"%%EOF"):
629
+ os.replace(staged_pdf, out_pdf)
645
630
  return out_pdf
646
631
  return None
647
- finally:
648
- if cleanup_staged:
649
- try:
650
- os.remove(staged)
651
- except OSError:
652
- pass
632
+
633
+ def _run_render_script(self, cmd: list[str], timeout: float) -> subprocess.CompletedProcess[str]:
634
+ return subprocess.run(cmd, capture_output=True, text=True, timeout=timeout, check=False)
635
+
636
+ def _close_owned_document(self, script: Path, name: str) -> None:
637
+ try:
638
+ subprocess.run(
639
+ [self._osascript, str(script), "--close-owned", name],
640
+ capture_output=True, text=True, timeout=3, check=False,
641
+ )
642
+ except (OSError, subprocess.TimeoutExpired):
643
+ pass
653
644
 
654
645
  def refresh_document(self, hwpx_path: str) -> bool:
655
646
  """Open ``hwpx_path``, let dirty fields regenerate, save in place, close.