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.
- {python_hwpx_automation-7.0.4/src/python_hwpx_automation.egg-info → python_hwpx_automation-7.1.0}/PKG-INFO +8 -7
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/README.md +6 -5
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/pyproject.toml +2 -2
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/read_export.py +3 -1
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/identity.json +15 -8
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/cli.py +14 -1
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/document.py +30 -2
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/_render_hwpx_mac.applescript +47 -35
- python_hwpx_automation-7.1.0/src/hwpx_automation/office/rendering/mac_session.py +87 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/oracle.py +33 -42
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/worker.py +55 -17
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/public-modules.json +6 -4
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/tool_contract.py +5 -4
- python_hwpx_automation-7.1.0/src/hwpx_automation/utils/read_budget.py +128 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/render_queue.py +17 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0/src/python_hwpx_automation.egg-info}/PKG-INFO +8 -7
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/python_hwpx_automation.egg-info/SOURCES.txt +2 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/python_hwpx_automation.egg-info/requires.txt +1 -1
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/LICENSE +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/MANIFEST.in +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/NOTICE +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/setup.cfg +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/__init__.pyi +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/__main__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/agent_document.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/api.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/blind_eval.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/capabilities.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/compat.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/configuration.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/content.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/context.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/diff.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/document.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/formatting.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/handles.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/locations.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/locator.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/plan.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/resources.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/search.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/transactions.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/core/txn.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/document_state.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/errors.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/execution_lock.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/fastmcp_adapter.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/form_fill.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/form_output_models.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/_shared.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/agent_document.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/authoring.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/content_edit.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/form_fill.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/layout_style.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/quality_render.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/specialized.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/tracked_changes.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/handlers/workflow.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/hwp_converter.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/hwp_support.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/hwpx_ops.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/identity.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ingest_adapters.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/markdown_plan.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/mcp_cli.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/metadata/tools_meta.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/mixed_form.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/mutation_models.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/network_policy.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/_batch_verification.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/bundle.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/catalog.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/dump.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/mapping.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/model.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/native.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/blueprint/replay.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/catalog.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/commands.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/form_plan.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/model.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/path.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/query.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/agent/story.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/advanced_generators.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/builder/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/builder/core.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/builder/report.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/_support.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/composer.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/harvest.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/plan.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profile.py +0 -0
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/report/profile.json +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/profiles/report/template.hwpx +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/design/validator.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/presets/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/presets/proposal.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/report_parser.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/style_profile.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/authoring/template_analyzer.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/charting/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/compliance/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/compliance/official_lint.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/compliance/pii.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/document_ops/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/document_ops/comparison.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/document_ops/mail_merge.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/document_ops/redline.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/evalplan/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/evalplan/runtime.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/compose.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/ir.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/measure.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/parser.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/exam/profile.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/classification.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fill_residue.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/apply.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/engine.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/measure.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/policy.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/report.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/seal.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/fit/wordbox.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/guidance.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/quality.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/split_run.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/form_fill/template_formfit.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/composition.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/data/bank.json +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/data/genres.json +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/gianmun.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/house_style/org_chart.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/quality/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/quality/page_guard.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/_hancom_open_rate.ps1 +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/_refresh_hwpx_mac.applescript +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/_render_hwpx.ps1 +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/block_splits.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/detectors.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/diff.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/fixture_corpus.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/page_qa.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/qa_contracts.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/rendering/qa_metrics.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/utilities/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/office/utilities/table_compute.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/_border_fill.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/composition.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/content_layout.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/context.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/form_fields.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/media.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/memo_style.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/package_validation.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/planning.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/preview_export.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/read_query.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/save_policy.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/tables.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/ops_services/transactions.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/preview_output_models.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/py.typed +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/quality.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/quality_generation.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/resources.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/runtime.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/runtime_services.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/server.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/storage.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/tool_bindings.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/upstream.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/utils/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/utils/helpers.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/visual_qa.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/__init__.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/adapters.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/dispatcher.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/models.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/policy.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/render_contracts.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/render_metrics.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/render_security.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/render_transport.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/rendering.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/service.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/state_machine.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workflow/store.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/workspace.py +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/python_hwpx_automation.egg-info/dependency_links.txt +0 -0
- {python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/python_hwpx_automation.egg-info/entry_points.txt +0 -0
- {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
|
|
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.
|
|
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
|
-
>
|
|
78
|
-
>
|
|
79
|
-
> 공개 트레인: `python-hwpx 6.3.0 → python-hwpx-automation 7.0.
|
|
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.
|
|
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
|
-
>
|
|
18
|
-
>
|
|
19
|
-
> 공개 트레인: `python-hwpx 6.3.0 → python-hwpx-automation 7.0.
|
|
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.
|
|
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
|
|
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.
|
|
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
|
-
|
|
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(
|
{python_hwpx_automation-7.0.4 → python_hwpx_automation-7.1.0}/src/hwpx_automation/identity.json
RENAMED
|
@@ -5,22 +5,29 @@
|
|
|
5
5
|
"releaseState": {
|
|
6
6
|
"status": "release-approved",
|
|
7
7
|
"candidate": {
|
|
8
|
-
"pythonHwpx": "6.
|
|
8
|
+
"pythonHwpx": "6.4.0",
|
|
9
9
|
"canonicalDistribution": "python-hwpx-automation",
|
|
10
|
-
"canonicalAutomation": "7.0
|
|
10
|
+
"canonicalAutomation": "7.1.0",
|
|
11
11
|
"compatibilityDistribution": "hwpx-mcp-server",
|
|
12
|
-
"compatibility": "7.0
|
|
13
|
-
"plugin": "2.
|
|
14
|
-
"contractHash": "
|
|
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.
|
|
20
|
-
"plugin": "2.0
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
98
|
-
|
|
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
|
-
|
|
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
|
-
--
|
|
225
|
-
--
|
|
226
|
-
on
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
end
|
|
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
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
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.
|