python-hwpx-automation 6.0.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hwpx_automation/__init__.py +61 -0
- hwpx_automation/__init__.pyi +27 -0
- hwpx_automation/__main__.py +8 -0
- hwpx_automation/agent_document.py +392 -0
- hwpx_automation/api.py +136 -0
- hwpx_automation/blind_eval.py +407 -0
- hwpx_automation/capabilities.py +110 -0
- hwpx_automation/compat.py +48 -0
- hwpx_automation/configuration.py +60 -0
- hwpx_automation/core/__init__.py +2 -0
- hwpx_automation/core/content.py +762 -0
- hwpx_automation/core/context.py +111 -0
- hwpx_automation/core/diff.py +53 -0
- hwpx_automation/core/document.py +37 -0
- hwpx_automation/core/formatting.py +513 -0
- hwpx_automation/core/handles.py +24 -0
- hwpx_automation/core/locations.py +205 -0
- hwpx_automation/core/locator.py +162 -0
- hwpx_automation/core/plan.py +680 -0
- hwpx_automation/core/resources.py +42 -0
- hwpx_automation/core/search.py +296 -0
- hwpx_automation/core/transactions.py +434 -0
- hwpx_automation/core/txn.py +48 -0
- hwpx_automation/document_state.py +95 -0
- hwpx_automation/errors.py +174 -0
- hwpx_automation/execution_lock.py +15 -0
- hwpx_automation/fastmcp_adapter.py +672 -0
- hwpx_automation/form_fill.py +1177 -0
- hwpx_automation/form_output_models.py +223 -0
- hwpx_automation/handlers/__init__.py +2 -0
- hwpx_automation/handlers/_shared.py +377 -0
- hwpx_automation/handlers/agent_document.py +257 -0
- hwpx_automation/handlers/authoring.py +750 -0
- hwpx_automation/handlers/content_edit.py +1078 -0
- hwpx_automation/handlers/form_fill.py +607 -0
- hwpx_automation/handlers/layout_style.py +660 -0
- hwpx_automation/handlers/quality_render.py +566 -0
- hwpx_automation/handlers/read_export.py +1295 -0
- hwpx_automation/handlers/specialized.py +624 -0
- hwpx_automation/handlers/tracked_changes.py +589 -0
- hwpx_automation/handlers/workflow.py +105 -0
- hwpx_automation/hwp_converter.py +227 -0
- hwpx_automation/hwp_support.py +94 -0
- hwpx_automation/hwpx_ops.py +1439 -0
- hwpx_automation/identity.json +263 -0
- hwpx_automation/identity.py +18 -0
- hwpx_automation/ingest_adapters.py +85 -0
- hwpx_automation/markdown_plan.py +216 -0
- hwpx_automation/mcp_cli.py +29 -0
- hwpx_automation/metadata/tools_meta.py +40 -0
- hwpx_automation/mixed_form.py +3007 -0
- hwpx_automation/mutation_models.py +401 -0
- hwpx_automation/network_policy.py +232 -0
- hwpx_automation/office/__init__.py +14 -0
- hwpx_automation/office/agent/__init__.py +125 -0
- hwpx_automation/office/agent/_batch_verification.py +383 -0
- hwpx_automation/office/agent/blueprint/__init__.py +58 -0
- hwpx_automation/office/agent/blueprint/bundle.py +282 -0
- hwpx_automation/office/agent/blueprint/catalog.py +136 -0
- hwpx_automation/office/agent/blueprint/dump.py +520 -0
- hwpx_automation/office/agent/blueprint/mapping.py +312 -0
- hwpx_automation/office/agent/blueprint/model.py +722 -0
- hwpx_automation/office/agent/blueprint/native.py +621 -0
- hwpx_automation/office/agent/blueprint/replay.py +622 -0
- hwpx_automation/office/agent/catalog.py +252 -0
- hwpx_automation/office/agent/cli.py +647 -0
- hwpx_automation/office/agent/commands.py +1383 -0
- hwpx_automation/office/agent/document.py +801 -0
- hwpx_automation/office/agent/form_plan.py +1760 -0
- hwpx_automation/office/agent/model.py +808 -0
- hwpx_automation/office/agent/path.py +155 -0
- hwpx_automation/office/agent/query.py +230 -0
- hwpx_automation/office/agent/story.py +207 -0
- hwpx_automation/office/authoring/__init__.py +3542 -0
- hwpx_automation/office/authoring/advanced_generators.py +154 -0
- hwpx_automation/office/authoring/builder/__init__.py +52 -0
- hwpx_automation/office/authoring/builder/core.py +996 -0
- hwpx_automation/office/authoring/builder/report.py +195 -0
- hwpx_automation/office/authoring/design/__init__.py +30 -0
- hwpx_automation/office/authoring/design/_support.py +144 -0
- hwpx_automation/office/authoring/design/composer.py +282 -0
- hwpx_automation/office/authoring/design/harvest.py +305 -0
- hwpx_automation/office/authoring/design/plan.py +69 -0
- hwpx_automation/office/authoring/design/profile.py +88 -0
- hwpx_automation/office/authoring/design/profiles/application_form/fragments/body.xml +1 -0
- hwpx_automation/office/authoring/design/profiles/application_form/fragments/heading.xml +1 -0
- hwpx_automation/office/authoring/design/profiles/application_form/fragments/info_table.xml +1 -0
- hwpx_automation/office/authoring/design/profiles/application_form/fragments/title.xml +1 -0
- hwpx_automation/office/authoring/design/profiles/application_form/profile.json +25 -0
- hwpx_automation/office/authoring/design/profiles/application_form/template.hwpx +0 -0
- hwpx_automation/office/authoring/design/profiles/home_notice/fragments/body.xml +1 -0
- hwpx_automation/office/authoring/design/profiles/home_notice/fragments/heading.xml +1 -0
- hwpx_automation/office/authoring/design/profiles/home_notice/fragments/title.xml +1 -0
- hwpx_automation/office/authoring/design/profiles/home_notice/profile.json +24 -0
- hwpx_automation/office/authoring/design/profiles/home_notice/template.hwpx +0 -0
- hwpx_automation/office/authoring/design/profiles/official_notice/fragments/body.xml +1 -0
- hwpx_automation/office/authoring/design/profiles/official_notice/fragments/heading.xml +1 -0
- hwpx_automation/office/authoring/design/profiles/official_notice/fragments/info_table.xml +1 -0
- hwpx_automation/office/authoring/design/profiles/official_notice/fragments/title.xml +1 -0
- hwpx_automation/office/authoring/design/profiles/official_notice/profile.json +25 -0
- hwpx_automation/office/authoring/design/profiles/official_notice/template.hwpx +0 -0
- hwpx_automation/office/authoring/design/profiles/report/fragments/body.xml +1 -0
- hwpx_automation/office/authoring/design/profiles/report/fragments/heading.xml +1 -0
- hwpx_automation/office/authoring/design/profiles/report/fragments/info_table.xml +1 -0
- hwpx_automation/office/authoring/design/profiles/report/fragments/title.xml +1 -0
- hwpx_automation/office/authoring/design/profiles/report/profile.json +25 -0
- hwpx_automation/office/authoring/design/profiles/report/template.hwpx +0 -0
- hwpx_automation/office/authoring/design/validator.py +107 -0
- hwpx_automation/office/authoring/presets/__init__.py +22 -0
- hwpx_automation/office/authoring/presets/proposal.py +538 -0
- hwpx_automation/office/authoring/report_parser.py +141 -0
- hwpx_automation/office/authoring/style_profile.py +437 -0
- hwpx_automation/office/authoring/template_analyzer.py +657 -0
- hwpx_automation/office/compliance/__init__.py +38 -0
- hwpx_automation/office/compliance/official_lint.py +478 -0
- hwpx_automation/office/compliance/pii.py +388 -0
- hwpx_automation/office/document_ops/__init__.py +13 -0
- hwpx_automation/office/document_ops/comparison.py +62 -0
- hwpx_automation/office/document_ops/mail_merge.py +73 -0
- hwpx_automation/office/document_ops/redline.py +35 -0
- hwpx_automation/office/evalplan/__init__.py +36 -0
- hwpx_automation/office/evalplan/runtime.py +2762 -0
- hwpx_automation/office/exam/__init__.py +44 -0
- hwpx_automation/office/exam/compose.py +282 -0
- hwpx_automation/office/exam/ir.py +44 -0
- hwpx_automation/office/exam/measure.py +163 -0
- hwpx_automation/office/exam/parser.py +150 -0
- hwpx_automation/office/exam/profile.py +123 -0
- hwpx_automation/office/form_fill/__init__.py +66 -0
- hwpx_automation/office/form_fill/classification.py +108 -0
- hwpx_automation/office/form_fill/fill_residue.py +242 -0
- hwpx_automation/office/form_fill/fit/__init__.py +36 -0
- hwpx_automation/office/form_fill/fit/apply.py +24 -0
- hwpx_automation/office/form_fill/fit/engine.py +24 -0
- hwpx_automation/office/form_fill/fit/measure.py +50 -0
- hwpx_automation/office/form_fill/fit/policy.py +28 -0
- hwpx_automation/office/form_fill/fit/report.py +28 -0
- hwpx_automation/office/form_fill/fit/seal.py +457 -0
- hwpx_automation/office/form_fill/fit/wordbox.py +1343 -0
- hwpx_automation/office/form_fill/guidance.py +704 -0
- hwpx_automation/office/form_fill/quality.py +961 -0
- hwpx_automation/office/form_fill/split_run.py +333 -0
- hwpx_automation/office/form_fill/template_formfit.py +656 -0
- hwpx_automation/office/house_style/__init__.py +196 -0
- hwpx_automation/office/house_style/composition.py +68 -0
- hwpx_automation/office/house_style/data/bank.json +625 -0
- hwpx_automation/office/house_style/data/genres.json +43 -0
- hwpx_automation/office/quality/__init__.py +14 -0
- hwpx_automation/office/quality/page_guard.py +277 -0
- hwpx_automation/office/rendering/__init__.py +145 -0
- hwpx_automation/office/rendering/_hancom_open_rate.ps1 +374 -0
- hwpx_automation/office/rendering/_refresh_hwpx_mac.applescript +162 -0
- hwpx_automation/office/rendering/_render_hwpx.ps1 +72 -0
- hwpx_automation/office/rendering/_render_hwpx_mac.applescript +249 -0
- hwpx_automation/office/rendering/block_splits.py +76 -0
- hwpx_automation/office/rendering/detectors.py +151 -0
- hwpx_automation/office/rendering/diff.py +153 -0
- hwpx_automation/office/rendering/fixture_corpus.py +215 -0
- hwpx_automation/office/rendering/oracle.py +909 -0
- hwpx_automation/office/rendering/page_qa.py +245 -0
- hwpx_automation/office/rendering/qa_contracts.py +293 -0
- hwpx_automation/office/rendering/qa_metrics.py +241 -0
- hwpx_automation/office/rendering/worker.py +290 -0
- hwpx_automation/office/utilities/__init__.py +12 -0
- hwpx_automation/office/utilities/table_compute.py +477 -0
- hwpx_automation/ops_services/__init__.py +1 -0
- hwpx_automation/ops_services/_border_fill.py +283 -0
- hwpx_automation/ops_services/composition.py +55 -0
- hwpx_automation/ops_services/content_layout.py +322 -0
- hwpx_automation/ops_services/context.py +213 -0
- hwpx_automation/ops_services/form_fields.py +557 -0
- hwpx_automation/ops_services/media.py +178 -0
- hwpx_automation/ops_services/memo_style.py +477 -0
- hwpx_automation/ops_services/package_validation.py +166 -0
- hwpx_automation/ops_services/planning.py +201 -0
- hwpx_automation/ops_services/preview_export.py +585 -0
- hwpx_automation/ops_services/read_query.py +601 -0
- hwpx_automation/ops_services/save_policy.py +604 -0
- hwpx_automation/ops_services/tables.py +539 -0
- hwpx_automation/ops_services/transactions.py +616 -0
- hwpx_automation/preview_output_models.py +69 -0
- hwpx_automation/public-modules.json +206 -0
- hwpx_automation/py.typed +1 -0
- hwpx_automation/quality.py +351 -0
- hwpx_automation/quality_generation.py +725 -0
- hwpx_automation/runtime.py +321 -0
- hwpx_automation/runtime_services.py +100 -0
- hwpx_automation/server.py +259 -0
- hwpx_automation/storage.py +747 -0
- hwpx_automation/tool_bindings.py +170 -0
- hwpx_automation/tool_contract.py +982 -0
- hwpx_automation/upstream.py +755 -0
- hwpx_automation/utils/__init__.py +2 -0
- hwpx_automation/utils/helpers.py +29 -0
- hwpx_automation/visual_qa.py +667 -0
- hwpx_automation/workflow/__init__.py +55 -0
- hwpx_automation/workflow/adapters.py +482 -0
- hwpx_automation/workflow/dispatcher.py +213 -0
- hwpx_automation/workflow/models.py +243 -0
- hwpx_automation/workflow/policy.py +198 -0
- hwpx_automation/workflow/render_contracts.py +173 -0
- hwpx_automation/workflow/render_metrics.py +196 -0
- hwpx_automation/workflow/render_queue.py +482 -0
- hwpx_automation/workflow/render_security.py +172 -0
- hwpx_automation/workflow/render_transport.py +369 -0
- hwpx_automation/workflow/rendering.py +206 -0
- hwpx_automation/workflow/service.py +758 -0
- hwpx_automation/workflow/state_machine.py +65 -0
- hwpx_automation/workflow/store.py +747 -0
- hwpx_automation/workspace.py +1694 -0
- python_hwpx_automation-6.0.3.dist-info/METADATA +279 -0
- python_hwpx_automation-6.0.3.dist-info/RECORD +217 -0
- python_hwpx_automation-6.0.3.dist-info/WHEEL +5 -0
- python_hwpx_automation-6.0.3.dist-info/entry_points.txt +3 -0
- python_hwpx_automation-6.0.3.dist-info/licenses/LICENSE +178 -0
- python_hwpx_automation-6.0.3.dist-info/licenses/NOTICE +14 -0
- python_hwpx_automation-6.0.3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "python-hwpx-automation.identity/v1",
|
|
3
|
+
"product": "python-hwpx-automation",
|
|
4
|
+
"releaseMajor": 6,
|
|
5
|
+
"releaseState": {
|
|
6
|
+
"status": "release-approved",
|
|
7
|
+
"candidate": {
|
|
8
|
+
"pythonHwpx": "5.0.1",
|
|
9
|
+
"canonicalDistribution": "python-hwpx-automation",
|
|
10
|
+
"canonicalAutomation": "6.0.3",
|
|
11
|
+
"compatibilityDistribution": "hwpx-mcp-server",
|
|
12
|
+
"compatibility": "6.0.3",
|
|
13
|
+
"plugin": "1.0.0",
|
|
14
|
+
"contractHash": "0ce938371f0b55a6"
|
|
15
|
+
},
|
|
16
|
+
"currentPublic": {
|
|
17
|
+
"pythonHwpx": "4.2.0",
|
|
18
|
+
"primaryDistribution": "hwpx-mcp-server",
|
|
19
|
+
"primaryApplication": "5.1.0",
|
|
20
|
+
"plugin": "0.8.0",
|
|
21
|
+
"contractHash": "429cb6706323e762"
|
|
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."
|
|
24
|
+
},
|
|
25
|
+
"identifiers": [
|
|
26
|
+
{
|
|
27
|
+
"surface": "repository",
|
|
28
|
+
"value": "airmang/python-hwpx-automation",
|
|
29
|
+
"classification": "canonical"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"surface": "distribution",
|
|
33
|
+
"value": "python-hwpx-automation",
|
|
34
|
+
"classification": "canonical"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"surface": "import-namespace",
|
|
38
|
+
"value": "hwpx_automation",
|
|
39
|
+
"classification": "canonical"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"surface": "task-console",
|
|
43
|
+
"value": "hwpx",
|
|
44
|
+
"classification": "canonical"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"surface": "mcp-console",
|
|
48
|
+
"value": "hwpx-automation-mcp",
|
|
49
|
+
"classification": "canonical"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"surface": "fastmcp-server-info-name",
|
|
53
|
+
"value": "python-hwpx-automation",
|
|
54
|
+
"classification": "canonical"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"surface": "host-config-key",
|
|
58
|
+
"value": "hwpx",
|
|
59
|
+
"classification": "host-local-alias"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"surface": "environment-prefix",
|
|
63
|
+
"value": "HWPX_AUTOMATION_",
|
|
64
|
+
"classification": "canonical"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"surface": "distribution",
|
|
68
|
+
"value": "hwpx-mcp-server",
|
|
69
|
+
"classification": "compatibility"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"surface": "import-namespace",
|
|
73
|
+
"value": "hwpx_mcp_server",
|
|
74
|
+
"classification": "compatibility"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"surface": "mcp-console",
|
|
78
|
+
"value": "hwpx-mcp-server",
|
|
79
|
+
"classification": "compatibility"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"surface": "environment-prefix",
|
|
83
|
+
"value": "HWPX_MCP_",
|
|
84
|
+
"classification": "compatibility"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"surface": "capability-version-field",
|
|
88
|
+
"value": "versions.automation",
|
|
89
|
+
"classification": "canonical"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"surface": "capability-version-field",
|
|
93
|
+
"value": "versions.mcp",
|
|
94
|
+
"classification": "compatibility-preserved"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"surface": "capability-floor-field",
|
|
98
|
+
"value": "minAutomationVersion",
|
|
99
|
+
"classification": "canonical"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"surface": "capability-floor-field",
|
|
103
|
+
"value": "minMcpVersion",
|
|
104
|
+
"classification": "compatibility-preserved"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"surface": "contract-floor-constant",
|
|
108
|
+
"value": "MIN_AUTOMATION_VERSION",
|
|
109
|
+
"classification": "canonical"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"surface": "contract-floor-constant",
|
|
113
|
+
"value": "MIN_MCP_VERSION",
|
|
114
|
+
"classification": "compatibility-preserved"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"surface": "protocol-error-schema",
|
|
118
|
+
"value": "hwpx.mcp-error/v1",
|
|
119
|
+
"classification": "compatibility-preserved"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"surface": "frozen-receipt-schema",
|
|
123
|
+
"value": "hwpx-mcp.authoring-runtime-owner/v1",
|
|
124
|
+
"classification": "compatibility-preserved"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"surface": "frozen-receipt-schema",
|
|
128
|
+
"value": "hwpx-mcp.compliance-quality-utilities-owner/v1",
|
|
129
|
+
"classification": "compatibility-preserved"
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"surface": "frozen-receipt-schema",
|
|
133
|
+
"value": "hwpx-mcp.document-operations-owner/v1",
|
|
134
|
+
"classification": "compatibility-preserved"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"surface": "frozen-receipt-schema",
|
|
138
|
+
"value": "hwpx-mcp.evalplan-runtime-owner/v1",
|
|
139
|
+
"classification": "compatibility-preserved"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"surface": "frozen-receipt-schema",
|
|
143
|
+
"value": "hwpx-mcp.exam-runtime-owner/v1",
|
|
144
|
+
"classification": "compatibility-preserved"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"surface": "frozen-receipt-schema",
|
|
148
|
+
"value": "hwpx-mcp.form-fill-runtime-owner/v1",
|
|
149
|
+
"classification": "compatibility-preserved"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"surface": "frozen-receipt-schema",
|
|
153
|
+
"value": "hwpx-mcp.form-fill-runtime-parity/v1",
|
|
154
|
+
"classification": "compatibility-preserved"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"surface": "frozen-receipt-schema",
|
|
158
|
+
"value": "hwpx-mcp.visual-runtime-owner/v1",
|
|
159
|
+
"classification": "compatibility-preserved"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"surface": "frozen-parity-receipt-field",
|
|
163
|
+
"value": "mcpRuntimeMembers",
|
|
164
|
+
"classification": "compatibility-preserved"
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"surface": "workflow-state-environment",
|
|
168
|
+
"value": "HWPX_AUTOMATION_WORKFLOW_STORE",
|
|
169
|
+
"classification": "canonical"
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"surface": "workflow-state-environment",
|
|
173
|
+
"value": "HWPX_WORKFLOW_STORE",
|
|
174
|
+
"classification": "compatibility-preserved"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"surface": "workflow-state-path",
|
|
178
|
+
"value": "${XDG_STATE_HOME:-~/.local/state}/hwpx-mcp-server/workflows.sqlite3",
|
|
179
|
+
"classification": "compatibility-preserved"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"surface": "render-queue-principal",
|
|
183
|
+
"value": "hwpx-mcp-server",
|
|
184
|
+
"classification": "compatibility-preserved"
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"surface": "render-integration-environment",
|
|
188
|
+
"value": "HWPX_RENDER_QUEUE_ROOT",
|
|
189
|
+
"classification": "integration-preserved"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"surface": "render-integration-environment",
|
|
193
|
+
"value": "HWPX_RENDER_QUEUE_URL",
|
|
194
|
+
"classification": "integration-preserved"
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"surface": "render-integration-environment",
|
|
198
|
+
"value": "HWPX_RENDER_QUEUE_SECRET",
|
|
199
|
+
"classification": "integration-preserved"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"surface": "render-integration-environment",
|
|
203
|
+
"value": "HWPX_RENDER_TRANSPORT_AUTH",
|
|
204
|
+
"classification": "integration-preserved"
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"surface": "render-integration-environment",
|
|
208
|
+
"value": "HWPX_RENDER_CA_FILE",
|
|
209
|
+
"classification": "integration-preserved"
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"surface": "render-integration-environment",
|
|
213
|
+
"value": "HWPX_RENDER_CLIENT_CERT_FILE",
|
|
214
|
+
"classification": "integration-preserved"
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"surface": "render-integration-environment",
|
|
218
|
+
"value": "HWPX_RENDER_CLIENT_KEY_FILE",
|
|
219
|
+
"classification": "integration-preserved"
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"surface": "workflow-security-environment",
|
|
223
|
+
"value": "HWPX_WORKFLOW_ENCRYPTION_KEY",
|
|
224
|
+
"classification": "capability-preserved"
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"surface": "oracle-capability-environment",
|
|
228
|
+
"value": "HWPX_ORACLE_STRUCTURAL_ONLY",
|
|
229
|
+
"classification": "capability-preserved"
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"surface": "oracle-capability-environment",
|
|
233
|
+
"value": "HWPX_ORACLE_BUDGET_SECONDS",
|
|
234
|
+
"classification": "capability-preserved"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"surface": "plugin-integration-environment",
|
|
238
|
+
"value": "HWPX_SKILL_VERSION",
|
|
239
|
+
"classification": "integration-preserved"
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"surface": "plugin-integration-environment",
|
|
243
|
+
"value": "HWPX_PLUGIN_ROOT",
|
|
244
|
+
"classification": "integration-preserved"
|
|
245
|
+
}
|
|
246
|
+
],
|
|
247
|
+
"compatibilityPolicy": {
|
|
248
|
+
"supportedThroughMajor": 6,
|
|
249
|
+
"removalNotBeforeMajor": 7,
|
|
250
|
+
"minimumPublicNoticeDays": 90,
|
|
251
|
+
"requiresObservedUsageWindow": true,
|
|
252
|
+
"requiresSeparateOwnerApproval": true,
|
|
253
|
+
"statePathMigrationInMajor6": false
|
|
254
|
+
},
|
|
255
|
+
"notes": {
|
|
256
|
+
"hostConfigKey": "The key is a host-local alias, not the MCP protocol identity.",
|
|
257
|
+
"environmentPrecedence": "HWPX_AUTOMATION_* wins; HWPX_MCP_* remains a 6.x fallback.",
|
|
258
|
+
"preservedWireIdentifiers": "The public hwpx.mcp-error/v1 schema, versions.mcp/minMcpVersion/MIN_MCP_VERSION aliases, frozen hwpx-mcp.* architecture receipt IDs, and mcpRuntimeMembers parity-receipt field remain exact in 6.x. They are compatibility identifiers, not statements that MCP owns the automation product.",
|
|
259
|
+
"preservedIntegrationEnvironment": "Product-neutral HWPX_RENDER_*, HWPX_WORKFLOW_ENCRYPTION_KEY, HWPX_ORACLE_*, HWPX_SKILL_VERSION, and HWPX_PLUGIN_ROOT names do not encode the former MCP product identity. They remain unchanged and are not aliases in the HWPX_AUTOMATION_ transition.",
|
|
260
|
+
"statePath": "HWPX_AUTOMATION_WORKFLOW_STORE wins over the prior HWPX_WORKFLOW_STORE override; the existing hwpx-mcp-server on-disk default remains in 6.x to avoid silent workflow loss.",
|
|
261
|
+
"renderQueuePrincipal": "The signed queue principal remains hwpx-mcp-server in 6.x so queued work and worker authorization do not split during the rename."
|
|
262
|
+
}
|
|
263
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""Load the installed product-identity contract."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
from importlib.resources import files
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def product_identity() -> dict[str, Any]:
|
|
12
|
+
"""Return a detached copy of the installed identity manifest."""
|
|
13
|
+
|
|
14
|
+
resource = files("hwpx_automation").joinpath("identity.json")
|
|
15
|
+
return json.loads(resource.read_text(encoding="utf-8"))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__all__ = ["product_identity"]
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""Optional document-ingest adapters for the MCP server layer."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import tempfile
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, BinaryIO
|
|
9
|
+
|
|
10
|
+
from hwpx.ingest import (
|
|
11
|
+
DocumentIngestError,
|
|
12
|
+
DocumentIngestResult,
|
|
13
|
+
DocumentSourceInfo,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MissingMarkItDownDependency(DocumentIngestError):
|
|
18
|
+
"""Raised when the optional MarkItDown runtime is not installed."""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class MarkItDownAdapter:
|
|
22
|
+
"""Fallback converter that delegates non-HWPX sources to Microsoft MarkItDown."""
|
|
23
|
+
|
|
24
|
+
name = "MarkItDownAdapter"
|
|
25
|
+
|
|
26
|
+
def accepts(self, file_stream: BinaryIO, source_info: DocumentSourceInfo) -> bool:
|
|
27
|
+
del file_stream
|
|
28
|
+
extension = (source_info.extension or "").lower()
|
|
29
|
+
return extension != ".hwpx"
|
|
30
|
+
|
|
31
|
+
def convert(
|
|
32
|
+
self,
|
|
33
|
+
file_stream: BinaryIO,
|
|
34
|
+
source_info: DocumentSourceInfo,
|
|
35
|
+
**kwargs: Any,
|
|
36
|
+
) -> DocumentIngestResult:
|
|
37
|
+
del kwargs
|
|
38
|
+
markitdown_cls = _load_markitdown_class()
|
|
39
|
+
source_path = _source_path(file_stream, source_info)
|
|
40
|
+
result = markitdown_cls().convert(str(source_path))
|
|
41
|
+
markdown = _extract_markdown(result)
|
|
42
|
+
return DocumentIngestResult(
|
|
43
|
+
markdown=markdown,
|
|
44
|
+
source_info=source_info,
|
|
45
|
+
source_format=(source_info.extension or "unknown").lstrip(".") or "unknown",
|
|
46
|
+
engine="markitdown",
|
|
47
|
+
metadata={"converter": self.name},
|
|
48
|
+
warnings=[
|
|
49
|
+
"Converted by optional MarkItDown adapter; layout fidelity is not claimed.",
|
|
50
|
+
],
|
|
51
|
+
lossiness="unknown",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _load_markitdown_class() -> type:
|
|
56
|
+
try:
|
|
57
|
+
from markitdown import MarkItDown
|
|
58
|
+
except ImportError as exc:
|
|
59
|
+
raise MissingMarkItDownDependency(
|
|
60
|
+
"install python-hwpx-automation[ingest] (or hwpx-mcp-server[ingest]) "
|
|
61
|
+
"to enable non-HWPX document ingest"
|
|
62
|
+
) from exc
|
|
63
|
+
return MarkItDown
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _source_path(file_stream: BinaryIO, source_info: DocumentSourceInfo) -> Path:
|
|
67
|
+
if source_info.local_path:
|
|
68
|
+
return Path(source_info.local_path)
|
|
69
|
+
|
|
70
|
+
suffix = source_info.extension or ""
|
|
71
|
+
with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp:
|
|
72
|
+
start_pos = file_stream.tell()
|
|
73
|
+
tmp.write(file_stream.read())
|
|
74
|
+
file_stream.seek(start_pos)
|
|
75
|
+
return Path(tmp.name)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _extract_markdown(result: Any) -> str:
|
|
79
|
+
for attr in ("text_content", "markdown", "text"):
|
|
80
|
+
value = getattr(result, attr, None)
|
|
81
|
+
if isinstance(value, str):
|
|
82
|
+
return value
|
|
83
|
+
if isinstance(result, str):
|
|
84
|
+
return result
|
|
85
|
+
raise ValueError("MarkItDown result did not include Markdown text")
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""Markdown-to-document-plan bridge."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import re
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import Any, Mapping
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(frozen=True, slots=True)
|
|
12
|
+
class MarkdownPlanResult:
|
|
13
|
+
plan: dict[str, Any]
|
|
14
|
+
warnings: list[str]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def markdown_to_document_plan(
|
|
18
|
+
markdown: str,
|
|
19
|
+
*,
|
|
20
|
+
title: str | None = None,
|
|
21
|
+
metadata: Mapping[str, Any] | None = None,
|
|
22
|
+
style_preset: str = "standard_korean_business",
|
|
23
|
+
) -> MarkdownPlanResult:
|
|
24
|
+
"""Convert a conservative Markdown subset into ``hwpx.document_plan.v1``."""
|
|
25
|
+
|
|
26
|
+
warnings: list[str] = []
|
|
27
|
+
blocks: list[dict[str, Any]] = []
|
|
28
|
+
lines = (markdown or "").replace("\r\n", "\n").replace("\r", "\n").split("\n")
|
|
29
|
+
resolved_title = (title or "").strip()
|
|
30
|
+
index = 0
|
|
31
|
+
|
|
32
|
+
while index < len(lines):
|
|
33
|
+
line = lines[index]
|
|
34
|
+
stripped = line.strip()
|
|
35
|
+
if not stripped:
|
|
36
|
+
index += 1
|
|
37
|
+
continue
|
|
38
|
+
|
|
39
|
+
if table := _parse_table(lines, index):
|
|
40
|
+
table_block, next_index = table
|
|
41
|
+
blocks.append(table_block)
|
|
42
|
+
index = next_index
|
|
43
|
+
continue
|
|
44
|
+
|
|
45
|
+
heading = _parse_heading(stripped)
|
|
46
|
+
if heading is not None:
|
|
47
|
+
level, text = heading
|
|
48
|
+
if not resolved_title and level == 1 and not blocks:
|
|
49
|
+
resolved_title = text
|
|
50
|
+
else:
|
|
51
|
+
blocks.append({"type": "heading", "level": min(level, 3), "text": text})
|
|
52
|
+
if level > 3:
|
|
53
|
+
warnings.append(f"Heading level {level} was clamped to document_plan level 3.")
|
|
54
|
+
index += 1
|
|
55
|
+
continue
|
|
56
|
+
|
|
57
|
+
if _is_list_item(stripped):
|
|
58
|
+
items, next_index, ordered = _collect_list(lines, index)
|
|
59
|
+
blocks.append({"type": "bullets", "items": items})
|
|
60
|
+
if ordered:
|
|
61
|
+
warnings.append("Ordered Markdown lists were converted to bullet blocks.")
|
|
62
|
+
index = next_index
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
paragraph, next_index = _collect_paragraph(lines, index)
|
|
66
|
+
if paragraph:
|
|
67
|
+
blocks.append({"type": "paragraph", "text": paragraph})
|
|
68
|
+
index = next_index
|
|
69
|
+
|
|
70
|
+
if not resolved_title:
|
|
71
|
+
resolved_title = _title_from_blocks(blocks) or "Markdown Import"
|
|
72
|
+
|
|
73
|
+
if not blocks:
|
|
74
|
+
blocks.append({"type": "paragraph", "text": "작성 필요"})
|
|
75
|
+
warnings.append("Markdown had no content blocks; inserted an empty paragraph placeholder.")
|
|
76
|
+
|
|
77
|
+
quality_gates = {
|
|
78
|
+
"validatePackage": True,
|
|
79
|
+
"validateDocument": True,
|
|
80
|
+
"reopen": True,
|
|
81
|
+
"minNonEmptyParagraphs": max(1, _non_empty_block_count(blocks)),
|
|
82
|
+
"visualReviewRequired": True,
|
|
83
|
+
}
|
|
84
|
+
return MarkdownPlanResult(
|
|
85
|
+
plan={
|
|
86
|
+
"schemaVersion": "hwpx.document_plan.v1",
|
|
87
|
+
"title": resolved_title,
|
|
88
|
+
"metadata": _string_metadata(metadata or {}),
|
|
89
|
+
"stylePreset": style_preset,
|
|
90
|
+
"blocks": blocks,
|
|
91
|
+
"qualityGates": quality_gates,
|
|
92
|
+
},
|
|
93
|
+
warnings=warnings,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _parse_heading(stripped: str) -> tuple[int, str] | None:
|
|
98
|
+
match = re.match(r"^(#{1,6})\s+(.+?)\s*#*\s*$", stripped)
|
|
99
|
+
if not match:
|
|
100
|
+
return None
|
|
101
|
+
return len(match.group(1)), match.group(2).strip()
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _is_list_item(stripped: str) -> bool:
|
|
105
|
+
return bool(re.match(r"^([-+*])\s+.+", stripped) or re.match(r"^\d+[.)]\s+.+", stripped))
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _collect_list(lines: list[str], index: int) -> tuple[list[str], int, bool]:
|
|
109
|
+
items: list[str] = []
|
|
110
|
+
ordered = False
|
|
111
|
+
while index < len(lines):
|
|
112
|
+
stripped = lines[index].strip()
|
|
113
|
+
unordered = re.match(r"^[-+*]\s+(.+)$", stripped)
|
|
114
|
+
numbered = re.match(r"^\d+[.)]\s+(.+)$", stripped)
|
|
115
|
+
if unordered:
|
|
116
|
+
items.append(unordered.group(1).strip())
|
|
117
|
+
elif numbered:
|
|
118
|
+
ordered = True
|
|
119
|
+
items.append(numbered.group(1).strip())
|
|
120
|
+
else:
|
|
121
|
+
break
|
|
122
|
+
index += 1
|
|
123
|
+
return items, index, ordered
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _collect_paragraph(lines: list[str], index: int) -> tuple[str, int]:
|
|
127
|
+
parts: list[str] = []
|
|
128
|
+
while index < len(lines):
|
|
129
|
+
stripped = lines[index].strip()
|
|
130
|
+
if not stripped or _parse_heading(stripped) or _is_list_item(stripped) or _parse_table(lines, index):
|
|
131
|
+
break
|
|
132
|
+
parts.append(stripped)
|
|
133
|
+
index += 1
|
|
134
|
+
return " ".join(parts).strip(), index
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _parse_table(lines: list[str], index: int) -> tuple[dict[str, Any], int] | None:
|
|
138
|
+
if index + 1 >= len(lines):
|
|
139
|
+
return None
|
|
140
|
+
header = lines[index].strip()
|
|
141
|
+
divider = lines[index + 1].strip()
|
|
142
|
+
if not _looks_like_table_row(header) or not _looks_like_divider(divider):
|
|
143
|
+
return None
|
|
144
|
+
|
|
145
|
+
labels = _split_table_row(header)
|
|
146
|
+
if not labels:
|
|
147
|
+
return None
|
|
148
|
+
keys = [f"col{col_index + 1}" for col_index in range(len(labels))]
|
|
149
|
+
rows: list[dict[str, str]] = []
|
|
150
|
+
index += 2
|
|
151
|
+
while index < len(lines) and _looks_like_table_row(lines[index].strip()):
|
|
152
|
+
cells = _split_table_row(lines[index].strip())
|
|
153
|
+
row = {
|
|
154
|
+
key: cells[col_index].strip() if col_index < len(cells) else ""
|
|
155
|
+
for col_index, key in enumerate(keys)
|
|
156
|
+
}
|
|
157
|
+
rows.append(row)
|
|
158
|
+
index += 1
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
"type": "table",
|
|
162
|
+
"columns": [
|
|
163
|
+
{"key": key, "label": label.strip() or key}
|
|
164
|
+
for key, label in zip(keys, labels)
|
|
165
|
+
],
|
|
166
|
+
"rows": rows,
|
|
167
|
+
}, index
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def _looks_like_table_row(line: str) -> bool:
|
|
171
|
+
return "|" in line and len(_split_table_row(line)) >= 2
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _looks_like_divider(line: str) -> bool:
|
|
175
|
+
cells = _split_table_row(line)
|
|
176
|
+
return bool(cells) and all(re.match(r"^:?-{3,}:?$", cell.strip()) for cell in cells)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _split_table_row(line: str) -> list[str]:
|
|
180
|
+
stripped = line.strip()
|
|
181
|
+
if stripped.startswith("|"):
|
|
182
|
+
stripped = stripped[1:]
|
|
183
|
+
if stripped.endswith("|"):
|
|
184
|
+
stripped = stripped[:-1]
|
|
185
|
+
return [cell.replace(r"\|", "|").strip() for cell in stripped.split("|")]
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _title_from_blocks(blocks: list[dict[str, Any]]) -> str:
|
|
189
|
+
for block in blocks:
|
|
190
|
+
text = str(block.get("text") or "").strip()
|
|
191
|
+
if block.get("type") == "heading" and text:
|
|
192
|
+
return text
|
|
193
|
+
for block in blocks:
|
|
194
|
+
text = str(block.get("text") or "").strip()
|
|
195
|
+
if text:
|
|
196
|
+
return text[:80]
|
|
197
|
+
return ""
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _string_metadata(metadata: Mapping[str, Any]) -> dict[str, str]:
|
|
201
|
+
return {
|
|
202
|
+
str(key): str(value)
|
|
203
|
+
for key, value in metadata.items()
|
|
204
|
+
if value is not None and str(value).strip()
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _non_empty_block_count(blocks: list[dict[str, Any]]) -> int:
|
|
209
|
+
count = 0
|
|
210
|
+
for block in blocks:
|
|
211
|
+
kind = block.get("type")
|
|
212
|
+
if kind in {"heading", "paragraph"} and str(block.get("text") or "").strip():
|
|
213
|
+
count += 1
|
|
214
|
+
elif kind == "bullets":
|
|
215
|
+
count += len(block.get("items") or [])
|
|
216
|
+
return count
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""Guarded entry point for the optional MCP adapter."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import sys
|
|
7
|
+
from collections.abc import Sequence
|
|
8
|
+
|
|
9
|
+
_INSTALL_HINT = (
|
|
10
|
+
'MCP support is optional. Install it with '
|
|
11
|
+
'"python-hwpx-automation[mcp]" and retry.'
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main(argv: Sequence[str] | None = None) -> None:
|
|
16
|
+
"""Start the MCP adapter or fail with an actionable extra-install hint."""
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
from .server import main as server_main
|
|
20
|
+
except ModuleNotFoundError as exc:
|
|
21
|
+
if exc.name == "mcp" or (exc.name or "").startswith("mcp."):
|
|
22
|
+
print(_INSTALL_HINT, file=sys.stderr)
|
|
23
|
+
raise SystemExit(2) from exc
|
|
24
|
+
raise
|
|
25
|
+
server_main(list(argv) if argv is not None else None)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if __name__ == "__main__":
|
|
29
|
+
main()
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""Static metadata used for hardened tool responses."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import Dict
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class ExampleTemplate:
|
|
12
|
+
tool: str
|
|
13
|
+
example_json: str
|
|
14
|
+
|
|
15
|
+
def render(self, plan_id: str) -> Dict[str, str]:
|
|
16
|
+
return {
|
|
17
|
+
"tool": self.tool,
|
|
18
|
+
"exampleJson": self.example_json.replace("<plan-id>", plan_id),
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
PLAN_NEXT_ACTION = ExampleTemplate(
|
|
23
|
+
tool="hwpx.preview_edit",
|
|
24
|
+
example_json='{"planId":"<plan-id>"}',
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
PREVIEW_NEXT_ACTION = ExampleTemplate(
|
|
28
|
+
tool="hwpx.apply_edit",
|
|
29
|
+
example_json='{"planId":"<plan-id>","confirm":true}',
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
APPLY_BAD_EXAMPLE = ExampleTemplate(
|
|
33
|
+
tool="hwpx.apply_edit",
|
|
34
|
+
example_json='{"planId":"<plan-id>"}',
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
ERROR_PREVIEW_REQUIRED = ExampleTemplate(
|
|
38
|
+
tool="hwpx.preview_edit",
|
|
39
|
+
example_json='{"planId":"<plan-id>"}',
|
|
40
|
+
)
|