@shundoo-ai/dsh-cosmic 1.0.21 → 1.0.22
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.
- package/package.json +1 -1
- package/skills/cosmic-build/LOCAL-PATCHES.md +43 -14
- package/skills/cosmic-build/SKILL.md +24 -9
- package/skills/cosmic-build/examples/java-rules/CosmicReportAggregation.java +26 -17
- package/skills/cosmic-build/examples/java-rules/CosmicReportFilters.java +96 -2
- package/skills/cosmic-build/knowledge/cosmic/arch/security/security_standard.md +4 -4
- package/skills/cosmic-build/knowledge/cosmic/platform/allimport.md +2 -1
- package/skills/cosmic-build/knowledge/cosmic/platform/core/dynamic-object-collection.md +6 -4
- package/skills/cosmic-build/knowledge/cosmic/platform/core/model.md +9 -9
- package/skills/cosmic-build/knowledge/cosmic/platform/core/view.md +5 -5
- package/skills/cosmic-build/knowledge/cosmic/platform/form-plugin.md +8 -4
- package/skills/cosmic-build/knowledge/cosmic/platform/list-plugin.md +5 -3
- package/skills/cosmic-build/knowledge/cosmic/platform/print-plugin-guide.md +1 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/report-plugin.md +269 -57
- package/skills/cosmic-build/knowledge/cosmic/platform/reportlistdata-plugin.md +130 -23
- package/skills/cosmic-build/knowledge/cosmic/platform/reporttreedata-plugin.md +48 -28
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/_index.md +12 -3
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/common/attachment-name-process.md +17 -13
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/common/dynamic-update-field.md +4 -4
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/control/filter-grid/filter-grid-set-value.md +1 -1
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/control/list/filter-basedatafield.md +2 -3
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/control/list/filter-container-init.md +0 -1
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/control/list/filter-popup.md +0 -1
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/control/list/filter-value-parse.md +5 -6
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/control/list/list-show-form.md +1 -1
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/control/list/query-field-dynamic.md +0 -7
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/data-access/business-data/delete-service.md +24 -29
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/data-access/ksql/db-batch.md +4 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/data-access/ksql/db-direct-access.md +4 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/data-access/qfilter/entity-object-access.md +8 -3
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/data-access/qfilter/qfilter-compose.md +6 -5
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/event/after-bind-data-set-visible.md +5 -1
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/event/click-return-data.md +2 -2
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/event/closed-call-back-set-value.md +2 -2
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/event/register-listener.md +1 -1
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/event/set-filter-tab-org.md +3 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/infra/dispatch-service/microservice-dev.md +18 -11
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/infra/dist-lock/dist-lock-basic.md +3 -6
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/infra/mq/mq-subscribe.md +5 -1
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/infra/thread-pool/async-operation.md +10 -6
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/infra/thread-pool/big-task-async.md +4 -2
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/infra/thread-pool/schedule-task.md +9 -7
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/operation/operation-interactive.md +33 -34
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/operation/operation-plugin-events.md +30 -22
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/report/report-async-query.md +133 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/report/report-batch-query.md +26 -22
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/report/report-chart.md +112 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/report/report-dataset-assembly.md +200 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/report/report-head-filter.md +177 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/report/report-hyperlink-drill.md +216 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/report/report-list-data-query.md +12 -12
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/report/report-merge-column.md +44 -6
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/report/report-print-data.md +163 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/report/report-row-data-toolbar.md +188 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/report/report-subtotal-total.md +139 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/report/report-tree-data-query.md +108 -12
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/report/report-tree-list.md +181 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/system-service/report-plugin-interface.md +3 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/tree/tree-basedata-cascade-confirm.md +14 -11
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/tree/tree-list-before-item-validate.md +1 -1
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/tree/tree-list-build-filter.md +1 -1
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/tree/tree-list-multi-level-filter.md +11 -11
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/tree/tree-list-refresh-node.md +22 -15
- package/skills/cosmic-build/knowledge/cosmic/platform/sdk/sdk-algo.md +2 -2
- package/skills/cosmic-build/knowledge/cosmic/platform/sdk/sdk-entity-model.md +3 -4
- package/skills/cosmic-build/knowledge/cosmic/platform/sdk/sdk-exception.md +9 -5
- package/skills/cosmic-build/knowledge/cosmic/platform/sdk/sdk-orm-access.md +4 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/sdk/sdk-request-context.md +7 -3
- package/skills/cosmic-build/knowledge/cosmic/platform/standards.md +28 -3
- package/skills/cosmic-build/references/compile-guide.md +36 -1
- package/skills/cosmic-build/references/dcs-code-rules.md +180 -0
- package/skills/cosmic-build/references/delivery.md +16 -2
- package/skills/cosmic-build/references/execution-contract.md +15 -3
- package/skills/cosmic-build/references/java-plugin-delivery.md +21 -11
- package/skills/cosmic-build/references/plugin-handoff-input.md +82 -24
- package/skills/cosmic-build/references/plugin-runtime-routing.md +23 -6
- package/skills/cosmic-build/references/report-filter-contract.md +53 -15
- package/skills/cosmic-build/references/sdk-inspection.md +4 -1
- package/skills/cosmic-build/references/type-registry.json +26 -17
- package/skills/cosmic-build/schemas/data-model-authoring.schema.json +1 -1
- package/skills/cosmic-build/scripts/_http_client.py +3 -0
- package/skills/cosmic-build/scripts/compile_plugin_source.py +251 -42
- package/skills/cosmic-build/scripts/configure_list.py +112 -0
- package/skills/cosmic-build/scripts/dcs-rule-catalog.json +799 -0
- package/skills/cosmic-build/scripts/dcs_code_gate.py +1976 -0
- package/skills/cosmic-build/scripts/execution_binding.py +25 -0
- package/skills/cosmic-build/scripts/platform_api_contract.py +352 -7
- package/skills/cosmic-build/scripts/plugin_source_gate.py +9 -1
- package/skills/cosmic-build/scripts/plugin_target_sdk.py +12 -8
- package/skills/cosmic-build/scripts/prepare_plugin_handoff.py +488 -88
- package/skills/cosmic-build/scripts/query_plugin_handoff.py +207 -20
- package/skills/cosmic-build/scripts/register_plugins.py +27 -10
- package/skills/cosmic-build/scripts/render_output_cards.py +57 -20
- package/skills/cosmic-build/scripts/resolve_output_path.py +60 -26
- package/skills/cosmic-build/scripts/run_java_tests.py +162 -0
- package/skills/cosmic-build/scripts/sync_generated_locale_assets.py +28 -0
- package/skills/cosmic-build/scripts/test/fixtures/ReportSdkCheck.java +1 -22
- package/skills/cosmic-build/scripts/test/fixtures/list_column_property_declarations.json +887 -0
- package/skills/cosmic-build/scripts/test/fixtures/operation-entry-field-prepare.java +78 -0
- package/skills/cosmic-build/scripts/test/test_add_field_required_contract.py +12 -0
- package/skills/cosmic-build/scripts/test/test_batch5_drift_governance.py +23 -2
- package/skills/cosmic-build/scripts/test/test_compile_plugin_source.py +287 -4
- package/skills/cosmic-build/scripts/test/test_configure_list_delivery.py +132 -0
- package/skills/cosmic-build/scripts/test/test_cosmic_sdk_examples.py +58 -1
- package/skills/cosmic-build/scripts/test/test_data_model_contract.py +19 -0
- package/skills/cosmic-build/scripts/test/test_dcs_code_gate.py +901 -0
- package/skills/cosmic-build/scripts/test/test_delivery_stage_boundary.py +1 -1
- package/skills/cosmic-build/scripts/test/test_direct_cli_architecture.py +2 -0
- package/skills/cosmic-build/scripts/test/test_http_client.py +6 -0
- package/skills/cosmic-build/scripts/test/test_java_toolchain_feedback.py +206 -0
- package/skills/cosmic-build/scripts/test/test_kd_api.py +21 -0
- package/skills/cosmic-build/scripts/test/test_list_configuration_closure.py +184 -0
- package/skills/cosmic-build/scripts/test/test_mcp_cli.py +139 -2
- package/skills/cosmic-build/scripts/test/test_menu_creation_closure.py +16 -0
- package/skills/cosmic-build/scripts/test/test_modeling_input_recovery.py +55 -1
- package/skills/cosmic-build/scripts/test/test_open_world_cli_catalog.py +1 -1
- package/skills/cosmic-build/scripts/test/test_operation_field_preparation.py +84 -0
- package/skills/cosmic-build/scripts/test/test_platform_api_contract.py +322 -1
- package/skills/cosmic-build/scripts/test/test_plugin_handoff.py +951 -4
- package/skills/cosmic-build/scripts/test/test_plugin_source_gate.py +30 -2
- package/skills/cosmic-build/scripts/test/test_plugin_target_sdk.py +21 -0
- package/skills/cosmic-build/scripts/test/test_property_reroute.py +165 -0
- package/skills/cosmic-build/scripts/test/test_property_schema_first.py +35 -0
- package/skills/cosmic-build/scripts/test/test_query_plugin_handoff.py +221 -0
- package/skills/cosmic-build/scripts/test/test_register_plugins.py +76 -4
- package/skills/cosmic-build/scripts/test/test_render_output_cards.py +75 -3
- package/skills/cosmic-build/scripts/test/test_report_business_contract.py +27 -5
- package/skills/cosmic-build/scripts/test/test_report_doc_contract_sync.py +103 -11
- package/skills/cosmic-build/scripts/test/test_report_plugin_source_gate.py +46 -16
- package/skills/cosmic-build/scripts/test/test_report_properties.py +74 -15
- package/skills/cosmic-build/scripts/test/test_report_query_data_source.py +3 -1
- package/skills/cosmic-build/scripts/test/test_report_sdk_optimization.py +1 -2
- package/skills/cosmic-build/scripts/test/test_test_environment.py +76 -1
- package/skills/cosmic-build/scripts/test_environment.py +67 -1
- package/skills/cosmic-build/skills/cosmic-coding-impl/SKILL.md +52 -10
- package/skills/cosmic-build/skills/cosmic-meta-api/apis/ai_meta.md +16 -3
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/report-write-contracts.json +59 -26
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/rule-domain.json +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/report-write.schema.json +75 -18
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/pdm/scripts/pdm_auto.py +39 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/pdm/scripts/pdm_client.py +97 -10
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/verify/SKILL.md +10 -12
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_apps.py +3 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_formactions.py +38 -29
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_listui.py +400 -233
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_metaops.py +87 -45
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_properties.py +42 -15
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_rules.py +135 -5
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/config.py +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/execution_errors.py +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/formatters.py +17 -11
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/property_reroute.py +15 -5
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/report_ops.py +1429 -238
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/validators.py +56 -28
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/cosmic_api.py +380 -134
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/field_decorator.py +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/meta_export.py +12 -11
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/meta_verifier.py +42 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_add_field_placement_closure.py +8 -8
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_build_configuration_readback.py +94 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_build_receipt_resume.py +47 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_metadata_unchanged_fail_closed.py +87 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_dym_evidence.py +23 -23
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_entity_integrity.py +279 -4
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_field_guard.py +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_plugin_contract.py +509 -32
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_readback_derivation.py +178 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_recreate_plan.py +125 -10
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_serve_contract.py +208 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_typed_filters.py +259 -50
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_rule_inventory_perf.py +29 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_rule_write_closure.py +20 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_run_batch_post_build_recovery.py +18 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_run_batch_verification_evidence.py +35 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_run_identity_guard.py +25 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_time_range_rule.py +98 -0
- package/skills/cosmic-build/skills/cosmic-meta-knowledge/domain-model/report-model.md +20 -9
- package/skills/cosmic-build/skills/cosmic-meta-knowledge/generation/report-modeling-guide.md +55 -25
- package/skills/cosmic-build/skills/cosmic-meta-knowledge/property-guides/report-column-properties.md +15 -39
- package/skills/cosmic-build/skills/cosmic-meta-modeling/SKILL.md +19 -17
- package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/report/SKILL.md +82 -38
- package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/report/examples/golden-example-report-batch.md +64 -19
- package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/report/examples/golden-example-report-plugin.md +32 -20
- package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/report/examples/golden-example-report-tree.md +78 -31
- package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/report/report-artifact-schema.json +2 -1
- package/skills/cosmic-build/skills/cosmic-meta-modeling/references/authoring-companion-fields.md +3 -0
- package/skills/cosmic-build/skills/cosmic-meta-modeling/references/authoring-list-configuration.md +2 -0
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/data_model_contract.py +3 -1
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/data_model_emit.py +27 -4
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/report_validator.py +99 -44
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/test_report_examples.py +31 -4
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/test_report_validator.py +129 -29
- package/skills/cosmic-build/skills/cosmic-meta-modifier/SKILL.md +6 -2
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/operation/validation.md +2 -0
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/property/SKILL.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/report-op/SKILL.md +104 -25
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/SKILL.md +9 -0
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/verify/usage-guide.md +2 -2
- package/skills/cosmic-build/skills/cosmic-meta-modifier/references/list-filter-modification.md +39 -12
- package/skills/cosmic-build/skills/mcp-server/SKILL.md +39 -24
- package/skills/cosmic-build/skills/mcp-server/scripts/mcp_cli.py +20 -6
- package/skills/cosmic-dev-best-practices/SKILL.md +1 -1
- package/skills/cosmic-dev-best-practices/references/README.md +2 -2
- package/skills/cosmic-dev-best-practices/references/basedata-dev-convention.md +2 -2
- package/skills/cosmic-dev-best-practices/references/bill-dev-convention.md +4 -4
- package/skills/cosmic-dev-best-practices/references/design-document-convention.md +2 -2
- package/skills/cosmic-dev-best-practices/references/design-examples/basedata-design-example.md +4 -4
- package/skills/cosmic-dev-best-practices/references/design-examples/bill-design-example.md +13 -13
- package/skills/cosmic-dev-best-practices/references/elements/CustomerField.md +1 -1
- package/skills/cosmic-dev-best-practices/references/elements/README.md +1 -1
- package/skills/cosmic-dev-best-practices/references/elements/SupplierField.md +1 -1
- package/skills/cosmic-dev-best-practices/references/elements/common-field-property-conventions.md +109 -13
- package/skills/cosmic-dev-best-practices/references/layout-control-convention.md +1 -1
- package/skills/erp-analysis/references/delivery-contract.md +2 -1
- package/skills/erp-analysis/templates/AGENTS.template.md +3 -1
- package/skills/cosmic-build/assets/platform-report-filters/TypedReportFilterFields.java +0 -169
- package/skills/cosmic-build/assets/platform-report-filters/platform.patch +0 -98
- package/skills/cosmic-build/scripts/apply_report_filter_extension.py +0 -39
|
@@ -877,7 +877,7 @@ class _PostBuildWriteError(ValueError):
|
|
|
877
877
|
|
|
878
878
|
|
|
879
879
|
def _attach_post_build_phase_failure(summary, payload, *, phase, app_root,
|
|
880
|
-
artifact_path, pending_write=None):
|
|
880
|
+
artifact_path, pending_write=None, verification=None):
|
|
881
881
|
"""A successful root save survives a later write or verification failure."""
|
|
882
882
|
targets = [
|
|
883
883
|
{"formId": row["formId"],
|
|
@@ -910,6 +910,15 @@ def _attach_post_build_phase_failure(summary, payload, *, phase, app_root,
|
|
|
910
910
|
"allowedNextActions": ["getFormSchema", "getProperties", "listElements"],
|
|
911
911
|
"modelInstruction": "Preserve the saved form and the original artifact. Inspect the exact retained target before a narrow existing-form repair; never rerun emit, runBatch or buildMeta for this artifact. Reconcile every failed or unknown post-write before retrying. The batch results use ok and phase, not success.",
|
|
912
912
|
})
|
|
913
|
+
issues = (verification or {}).get("issues") or []
|
|
914
|
+
counts = (verification or {}).get("summary") or {}
|
|
915
|
+
if phase == "verify" and issues and counts.get("failed") == len(issues) and not any(counts.get(key) for key in ("errors", "warnings", "skipped")) and all(item.get("status") == "fail" and item.get("type") in
|
|
916
|
+
{"property_equals", "combo_options_equal", "unit_binding_equals"} for item in issues):
|
|
917
|
+
summary.update({"retryAdvice": "repair_observed_configuration", "reconciliation": [],
|
|
918
|
+
"allowedNextActions": ["existing_form_writer", "report_blocker"],
|
|
919
|
+
"modelInstruction": "Native readback already isolated the configuration differences. Reuse verification.issues (expected and actual) and verifiedTargets; repair only those named differences through their existing-form writers. Do not rediscover the form, export DYM or replay successful writes. If the requested stored values are unsupported, report that exact boundary instead of substituting values."})
|
|
920
|
+
summary["repairPlans"][0].update({"observedIssues": issues,
|
|
921
|
+
"precondition": "Use the existing independent readback; successful configuration is retained. Re-read only if another write changes the target or a narrow repair remains unknown."})
|
|
913
922
|
return summary
|
|
914
923
|
|
|
915
924
|
|
|
@@ -1034,8 +1043,8 @@ def _apply_form_composition_failure_contract(
|
|
|
1034
1043
|
def _compact_verified_targets(report):
|
|
1035
1044
|
"""Expose successful read-back assertions without forcing a second query.
|
|
1036
1045
|
|
|
1037
|
-
|
|
1038
|
-
|
|
1046
|
+
Include the checked property and values so a successful receipt can be reused
|
|
1047
|
+
without guessing what property_equals meant or exporting another snapshot.
|
|
1039
1048
|
"""
|
|
1040
1049
|
evidence = []
|
|
1041
1050
|
for result in getattr(report, "results", []) or []:
|
|
@@ -1045,7 +1054,15 @@ def _compact_verified_targets(report):
|
|
|
1045
1054
|
assertion_type = str(getattr(spec, "type", "") or "").strip()
|
|
1046
1055
|
target = str(getattr(spec, "target", "") or "").strip()
|
|
1047
1056
|
if assertion_type and target:
|
|
1048
|
-
|
|
1057
|
+
item = {"type": assertion_type, "target": target}
|
|
1058
|
+
prop = (getattr(spec, "metadata", None) or {}).get("property")
|
|
1059
|
+
if prop:
|
|
1060
|
+
item["property"] = prop
|
|
1061
|
+
if hasattr(spec, "expected"):
|
|
1062
|
+
item["expected"] = spec.expected
|
|
1063
|
+
if hasattr(result, "actual"):
|
|
1064
|
+
item["actual"] = result.actual
|
|
1065
|
+
evidence.append(item)
|
|
1049
1066
|
return evidence
|
|
1050
1067
|
|
|
1051
1068
|
|
|
@@ -1358,32 +1375,33 @@ def _resolve_template_number(args_template, artifact_path, manifest):
|
|
|
1358
1375
|
submit BD missing template number as a bill, causing BillNoField error and masking upstream emit issues.
|
|
1359
1376
|
Caller must check return value and exit with error when None.
|
|
1360
1377
|
"""
|
|
1361
|
-
if args_template is not None
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
if tn is
|
|
1365
|
-
return
|
|
1366
|
-
|
|
1367
|
-
if
|
|
1368
|
-
return tn
|
|
1369
|
-
return None
|
|
1378
|
+
tn = args_template if args_template is not None else _read_artifact_template(artifact_path)
|
|
1379
|
+
if tn is None:
|
|
1380
|
+
tn = _manifest_template_for(manifest, artifact_path)
|
|
1381
|
+
if tn is None:
|
|
1382
|
+
return None
|
|
1383
|
+
value = str(tn).strip()
|
|
1384
|
+
return "blankPage" if value.casefold() in {"blank", "blankpage"} else value
|
|
1370
1385
|
|
|
1371
1386
|
|
|
1372
|
-
def _artifact_supports_blank_template(artifact):
|
|
1373
|
-
"""
|
|
1387
|
+
def _artifact_supports_blank_template(artifact, template=""):
|
|
1388
|
+
"""Permit an explicit blank bill while rejecting an accidentally missing template."""
|
|
1374
1389
|
if not isinstance(artifact, dict):
|
|
1375
1390
|
return False
|
|
1376
1391
|
roots = [
|
|
1377
1392
|
entity for entity in artifact.get("entities") or []
|
|
1378
1393
|
if isinstance(entity, dict) and not entity.get("parentEntityId")
|
|
1379
1394
|
]
|
|
1380
|
-
|
|
1395
|
+
if len(roots) != 1:
|
|
1396
|
+
return False
|
|
1397
|
+
root_type = str(roots[0].get("type") or "").strip()
|
|
1398
|
+
return root_type == "MainEntity" or (root_type == "BillEntity" and template == "blankPage")
|
|
1381
1399
|
|
|
1382
1400
|
|
|
1383
|
-
def _artifact_file_supports_blank_template(artifact_path):
|
|
1401
|
+
def _artifact_file_supports_blank_template(artifact_path, template=""):
|
|
1384
1402
|
try:
|
|
1385
1403
|
with open(artifact_path, "r", encoding="utf-8-sig") as f:
|
|
1386
|
-
return _artifact_supports_blank_template(json.load(f))
|
|
1404
|
+
return _artifact_supports_blank_template(json.load(f), template)
|
|
1387
1405
|
except (OSError, json.JSONDecodeError):
|
|
1388
1406
|
return False
|
|
1389
1407
|
|
|
@@ -1974,32 +1992,128 @@ def _resolve_owned_report_target(cfg, token, args, command):
|
|
|
1974
1992
|
return row
|
|
1975
1993
|
|
|
1976
1994
|
|
|
1977
|
-
def
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1995
|
+
def _remove_owned_report_column(cfg, token, args):
|
|
1996
|
+
"""CLI 与 serve 共用同一归属、预检和回读闭环。"""
|
|
1997
|
+
field_key = normalize_report_column_removal_input({"fieldKey": args.fieldKey})["fieldKey"]
|
|
1998
|
+
if not getattr(args, "app_root", None) or not getattr(args, "formNumber", None):
|
|
1999
|
+
raise ValueError("REPORT_INPUT_INVALID: removeReportColumn requires appRoot and exact formNumber")
|
|
2000
|
+
if getattr(args, "dry_run", False):
|
|
2001
|
+
return do_remove_report_column(cfg, None, args.formId or "", field_key,
|
|
2002
|
+
dry_run=True, form_number=args.formNumber)
|
|
2003
|
+
target = _resolve_owned_report_target(cfg, token, args, "removeReportColumn")
|
|
2004
|
+
before = do_get_report_schema(cfg, token, form_id=target["formId"])
|
|
2005
|
+
expected = plan_report_column_removal(before, field_key, args.app_root, args.formNumber, target["formId"])
|
|
2006
|
+
result = do_remove_report_column(cfg, token, target["formId"], field_key, form_number=args.formNumber)
|
|
2007
|
+
if not _is_api_success(result):
|
|
2008
|
+
return result
|
|
2009
|
+
return _attach_report_readback(cfg, token, target["formId"], "columnsRemove", expected,
|
|
2010
|
+
result["data"], app_root=args.app_root, schema_before=before)
|
|
2011
|
+
|
|
2012
|
+
|
|
2013
|
+
def _attach_report_readback(cfg, token, form_id, section, expected, result_data,
|
|
2014
|
+
filter_editors=None, app_root=None, schema_before=None):
|
|
2015
|
+
try:
|
|
2016
|
+
schema = do_get_report_schema(cfg, token, form_id=form_id)
|
|
2017
|
+
if not isinstance(schema, dict):
|
|
2018
|
+
raise TypeError("Report read-back must be an object")
|
|
2019
|
+
except Exception as exc:
|
|
2020
|
+
# 写入已成功,回读失败不能诱导宿主重放写请求。
|
|
2021
|
+
schema = {"readBackAvailable": False, "readBackSource": "unavailable",
|
|
2022
|
+
"readBackError": type(exc).__name__}
|
|
2023
|
+
|
|
2024
|
+
def settle(result):
|
|
2025
|
+
result["data"]["platformMutationApplied"] = True
|
|
2026
|
+
if schema.get("readBackError"):
|
|
2027
|
+
result["verification"]["errorType"] = schema["readBackError"]
|
|
2028
|
+
if app_root:
|
|
2029
|
+
try:
|
|
2030
|
+
result["data"]["reportAuthoringState"] = sync_report_authoring_state(
|
|
2031
|
+
app_root, result_data["formNumber"], form_id, section, expected,
|
|
2032
|
+
schema_before or {}, schema, result["verification"],
|
|
2033
|
+
result["data"].get("filterEditors"))
|
|
2034
|
+
except (OSError, ValueError, KeyError, TypeError) as exc:
|
|
2035
|
+
result["data"]["reportAuthoringState"] = {"status": "failed", "errorType": type(exc).__name__,
|
|
2036
|
+
"platformMutationApplied": True, "reason": "Repair local state from current metadata; do not replay the platform write"}
|
|
2037
|
+
return result
|
|
2038
|
+
if section == "filters" and filter_editors:
|
|
2039
|
+
# What the write's receipt showed about each typed editor; the read-back settles the rest.
|
|
2040
|
+
schema["filterEditorOutcome"] = filter_editors
|
|
1982
2041
|
if not schema.get("readBackAvailable"):
|
|
1983
2042
|
# No canonical read-back on this deployment; the write already returned platform
|
|
1984
|
-
# success, so report succeeded-but-unverified, not a mismatch
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
"
|
|
1988
|
-
|
|
1989
|
-
|
|
2043
|
+
# success, so report succeeded-but-unverified, not a mismatch — unless the platform's own
|
|
2044
|
+
# receipt already showed a filter editor other than the requested or legacy one.
|
|
2045
|
+
receipt_mismatch = (section == "columnsRemove" or
|
|
2046
|
+
bool(filter_editors) and filter_editors.get("typedFilterSupport") == "mismatch")
|
|
2047
|
+
data = dict(result_data)
|
|
2048
|
+
if filter_editors:
|
|
2049
|
+
data["filterEditors"] = filter_editors
|
|
2050
|
+
return settle({
|
|
2051
|
+
"status": not receipt_mismatch,
|
|
2052
|
+
"errorCode": "REPORT_READBACK_MISMATCH" if receipt_mismatch else "0",
|
|
2053
|
+
"message": ("Deletion receipt succeeded but independent read-back is unavailable; do not replay"
|
|
2054
|
+
if section == "columnsRemove" else "平台回执显示过滤控件类型与请求不一致" if receipt_mismatch else None),
|
|
2055
|
+
"data": data,
|
|
1990
2056
|
"verification": {"verified": False, "reason": "canonical read-back unavailable"},
|
|
1991
|
-
}
|
|
1992
|
-
|
|
2057
|
+
})
|
|
2058
|
+
try:
|
|
2059
|
+
verification = report_readback_verification(section, expected, schema)
|
|
2060
|
+
except (ValueError, KeyError, TypeError, AttributeError) as exc:
|
|
2061
|
+
verification = {"verified": False, "reason": "Invalid report read-back; reconcile before coding",
|
|
2062
|
+
"errorType": type(exc).__name__}
|
|
2063
|
+
data = dict(result_data)
|
|
2064
|
+
editors = verification.get("filterEditors") or filter_editors
|
|
2065
|
+
if section == "filters" and editors:
|
|
2066
|
+
data["filterEditors"] = editors
|
|
1993
2067
|
result = {
|
|
1994
2068
|
"status": bool(verification.get("verified")),
|
|
1995
2069
|
"errorCode": "0" if verification.get("verified") else "REPORT_READBACK_MISMATCH",
|
|
1996
2070
|
"message": None if verification.get("verified") else "报表写入回执成功,但独立回读与请求不一致",
|
|
1997
|
-
"data":
|
|
2071
|
+
"data": data,
|
|
1998
2072
|
"verification": verification,
|
|
1999
2073
|
}
|
|
2074
|
+
return settle(result)
|
|
2075
|
+
|
|
2076
|
+
|
|
2077
|
+
_REPORT_STATE_WRITES = {"setReportColumns", "addReportColumns", "removeReportColumn", "setReportFilters", "setReportSorts",
|
|
2078
|
+
"registerReportPlugin", "setReportProperties", "setReportQueryDataSource", "setReportFilterFieldConfig",
|
|
2079
|
+
"setReportDefaultHiddenFields", "setReportRowBackColor", "registerReportPluginExt"}
|
|
2080
|
+
|
|
2081
|
+
|
|
2082
|
+
def _invalidate_unmerged_report_state(result, command, app_root, form_number, dry_run=False):
|
|
2083
|
+
"""其他写入入口只失效旧需求,不从不完整回执补造插件契约。"""
|
|
2084
|
+
if dry_run or command not in _REPORT_STATE_WRITES or not app_root or not form_number:
|
|
2085
|
+
return result
|
|
2086
|
+
data = result.get("data") if isinstance(result, dict) else None
|
|
2087
|
+
if isinstance(data, dict) and data.get("reportAuthoringState"):
|
|
2088
|
+
return result
|
|
2089
|
+
applied = _serve_result_success(result) or (isinstance(data, dict) and data.get("platformMutationApplied") is True)
|
|
2090
|
+
possible = isinstance(data, dict) and data.get("platformMutationPossible") is True
|
|
2091
|
+
if not applied and not possible:
|
|
2092
|
+
return result
|
|
2093
|
+
evidence = {"platformMutationApplied": True} if applied else {"platformMutationPossible": True}
|
|
2094
|
+
try:
|
|
2095
|
+
state = invalidate_report_authoring_state(app_root, form_number,
|
|
2096
|
+
f"{command} crossed the report write boundary; reconcile the complete artifact before coding; do not replay the write",
|
|
2097
|
+
mutation_applied=True if applied else None)
|
|
2098
|
+
except (OSError, ValueError) as exc:
|
|
2099
|
+
state = {"status": "failed", "errorType": type(exc).__name__, **evidence,
|
|
2100
|
+
"reason": "Repair local state; do not replay the platform write"}
|
|
2101
|
+
if isinstance(result, dict):
|
|
2102
|
+
if not isinstance(data, dict):
|
|
2103
|
+
result["data"] = data = {}
|
|
2104
|
+
data["reportAuthoringState"] = state
|
|
2000
2105
|
return result
|
|
2001
2106
|
|
|
2002
2107
|
|
|
2108
|
+
def _report_mutation_failure(exc):
|
|
2109
|
+
"""只接收报表写入边界异常,输入或身份预检失败不会触发失效。"""
|
|
2110
|
+
code, message = _exception_error_code(exc)
|
|
2111
|
+
return {"status": False, "errorCode": code, "message": message, "writeAttempted": True,
|
|
2112
|
+
"data": {**({"platformMutationApplied": True} if exc.mutation_applied is True else
|
|
2113
|
+
{"platformMutationPossible": True}),
|
|
2114
|
+
"runtimeVerified": False, "retryAdvice": "Re-read and reconcile; do not replay the write"}}
|
|
2115
|
+
|
|
2116
|
+
|
|
2003
2117
|
def _json_diff_paths(before, after, path=""):
|
|
2004
2118
|
"""Return exact JSON Pointer leaf/subtree paths changed by a replacement."""
|
|
2005
2119
|
if type(before) is not type(after):
|
|
@@ -2929,12 +3043,12 @@ from _core.formatters import ( # noqa: F401
|
|
|
2929
3043
|
_print_forms, _print_schema, _print_templates,
|
|
2930
3044
|
_print_form_layout_tree, _print_panels,
|
|
2931
3045
|
_print_find_results, _print_biz_hierarchy,
|
|
2932
|
-
pjson, _transform_build_meta_result, save_run_batch_result,
|
|
3046
|
+
pjson, _transform_build_meta_result, save_run_batch_result, result_summary,
|
|
2933
3047
|
set_output_file, set_stdout_mode, set_current_command, _is_en,
|
|
2934
3048
|
)
|
|
2935
3049
|
|
|
2936
3050
|
|
|
2937
|
-
from execution_binding import execution_binding, validate_execution_binding
|
|
3051
|
+
from execution_binding import execution_binding, validate_execution_binding, bound_entrypoint
|
|
2938
3052
|
from _core.execution_errors import attach_execution_error
|
|
2939
3053
|
|
|
2940
3054
|
_FORMATTER_PJSON = pjson
|
|
@@ -3034,6 +3148,10 @@ def _is_machine_failure(result):
|
|
|
3034
3148
|
def pjson(obj, force_stdout=False):
|
|
3035
3149
|
"""Emit one structured result and make semantic failure affect the exit code."""
|
|
3036
3150
|
global _CLI_RESULT_EMITTED
|
|
3151
|
+
if _CLI_DELIVERY_ARGS is not None:
|
|
3152
|
+
obj = _invalidate_unmerged_report_state(obj, getattr(_CLI_DELIVERY_ARGS, "cmd", None),
|
|
3153
|
+
getattr(_CLI_DELIVERY_ARGS, "app_root", None), getattr(_CLI_DELIVERY_ARGS, "formNumber", None),
|
|
3154
|
+
getattr(_CLI_DELIVERY_ARGS, "dry_run", False))
|
|
3037
3155
|
obj = attach_execution_error(_attach_verified_form_delivery(obj, _CLI_DELIVERY_ARGS))
|
|
3038
3156
|
_FORMATTER_PJSON(obj, force_stdout=force_stdout)
|
|
3039
3157
|
_CLI_RESULT_EMITTED = True
|
|
@@ -3072,20 +3190,21 @@ def _exception_error_code(exc):
|
|
|
3072
3190
|
return "CLI_EXECUTION_ERROR", text or exc.__class__.__name__
|
|
3073
3191
|
|
|
3074
3192
|
|
|
3075
|
-
def _emit_machine_error(error_code, message, recovery=None):
|
|
3193
|
+
def _emit_machine_error(error_code, message, recovery=None, data=None):
|
|
3076
3194
|
global _CLI_RESULT_EMITTED
|
|
3077
3195
|
_FORMATTER_PJSON(
|
|
3078
3196
|
{
|
|
3079
3197
|
"status": False,
|
|
3080
3198
|
"errorCode": str(error_code or "CLI_EXECUTION_ERROR"),
|
|
3081
3199
|
"message": str(message or "Command failed"),
|
|
3082
|
-
"data":
|
|
3200
|
+
"data": data,
|
|
3083
3201
|
"errorCategory": attach_execution_error({"status": False, "errorCode": error_code})["errorCategory"],
|
|
3084
3202
|
"capabilityLimitConfirmed": error_code == "FULL_METADATA_API_UNAVAILABLE",
|
|
3085
3203
|
"executionBinding": execution_binding(),
|
|
3086
3204
|
**({"writeAttempted": False} if error_code in {
|
|
3087
3205
|
"SKILL_SOURCE_MISMATCH", "SKILL_REVISION_MISMATCH", "ENVIRONMENT_BINDING_MISMATCH",
|
|
3088
3206
|
"CONDITIONAL_CARRY_SOURCE_PROPERTY_UNAVAILABLE",
|
|
3207
|
+
"REPORT_SORTS_API_UNSAFE",
|
|
3089
3208
|
} else {}),
|
|
3090
3209
|
**({"recovery": recovery} if recovery else {}),
|
|
3091
3210
|
},
|
|
@@ -3100,8 +3219,12 @@ from _core.reset import ( # noqa: F401
|
|
|
3100
3219
|
)
|
|
3101
3220
|
|
|
3102
3221
|
from _core.report_ops import ( # noqa: F401
|
|
3222
|
+
ReportMutationError,
|
|
3103
3223
|
set_report_columns as do_set_report_columns,
|
|
3104
3224
|
add_report_columns as do_add_report_columns,
|
|
3225
|
+
remove_report_column as do_remove_report_column,
|
|
3226
|
+
normalize_report_column_removal_input,
|
|
3227
|
+
plan_report_column_removal,
|
|
3105
3228
|
plan_report_column_append,
|
|
3106
3229
|
set_report_filters as do_set_report_filters,
|
|
3107
3230
|
set_report_sorts as do_set_report_sorts,
|
|
@@ -3122,6 +3245,7 @@ from _core.report_ops import ( # noqa: F401
|
|
|
3122
3245
|
normalize_report_properties_artifact,
|
|
3123
3246
|
report_properties_artifact_summary,
|
|
3124
3247
|
report_readback_verification,
|
|
3248
|
+
resolve_filter_editors,
|
|
3125
3249
|
validate_report_references,
|
|
3126
3250
|
assert_report_filter_keys_free,
|
|
3127
3251
|
collect_report_column_keys,
|
|
@@ -3129,7 +3253,12 @@ from _core.report_ops import ( # noqa: F401
|
|
|
3129
3253
|
attach_dym_evidence,
|
|
3130
3254
|
filters_need_dym_evidence,
|
|
3131
3255
|
compile_report_plugin_contract,
|
|
3256
|
+
compile_report_default_sorts,
|
|
3257
|
+
REPORT_SORTS_API_UNSAFE,
|
|
3132
3258
|
write_report_plugin_contract,
|
|
3259
|
+
write_report_authoring_state,
|
|
3260
|
+
sync_report_authoring_state,
|
|
3261
|
+
invalidate_report_authoring_state,
|
|
3133
3262
|
plan_report_recreate,
|
|
3134
3263
|
write_report_recreate_backup,
|
|
3135
3264
|
)
|
|
@@ -3325,6 +3454,15 @@ def _verify_listcolumn_landed(cfg, token, form_id, field_key, result):
|
|
|
3325
3454
|
# ─── Serve mode ─────────────────────────────────────────────────────────────────
|
|
3326
3455
|
|
|
3327
3456
|
def _dispatch_serve(cfg, token, cmd, cmd_args):
|
|
3457
|
+
try:
|
|
3458
|
+
result = _dispatch_serve_command(cfg, token, cmd, cmd_args)
|
|
3459
|
+
except ReportMutationError as exc:
|
|
3460
|
+
result = _report_mutation_failure(exc)
|
|
3461
|
+
return _invalidate_unmerged_report_state(result, cmd, cmd_args.get("appRoot"),
|
|
3462
|
+
cmd_args.get("formNumber"), cmd_args.get("dryRun", False))
|
|
3463
|
+
|
|
3464
|
+
|
|
3465
|
+
def _dispatch_serve_command(cfg, token, cmd, cmd_args):
|
|
3328
3466
|
"""Dispatch commands in serve mode to corresponding business functions.
|
|
3329
3467
|
|
|
3330
3468
|
Args:
|
|
@@ -4342,7 +4480,7 @@ def _dispatch_serve(cfg, token, cmd, cmd_args):
|
|
|
4342
4480
|
form_name=cmd_args.get("formName") or cmd_args.get("form_name"),
|
|
4343
4481
|
field_name=cmd_args.get("fieldName") or cmd_args.get("field_name"),
|
|
4344
4482
|
biz_word=cmd_args.get("bizWord") or cmd_args.get("biz_word"),
|
|
4345
|
-
field_type=cmd_args.get("fieldType") or cmd_args.get("field_type")
|
|
4483
|
+
field_type=cmd_args.get("fieldType") or cmd_args.get("field_type"),
|
|
4346
4484
|
app_root=cmd_args.get("appRoot") or cmd_args.get("app_root"),
|
|
4347
4485
|
project_root=cmd_args.get("projectRoot") or cmd_args.get("project_root"),
|
|
4348
4486
|
app_name=cmd_args.get("appName") or cmd_args.get("app_name"),
|
|
@@ -4395,7 +4533,7 @@ def _dispatch_serve(cfg, token, cmd, cmd_args):
|
|
|
4395
4533
|
form_name=cmd_args.get("formName") or cmd_args.get("form_name"),
|
|
4396
4534
|
field_name=cmd_args.get("fieldName") or cmd_args.get("field_name"),
|
|
4397
4535
|
biz_word=cmd_args.get("bizWord") or cmd_args.get("biz_word"),
|
|
4398
|
-
field_type=cmd_args.get("fieldType") or cmd_args.get("field_type")
|
|
4536
|
+
field_type=cmd_args.get("fieldType") or cmd_args.get("field_type"),
|
|
4399
4537
|
app_root=cmd_args.get("appRoot") or cmd_args.get("app_root"),
|
|
4400
4538
|
project_root=cmd_args.get("projectRoot") or cmd_args.get("project_root"),
|
|
4401
4539
|
app_name=cmd_args.get("appName") or cmd_args.get("app_name"),
|
|
@@ -4534,6 +4672,15 @@ def _dispatch_serve(cfg, token, cmd, cmd_args):
|
|
|
4534
4672
|
form_number=cmd_args.get("formNumber"),
|
|
4535
4673
|
)
|
|
4536
4674
|
|
|
4675
|
+
elif cmd == "removeReportColumn":
|
|
4676
|
+
from types import SimpleNamespace
|
|
4677
|
+
if not isinstance(cmd_args.get("dryRun", False), bool):
|
|
4678
|
+
raise ValueError("REPORT_INPUT_INVALID: dryRun must be boolean")
|
|
4679
|
+
return _remove_owned_report_column(cfg, token, SimpleNamespace(
|
|
4680
|
+
app_root=cmd_args.get("appRoot"), formNumber=cmd_args.get("formNumber"),
|
|
4681
|
+
formId=cmd_args.get("formId"), fieldKey=cmd_args.get("fieldKey"),
|
|
4682
|
+
dry_run=cmd_args.get("dryRun", False)))
|
|
4683
|
+
|
|
4537
4684
|
elif cmd == "setReportFilters":
|
|
4538
4685
|
filters = normalize_report_filters_input(_load_json_arg(cmd_args.get("filters", [])))
|
|
4539
4686
|
return do_set_report_filters(
|
|
@@ -4545,14 +4692,8 @@ def _dispatch_serve(cfg, token, cmd, cmd_args):
|
|
|
4545
4692
|
)
|
|
4546
4693
|
|
|
4547
4694
|
elif cmd == "setReportSorts":
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
cfg, token,
|
|
4551
|
-
form_id=cmd_args.get("formId"),
|
|
4552
|
-
sorts=sorts,
|
|
4553
|
-
dry_run=cmd_args.get("dryRun", False),
|
|
4554
|
-
form_number=cmd_args.get("formNumber"),
|
|
4555
|
-
)
|
|
4695
|
+
normalize_report_sorts_input(_load_json_arg(cmd_args.get("sorts", [])))
|
|
4696
|
+
raise RuntimeError(REPORT_SORTS_API_UNSAFE)
|
|
4556
4697
|
|
|
4557
4698
|
elif cmd == "registerReportPlugin":
|
|
4558
4699
|
plugin = normalize_report_plugin_input(_load_json_arg(cmd_args.get("plugin", {})))
|
|
@@ -4979,8 +5120,7 @@ def _serve_loop(cfg):
|
|
|
4979
5120
|
|
|
4980
5121
|
|
|
4981
5122
|
# ─── Report Pipeline ─────────────────────────────────────────────────────────
|
|
4982
|
-
#
|
|
4983
|
-
# setReportFilters → setReportSorts → registerReportPlugin ×N
|
|
5123
|
+
# 创建流水线保留七步依赖顺序;默认排序仅进入 Java 契约,不写入 InitField。
|
|
4984
5124
|
#
|
|
4985
5125
|
# Report data sources are hidden in the Cosmic designer and are no longer written here.
|
|
4986
5126
|
# A report gets its rows from the data-fetch plugin's query(ReportQueryParam, Object).
|
|
@@ -5042,9 +5182,13 @@ def _settle_report_property_design_state(cfg, token, result, form_number, app_ro
|
|
|
5042
5182
|
print(f"[{command}] could not sync design-state evidence: {exc}",
|
|
5043
5183
|
file=sys.stderr, flush=True)
|
|
5044
5184
|
return
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5185
|
+
try:
|
|
5186
|
+
attach_report_property_design_state(
|
|
5187
|
+
result, evidence_path,
|
|
5188
|
+
expectation["hostType"], expectation["expected"])
|
|
5189
|
+
except Exception as exc:
|
|
5190
|
+
# 此处只有写成功后才会进入,设计证据失败不能丢失该边界。
|
|
5191
|
+
raise ReportMutationError(str(exc), mutation_applied=True) from exc
|
|
5048
5192
|
|
|
5049
5193
|
|
|
5050
5194
|
def _execute_report_pipeline(cfg, token, artifact, biz_app_id, biz_unit_id, app_root=None):
|
|
@@ -5055,7 +5199,7 @@ def _execute_report_pipeline(cfg, token, artifact, biz_app_id, biz_unit_id, app_
|
|
|
5055
5199
|
2. setReportQueryDataSource (if a query data source is declared)
|
|
5056
5200
|
3. setReportColumns
|
|
5057
5201
|
4. setReportFilters (if any)
|
|
5058
|
-
5.
|
|
5202
|
+
5. preserve default sorts for the Java query contract (no metadata write)
|
|
5059
5203
|
6. registerReportPlugin for each plugin (if any)
|
|
5060
5204
|
7. apply reportProperties (if any), LAST so it settles ShowFilterFields after step 4
|
|
5061
5205
|
|
|
@@ -5104,6 +5248,10 @@ def _execute_report_pipeline(cfg, token, artifact, biz_app_id, biz_unit_id, app_
|
|
|
5104
5248
|
normalize_report_plugin_input(item)
|
|
5105
5249
|
for item in (artifact.get("reportPlugins") or [])
|
|
5106
5250
|
]
|
|
5251
|
+
# 创建前确认排序引用和承接插件;不能创建后才发现需求没有实现通道。
|
|
5252
|
+
default_sorts = compile_report_default_sorts({
|
|
5253
|
+
"reportSorts": sorts, "reportColumns": columns, "reportPlugins": plugins,
|
|
5254
|
+
})
|
|
5107
5255
|
if artifact.get("reportBehavior"):
|
|
5108
5256
|
raise ValueError(
|
|
5109
5257
|
"REPORT_INPUT_INVALID: reportBehavior is not a published typed CLI capability"
|
|
@@ -5182,20 +5330,21 @@ def _execute_report_pipeline(cfg, token, artifact, biz_app_id, biz_unit_id, app_
|
|
|
5182
5330
|
print("[report-pipeline] Step 3/7: no reportColumns (skipped)", file=sys.stderr, flush=True)
|
|
5183
5331
|
|
|
5184
5332
|
# Step 4: setReportFilters
|
|
5333
|
+
# The outcome records what the platform did with each typed filter editor: a platform without
|
|
5334
|
+
# the typed report filter patch renders the legacy control, which is reported, not failed.
|
|
5335
|
+
filter_editor_outcome = {}
|
|
5185
5336
|
if filters:
|
|
5186
5337
|
print(f"[report-pipeline] Step 4/7: setReportFilters ({len(filters)} filters)",
|
|
5187
5338
|
file=sys.stderr, flush=True)
|
|
5188
|
-
do_set_report_filters(cfg, token, form_id=form_id, filters=filters
|
|
5339
|
+
do_set_report_filters(cfg, token, form_id=form_id, filters=filters,
|
|
5340
|
+
outcome=filter_editor_outcome)
|
|
5189
5341
|
else:
|
|
5190
5342
|
print("[report-pipeline] Step 4/7: no reportFilters (skipped)", file=sys.stderr, flush=True)
|
|
5191
5343
|
|
|
5192
|
-
#
|
|
5344
|
+
# 第五步仅保留插件排序契约,绝不调用会污染 InitField 的 ReportSorts。
|
|
5193
5345
|
if sorts:
|
|
5194
|
-
print(f"[report-pipeline] Step 5/7:
|
|
5195
|
-
|
|
5196
|
-
validate_report_references(
|
|
5197
|
-
"sorts", sorts, do_get_report_schema(cfg, token, form_id=form_id))
|
|
5198
|
-
do_set_report_sorts(cfg, token, form_id=form_id, sorts=sorts)
|
|
5346
|
+
print(f"[report-pipeline] Step 5/7: default sorts -> Java query contract "
|
|
5347
|
+
f"({len(default_sorts)} rules; runtime unverified)", file=sys.stderr, flush=True)
|
|
5199
5348
|
else:
|
|
5200
5349
|
print("[report-pipeline] Step 5/7: no reportSorts (skipped)", file=sys.stderr, flush=True)
|
|
5201
5350
|
|
|
@@ -5210,9 +5359,11 @@ def _execute_report_pipeline(cfg, token, artifact, biz_app_id, biz_unit_id, app_
|
|
|
5210
5359
|
print("[report-pipeline] Step 6/7: no reportPlugins (skipped)", file=sys.stderr, flush=True)
|
|
5211
5360
|
|
|
5212
5361
|
# Step 7: reportProperties
|
|
5213
|
-
# Last on purpose.
|
|
5214
|
-
#
|
|
5215
|
-
#
|
|
5362
|
+
# Last on purpose. A platform without the typed report filter patch has setReportFilters
|
|
5363
|
+
# write ShowFilterFields as a comma-joined string the runtime cannot parse, and a patched one
|
|
5364
|
+
# resets FilterMustInput and the initial filter fields from the filters, so applying the
|
|
5365
|
+
# property section afterwards is what leaves a freshly created report with what it declared.
|
|
5366
|
+
# Every write here verifies itself.
|
|
5216
5367
|
property_results = []
|
|
5217
5368
|
if property_plan:
|
|
5218
5369
|
_prop_number = str(
|
|
@@ -5258,15 +5409,10 @@ def _execute_report_pipeline(cfg, token, artifact, biz_app_id, biz_unit_id, app_
|
|
|
5258
5409
|
file=sys.stderr, flush=True)
|
|
5259
5410
|
|
|
5260
5411
|
final_schema = do_get_report_schema(cfg, token, form_id=form_id)
|
|
5261
|
-
#
|
|
5262
|
-
# projection they had no observable read-back at all. The platform's own design-state
|
|
5263
|
-
# export does carry them: sync it now — after every write, before verification — so the
|
|
5264
|
-
# file on disk cannot be older than what it is being used to prove.
|
|
5265
|
-
# The same export also proves the filter properties the API projection cannot decide, so a
|
|
5266
|
-
# report with a required filter needs it even when it declares no sorts and no plugin.
|
|
5412
|
+
# 设计态导出只补充插件和过滤属性证据,不证明排序。所有写入后同步,避免使用旧文件。
|
|
5267
5413
|
_pending_dym_sections = [
|
|
5268
5414
|
section for section in (final_schema.get("unverifiableSections") or [])
|
|
5269
|
-
if
|
|
5415
|
+
if section == "reportPlugins" and plugins
|
|
5270
5416
|
]
|
|
5271
5417
|
if app_root and (_pending_dym_sections or filters_need_dym_evidence(filters)):
|
|
5272
5418
|
_dym_number = str(final_schema.get("formNumber") or form_number or "").strip()
|
|
@@ -5291,12 +5437,13 @@ def _execute_report_pipeline(cfg, token, artifact, biz_app_id, biz_unit_id, app_
|
|
|
5291
5437
|
if columns:
|
|
5292
5438
|
checks.append(report_readback_verification("columns", columns, final_schema))
|
|
5293
5439
|
if filters:
|
|
5294
|
-
if
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
checks.append(
|
|
5298
|
-
|
|
5299
|
-
|
|
5440
|
+
if filter_editor_outcome:
|
|
5441
|
+
final_schema["filterEditorOutcome"] = filter_editor_outcome
|
|
5442
|
+
filter_check = report_readback_verification("filters", filters, final_schema)
|
|
5443
|
+
checks.append(filter_check)
|
|
5444
|
+
if filter_check.get("filterEditors"):
|
|
5445
|
+
filter_editor_outcome = filter_check["filterEditors"]
|
|
5446
|
+
# 默认排序由 query() 实现,不纳入元数据回读通过项。
|
|
5300
5447
|
if "reportPlugins" not in unverifiable:
|
|
5301
5448
|
for plugin in plugins:
|
|
5302
5449
|
checks.append(report_readback_verification("plugin", plugin, final_schema))
|
|
@@ -5326,6 +5473,15 @@ def _execute_report_pipeline(cfg, token, artifact, biz_app_id, biz_unit_id, app_
|
|
|
5326
5473
|
print("[report-pipeline] no report read-back available on this deployment; "
|
|
5327
5474
|
"section writes succeeded but were not independently re-read",
|
|
5328
5475
|
file=sys.stderr, flush=True)
|
|
5476
|
+
# The platform's own filter receipt is still evidence: an editor it reported as neither the
|
|
5477
|
+
# requested one nor the legacy one fails the run even without a read-back.
|
|
5478
|
+
if filter_editor_outcome.get("typedFilterSupport") == "mismatch":
|
|
5479
|
+
_editors, _receipt_mismatches = resolve_filter_editors(filter_editor_outcome, [])
|
|
5480
|
+
failed_checks = [{
|
|
5481
|
+
"section": "reportFilters", "source": "receipt", "verified": False,
|
|
5482
|
+
"mismatches": _receipt_mismatches, "filterEditors": _editors,
|
|
5483
|
+
}]
|
|
5484
|
+
checks = list(failed_checks)
|
|
5329
5485
|
|
|
5330
5486
|
# createPage adds the ISV prefix, so reconcile form_number to the authoritative
|
|
5331
5487
|
# value read back by formId (keeps archive/formNumbers/syncDym pointing at the real form).
|
|
@@ -5357,8 +5513,26 @@ def _execute_report_pipeline(cfg, token, artifact, biz_app_id, biz_unit_id, app_
|
|
|
5357
5513
|
"readBackSource": read_back_source,
|
|
5358
5514
|
"verification": {"verified": verification_verified, "checks": checks},
|
|
5359
5515
|
}
|
|
5516
|
+
if default_sorts:
|
|
5517
|
+
summary["reportDefaultSorts"] = {
|
|
5518
|
+
"implementation": "reportlist.query", "requirements": default_sorts,
|
|
5519
|
+
"status": "pendingJavaImplementation", "metadataWritten": False, "runtimeVerified": False,
|
|
5520
|
+
}
|
|
5360
5521
|
if query_data_source_result:
|
|
5361
5522
|
summary["queryDataSource"] = query_data_source_result
|
|
5523
|
+
if filter_editor_outcome and any(
|
|
5524
|
+
row.get("requestedFieldType") for row in filter_editor_outcome.get("editors") or []):
|
|
5525
|
+
# Which editor each typed filter actually got. prepare_plugin_handoff forwards it to the
|
|
5526
|
+
# plugin contract, and a degraded filter is an unresolved boundary the reply must name.
|
|
5527
|
+
summary["reportFilterEditors"] = {**filter_editor_outcome, "formNumber": form_number}
|
|
5528
|
+
if filter_editor_outcome.get("typedFilterSupport") not in ("available", "notRequested"):
|
|
5529
|
+
print(
|
|
5530
|
+
"[report-pipeline] typed filter editors: "
|
|
5531
|
+
f"{filter_editor_outcome.get('typedFilterSupport')}; degraded "
|
|
5532
|
+
f"{filter_editor_outcome.get('degradedFilters') or []} render the legacy control until "
|
|
5533
|
+
"the platform's typed report filter patch is installed and the filters are re-applied",
|
|
5534
|
+
file=sys.stderr, flush=True,
|
|
5535
|
+
)
|
|
5362
5536
|
if property_plan:
|
|
5363
5537
|
# Each property write verified itself, so what the summary carries is which of them could
|
|
5364
5538
|
# be proven and which resolve on no read path this pipeline owns.
|
|
@@ -5383,9 +5557,10 @@ def _execute_report_pipeline(cfg, token, artifact, biz_app_id, biz_unit_id, app_
|
|
|
5383
5557
|
_plugin_contract = (
|
|
5384
5558
|
None if (query_data_source and not plugins)
|
|
5385
5559
|
else compile_report_plugin_contract(
|
|
5386
|
-
{"reportColumns": columns, "reportFilters": filters, "
|
|
5387
|
-
"reportProperties": artifact.get("reportProperties") or {}},
|
|
5560
|
+
{"reportColumns": columns, "reportFilters": filters, "reportSorts": sorts,
|
|
5561
|
+
"reportPlugins": plugins, "reportProperties": artifact.get("reportProperties") or {}},
|
|
5388
5562
|
form_number,
|
|
5563
|
+
filter_editors=filter_editor_outcome or None,
|
|
5389
5564
|
)
|
|
5390
5565
|
)
|
|
5391
5566
|
if _plugin_contract:
|
|
@@ -5393,6 +5568,7 @@ def _execute_report_pipeline(cfg, token, artifact, biz_app_id, biz_unit_id, app_
|
|
|
5393
5568
|
"dataSetColumnTypes": len(_plugin_contract["dataSetColumnTypes"]),
|
|
5394
5569
|
"columnPresentation": len(_plugin_contract["columnPresentation"]),
|
|
5395
5570
|
"filterEnforcement": len(_plugin_contract["filterEnforcement"]),
|
|
5571
|
+
"defaultSorts": len(_plugin_contract["defaultSorts"]),
|
|
5396
5572
|
}
|
|
5397
5573
|
if app_root:
|
|
5398
5574
|
try:
|
|
@@ -5410,6 +5586,16 @@ def _execute_report_pipeline(cfg, token, artifact, biz_app_id, biz_unit_id, app_
|
|
|
5410
5586
|
file=sys.stderr, flush=True,
|
|
5411
5587
|
)
|
|
5412
5588
|
|
|
5589
|
+
if app_root and verification_verified and not failed_checks:
|
|
5590
|
+
try:
|
|
5591
|
+
summary["reportAuthoringState"] = write_report_authoring_state(
|
|
5592
|
+
app_root, form_number, form_id,
|
|
5593
|
+
{**artifact, "reportColumns": columns, "reportFilters": filters, "reportPlugins": plugins},
|
|
5594
|
+
final_schema, filter_editor_outcome or None)
|
|
5595
|
+
except (OSError, ValueError) as exc:
|
|
5596
|
+
summary["reportAuthoringState"] = {"status": "failed", "errorType": type(exc).__name__,
|
|
5597
|
+
"platformMutationApplied": True, "reason": "Repair local state; do not recreate the report"}
|
|
5598
|
+
|
|
5413
5599
|
# Java plugin delivery consumes this result through
|
|
5414
5600
|
# prepare_plugin_handoff.py --run-result, so persist it at a stable path instead of
|
|
5415
5601
|
# relying on pjson's size threshold (a small report summary never reached disk).
|
|
@@ -5468,6 +5654,7 @@ _CATALOG_PAYLOAD_SCHEMA_REFS = {
|
|
|
5468
5654
|
"createScript": "skills/cosmic-meta-api/contracts/schema/script-create.schema.json",
|
|
5469
5655
|
"setReportColumns": "skills/cosmic-meta-api/contracts/schema/report-write.schema.json#/$defs/columns",
|
|
5470
5656
|
"addReportColumns": "skills/cosmic-meta-api/contracts/schema/report-write.schema.json#/$defs/columns",
|
|
5657
|
+
"removeReportColumn": "skills/cosmic-meta-api/contracts/schema/report-write.schema.json#/$defs/columnRemoval",
|
|
5471
5658
|
"setReportFilters": "skills/cosmic-meta-api/contracts/schema/report-write.schema.json#/$defs/filters",
|
|
5472
5659
|
"setReportSorts": "skills/cosmic-meta-api/contracts/schema/report-write.schema.json#/$defs/sorts",
|
|
5473
5660
|
"registerReportPlugin": "skills/cosmic-meta-api/contracts/schema/report-write.schema.json#/$defs/plugin",
|
|
@@ -5537,6 +5724,7 @@ _CATALOG_COMMAND_CONTRACT_REFS = {
|
|
|
5537
5724
|
"setSummaryToField": "skills/cosmic-meta-api/contracts/cli/rule-domain.json#commands/setSummaryToField",
|
|
5538
5725
|
"setReportColumns": "skills/cosmic-meta-api/contracts/cli/report-write-contracts.json#commands/setReportColumns",
|
|
5539
5726
|
"addReportColumns": "skills/cosmic-meta-api/contracts/cli/report-write-contracts.json#commands/addReportColumns",
|
|
5727
|
+
"removeReportColumn": "skills/cosmic-meta-api/contracts/cli/report-write-contracts.json#commands/removeReportColumn",
|
|
5540
5728
|
"setReportFilters": "skills/cosmic-meta-api/contracts/cli/report-write-contracts.json#commands/setReportFilters",
|
|
5541
5729
|
"setReportSorts": "skills/cosmic-meta-api/contracts/cli/report-write-contracts.json#commands/setReportSorts",
|
|
5542
5730
|
"registerReportPlugin": "skills/cosmic-meta-api/contracts/cli/report-write-contracts.json#commands/registerReportPlugin",
|
|
@@ -5616,11 +5804,12 @@ _CATALOG_COMMANDS_BY_EFFECT = {
|
|
|
5616
5804
|
}),
|
|
5617
5805
|
"destructive": frozenset({
|
|
5618
5806
|
"deleteApp", "deleteForm", "deleteMenu", "deleteOperation", "deleteOperationValidation", "deletePlugin",
|
|
5619
|
-
"deleteRule", "deleteUnit", "removeContainer", "removeField", "removeFilterColumn",
|
|
5807
|
+
"deleteRule", "deleteUnit", "removeContainer", "removeField", "removeFilterColumn", "removeReportColumn",
|
|
5620
5808
|
}),
|
|
5621
5809
|
}
|
|
5622
5810
|
_CATALOG_RISK_OVERRIDES = {
|
|
5623
5811
|
"cleanTemp": "medium",
|
|
5812
|
+
"removeReportColumn": "high",
|
|
5624
5813
|
# the only setter whose blast radius is an entire form: an unmodified round trip
|
|
5625
5814
|
# silently changed the resolved Features of 17 fields
|
|
5626
5815
|
"saveFullMetadata": "high",
|
|
@@ -5645,6 +5834,11 @@ _CATALOG_UNAVAILABLE_COMMANDS = {
|
|
|
5645
5834
|
# 404 came from calling dedicated endpoints that were never supposed to exist.
|
|
5646
5835
|
# Both now route through setComplexProperty with the complexType the backend
|
|
5647
5836
|
# actually dispatches on (filter / permissionControl), so they are available again.
|
|
5837
|
+
"setReportSorts": {
|
|
5838
|
+
"availability": "blocked",
|
|
5839
|
+
"availabilityReason": REPORT_SORTS_API_UNSAFE,
|
|
5840
|
+
"replacedBy": "Java reportlist query() via reportContract.defaultSorts",
|
|
5841
|
+
},
|
|
5648
5842
|
"setComboItems": {
|
|
5649
5843
|
"availability": "deprecated",
|
|
5650
5844
|
"availabilityReason": (
|
|
@@ -5724,15 +5918,26 @@ _CATALOG_ARGUMENT_CONSTRAINTS = {
|
|
|
5724
5918
|
"column is skipped, so repeating the call is idempotent"
|
|
5725
5919
|
),
|
|
5726
5920
|
}],
|
|
5921
|
+
"removeReportColumn": [{
|
|
5922
|
+
"kind": "target_binding",
|
|
5923
|
+
"arguments": ["app_root", "formNumber", "fieldKey"],
|
|
5924
|
+
"identity": "exact leaf fieldKey",
|
|
5925
|
+
"message": "Deletes one leaf through ReportColumns.remove, verifies the remaining tree, and refreshes complete authoring when possible. Backend patch required; unavailable fails closed, never hides or rebuilds. Unknown outcomes must not be replayed; Java and entity cleanup remain separate evidence boundaries.",
|
|
5926
|
+
}],
|
|
5727
5927
|
"setReportFilters": [{
|
|
5728
5928
|
"kind": "full_replacement",
|
|
5729
5929
|
"arguments": ["app_root", "formNumber", "filters"],
|
|
5730
|
-
"message":
|
|
5930
|
+
"message": (
|
|
5931
|
+
"filters is the complete desired report filter state; a filter may declare fieldType "
|
|
5932
|
+
"with its parameters for a native editor, and the result's filterEditors says which "
|
|
5933
|
+
"editor each filter rendered (a platform without the typed filter patch renders the "
|
|
5934
|
+
"legacy control). CLI performs independent read-back"
|
|
5935
|
+
),
|
|
5731
5936
|
}],
|
|
5732
5937
|
"setReportSorts": [{
|
|
5733
|
-
"kind": "
|
|
5938
|
+
"kind": "blocked",
|
|
5734
5939
|
"arguments": ["app_root", "formNumber", "sorts"],
|
|
5735
|
-
"message": "
|
|
5940
|
+
"message": "REPORT_SORTS_API_UNSAFE: no metadata write; preserve reportSorts in the Java query contract",
|
|
5736
5941
|
}],
|
|
5737
5942
|
"registerReportPlugin": [{
|
|
5738
5943
|
"kind": "upsert",
|
|
@@ -5767,8 +5972,7 @@ _CATALOG_ARGUMENT_CONSTRAINTS = {
|
|
|
5767
5972
|
"target": "templateNumber",
|
|
5768
5973
|
"sources": ["template", "artifact.templateNumber", "emitManifest.templateNumber"],
|
|
5769
5974
|
"message": (
|
|
5770
|
-
"templateNumber has no implicit default; an explicit blank
|
|
5771
|
-
"for a MainEntity dynamic form"
|
|
5975
|
+
"templateNumber has no implicit default; use blankPage for an explicit blank BillEntity, or empty for a MainEntity dynamic form"
|
|
5772
5976
|
),
|
|
5773
5977
|
},
|
|
5774
5978
|
{
|
|
@@ -5791,8 +5995,7 @@ _CATALOG_ARGUMENT_CONSTRAINTS = {
|
|
|
5791
5995
|
"target": "templateNumber",
|
|
5792
5996
|
"sources": ["template", "artifact.templateNumber", "emitManifest.templateNumber"],
|
|
5793
5997
|
"message": (
|
|
5794
|
-
"no implicit default: every artifact needs an explicit templateNumber;
|
|
5795
|
-
"for a MainEntity dynamic form"
|
|
5998
|
+
"no implicit default: every artifact needs an explicit templateNumber; blankPage supports BillEntity, empty supports MainEntity"
|
|
5796
5999
|
),
|
|
5797
6000
|
},
|
|
5798
6001
|
{
|
|
@@ -6044,7 +6247,7 @@ _CATALOG_ARGUMENT_CONSTRAINTS = {
|
|
|
6044
6247
|
"argument": "field_type",
|
|
6045
6248
|
"selectionOwner": "model",
|
|
6046
6249
|
"contractRef": "skills/cosmic-meta-knowledge/domain-model/field-types.md",
|
|
6047
|
-
"message": "
|
|
6250
|
+
"message": "select the exact documented FieldDataType from business meaning and pass it explicitly for every new field; there is no default field type",
|
|
6048
6251
|
},
|
|
6049
6252
|
{
|
|
6050
6253
|
"kind": "conditional_parameters",
|
|
@@ -6619,6 +6822,7 @@ def _main_impl():
|
|
|
6619
6822
|
help="One or more artifact file paths (space-separated); when omitted, from --app-root _emit_manifest.json auto-collected")
|
|
6620
6823
|
prb.add_argument("--app-root", default=None, dest="app_root",
|
|
6621
6824
|
help="Working directory; when provided, auto-fills --bizAppId / --bizUnitId / --artifacts / --template")
|
|
6825
|
+
prb.add_argument("--compact", action="store_true", help="Return verification and continuation evidence; keep the full receipt at resultPath")
|
|
6622
6826
|
prb.add_argument("--app-code", "--appCode", default=None, dest="app_code",
|
|
6623
6827
|
help="Exact existing application code; verifies and synchronizes a trusted appRoot identity before any build write")
|
|
6624
6828
|
prb.add_argument("--emit-manifest", default=None, dest="emit_manifest",
|
|
@@ -6835,7 +7039,7 @@ def _main_impl():
|
|
|
6835
7039
|
paf.add_argument("--biz-word", dest="biz_word",
|
|
6836
7040
|
help="Concise semantic English business word without ISV prefix")
|
|
6837
7041
|
paf.add_argument(
|
|
6838
|
-
"--field-type", default=
|
|
7042
|
+
"--field-type", default=None, dest="field_type",
|
|
6839
7043
|
choices=field_type_choices(),
|
|
6840
7044
|
help="Exact FieldDataType selected from the authoritative field-types contract"
|
|
6841
7045
|
)
|
|
@@ -6963,8 +7167,8 @@ def _main_impl():
|
|
|
6963
7167
|
help="New field display name")
|
|
6964
7168
|
pasf.add_argument("--biz-word", required=True, dest="biz_word",
|
|
6965
7169
|
help="Concise semantic English business word without ISV prefix")
|
|
6966
|
-
pasf.add_argument("--field-type", default=
|
|
6967
|
-
help="
|
|
7170
|
+
pasf.add_argument("--field-type", default=None, dest="field_type",
|
|
7171
|
+
help="Exact platform field type selected from business semantics")
|
|
6968
7172
|
pasf.add_argument("--app-root", default=None, dest="app_root",
|
|
6969
7173
|
help="Already verified app root")
|
|
6970
7174
|
pasf.add_argument("--project-root", default=None, dest="project_root",
|
|
@@ -7476,7 +7680,7 @@ def _main_impl():
|
|
|
7476
7680
|
p_eccv.add_argument("--condition-field", dest="condition_field")
|
|
7477
7681
|
p_eccv.add_argument(
|
|
7478
7682
|
"--operator",
|
|
7479
|
-
choices=["equals", "not-equals", "greater-than", "greater-or-equal", "less-than", "less-or-equal"])
|
|
7683
|
+
choices=["equals", "not-equals", "greater-than", "greater-or-equal", "less-than", "less-or-equal", "empty", "not-empty"])
|
|
7480
7684
|
p_eccv.add_argument("--value")
|
|
7481
7685
|
p_eccv.add_argument("--source", help="Source field key or caption")
|
|
7482
7686
|
p_eccv.add_argument("--target", help="Target field key or caption")
|
|
@@ -8533,6 +8737,14 @@ def _main_impl():
|
|
|
8533
8737
|
p_arc.add_argument("--app-root", required=True, dest="app_root",
|
|
8534
8738
|
help="Owned application root used to prove the exact report target")
|
|
8535
8739
|
|
|
8740
|
+
p_rrc = sub.add_parser("removeReportColumn",
|
|
8741
|
+
help="Remove one report leaf column (requires backend deletion patch; no automatic fallback)")
|
|
8742
|
+
p_rrc.add_argument("--formNumber", required=True, help="Exact report form number")
|
|
8743
|
+
p_rrc.add_argument("--formId", default=None, help="Optional exact form ID; mismatch fails closed")
|
|
8744
|
+
p_rrc.add_argument("--fieldKey", required=True, help="Exact leaf column key, including a nested leaf")
|
|
8745
|
+
p_rrc.add_argument("--app-root", required=True, dest="app_root", help="Owned application root")
|
|
8746
|
+
p_rrc.add_argument("--dryRun", action="store_true", dest="dry_run", help="Local payload only; does not prove backend support")
|
|
8747
|
+
|
|
8536
8748
|
p_srf = sub.add_parser("setReportFilters",
|
|
8537
8749
|
help="Set report filter fields")
|
|
8538
8750
|
p_srf.add_argument("--formNumber", required=True, help="Exact report form number")
|
|
@@ -8545,13 +8757,13 @@ def _main_impl():
|
|
|
8545
8757
|
help="Owned application root used to prove the exact report target")
|
|
8546
8758
|
|
|
8547
8759
|
p_srs = sub.add_parser("setReportSorts",
|
|
8548
|
-
help="
|
|
8760
|
+
help="Blocked unsafe metadata sorting; use the Java query contract")
|
|
8549
8761
|
p_srs.add_argument("--formNumber", required=True, help="Exact report form number")
|
|
8550
8762
|
p_srs.add_argument("--formId", default=None, help="Optional exact report form ID; mismatch fails closed")
|
|
8551
8763
|
p_srs.add_argument("--sorts", required=True,
|
|
8552
8764
|
help="Report sorts JSON file path or inline JSON string")
|
|
8553
8765
|
p_srs.add_argument("--dryRun", action="store_true", dest="dry_run",
|
|
8554
|
-
help="
|
|
8766
|
+
help="兼容旧参数;同样拒绝危险排序写入,不输出可执行 payload")
|
|
8555
8767
|
p_srs.add_argument("--app-root", required=True, dest="app_root",
|
|
8556
8768
|
help="Owned application root used to prove the exact report target")
|
|
8557
8769
|
|
|
@@ -8590,8 +8802,9 @@ def _main_impl():
|
|
|
8590
8802
|
"moreFilterPanel=ReportMoreFilterPanelAp, form=ReportFormAp (root), "
|
|
8591
8803
|
"tree=ReportTreeAp, column=one report column or column group")
|
|
8592
8804
|
p_srp.add_argument("--element", default=None, dest="element_key",
|
|
8593
|
-
help="Exact report column or column group key; required for --target column "
|
|
8594
|
-
"
|
|
8805
|
+
help="Exact report column or column group key; required for --target column, "
|
|
8806
|
+
"optional for --target tree to pick one of several ReportTreeAp controls "
|
|
8807
|
+
"(found by type otherwise), and refused for every other target")
|
|
8595
8808
|
p_srp.add_argument("--input", required=True, dest="input_file",
|
|
8596
8809
|
help="Property map as JSON or @file, e.g. '{\"ShowSeq\": false, \"PageRows\": 500}'")
|
|
8597
8810
|
p_srp.add_argument("--dryRun", action="store_true", dest="dry_run",
|
|
@@ -9217,10 +9430,12 @@ def _main_impl():
|
|
|
9217
9430
|
set_stdout_mode(bool(args.stdout))
|
|
9218
9431
|
if (args.stdout or args.output_file) and hasattr(args, "raw_json"):
|
|
9219
9432
|
args.raw_json = True
|
|
9220
|
-
|
|
9221
|
-
_route_unstructured_prints_to_stderr()
|
|
9433
|
+
# 进程级日志路由由 main 独占并恢复,内部执行函数不改写 builtins.print。
|
|
9222
9434
|
app_root = _resolve_app_root_arg(args)
|
|
9223
9435
|
if app_root:
|
|
9436
|
+
selected = bound_entrypoint(app_root, "skills/cosmic-meta-api/scripts/cosmic_api.py")
|
|
9437
|
+
if selected:
|
|
9438
|
+
return subprocess.call([sys.executable, str(selected), *sys.argv[1:]])
|
|
9224
9439
|
validate_execution_binding(app_root)
|
|
9225
9440
|
_retarget_runtime_dir(app_root)
|
|
9226
9441
|
|
|
@@ -9263,7 +9478,7 @@ def _main_impl():
|
|
|
9263
9478
|
args.fields = _load_json_arg(args.fields)
|
|
9264
9479
|
if args.biz_word is not None or args.combo is not None or args.combo_json is not None:
|
|
9265
9480
|
raise _CliUsageError("--fields carries each field specification; do not combine single-field specifications")
|
|
9266
|
-
if args.field_type
|
|
9481
|
+
if args.field_type is not None or args.required or any(getattr(args, name, None) for name in (
|
|
9267
9482
|
"basedata", "ref_bill", "mul_table", "unit_field", "flex_type", "ref_base_field", "ref_display_prop", "asstTypeId", "asst_type", "extAppId")):
|
|
9268
9483
|
raise _CliUsageError("--fields carries reference/type options on each item; do not combine single-field or selected-extension flags")
|
|
9269
9484
|
validate_add_fields_input(args.fields)
|
|
@@ -9330,10 +9545,13 @@ def _main_impl():
|
|
|
9330
9545
|
# before resolving a platform target so malformed JSON can never cause a write.
|
|
9331
9546
|
if args.cmd in ("setReportColumns", "addReportColumns"):
|
|
9332
9547
|
args._report_payload = normalize_report_columns_input(_load_json_arg(args.columns))
|
|
9548
|
+
elif args.cmd == "removeReportColumn":
|
|
9549
|
+
args.fieldKey = normalize_report_column_removal_input({"fieldKey": args.fieldKey})["fieldKey"]
|
|
9333
9550
|
elif args.cmd == "setReportFilters":
|
|
9334
9551
|
args._report_payload = normalize_report_filters_input(_load_json_arg(args.filters))
|
|
9335
9552
|
elif args.cmd == "setReportSorts":
|
|
9336
|
-
|
|
9553
|
+
normalize_report_sorts_input(_load_json_arg(args.sorts))
|
|
9554
|
+
raise RuntimeError(REPORT_SORTS_API_UNSAFE)
|
|
9337
9555
|
elif args.cmd == "registerReportPlugin":
|
|
9338
9556
|
args._report_payload = normalize_report_plugin_input(_load_json_arg(args.plugin))
|
|
9339
9557
|
|
|
@@ -9528,10 +9746,9 @@ def _main_impl():
|
|
|
9528
9746
|
file=sys.stderr,
|
|
9529
9747
|
)
|
|
9530
9748
|
sys.exit(2)
|
|
9531
|
-
if _tpl
|
|
9749
|
+
if _tpl in {"", "blankPage"} and not _artifact_supports_blank_template(raw_artifact, _tpl):
|
|
9532
9750
|
print(
|
|
9533
|
-
"⛔ run: 空 templateNumber 仅适用于 MainEntity
|
|
9534
|
-
"BillEntity/BaseEntity 必须提供真实模板编码。",
|
|
9751
|
+
"⛔ run: 空 templateNumber 仅适用于 MainEntity;BillEntity 显式空白创建请使用 blankPage。",
|
|
9535
9752
|
file=sys.stderr,
|
|
9536
9753
|
)
|
|
9537
9754
|
sys.exit(2)
|
|
@@ -9821,11 +10038,11 @@ def _main_impl():
|
|
|
9821
10038
|
invalid_blank_tpl = [
|
|
9822
10039
|
os.path.basename(p)
|
|
9823
10040
|
for p, t in tpl_per_artifact.items()
|
|
9824
|
-
if t
|
|
10041
|
+
if t in {"", "blankPage"} and not _artifact_file_supports_blank_template(p, t)
|
|
9825
10042
|
]
|
|
9826
10043
|
if invalid_blank_tpl:
|
|
9827
10044
|
print(
|
|
9828
|
-
"⛔ runBatch:
|
|
10045
|
+
"⛔ runBatch: 空模板仅支持 MainEntity 或显式 blankPage 的 BillEntity:"
|
|
9829
10046
|
+ ", ".join(invalid_blank_tpl),
|
|
9830
10047
|
file=sys.stderr,
|
|
9831
10048
|
)
|
|
@@ -10744,7 +10961,7 @@ def _main_impl():
|
|
|
10744
10961
|
if not final_ok and phase != "buildMeta" and not summary_one.get("errorCode"):
|
|
10745
10962
|
_attach_post_build_phase_failure(
|
|
10746
10963
|
summary_one, transformed, phase=phase, app_root=app_root,
|
|
10747
|
-
artifact_path=afile, pending_write=pending_write,
|
|
10964
|
+
artifact_path=afile, pending_write=pending_write, verification=verification,
|
|
10748
10965
|
)
|
|
10749
10966
|
_apply_build_failure_contract(transformed, summary_one)
|
|
10750
10967
|
return {
|
|
@@ -10917,7 +11134,7 @@ def _main_impl():
|
|
|
10917
11134
|
_atomic_json(progress.result_path, summary)
|
|
10918
11135
|
elif app_root:
|
|
10919
11136
|
summary = save_run_batch_result(summary, app_root, artifact_files)
|
|
10920
|
-
pjson(summary)
|
|
11137
|
+
pjson(result_summary(summary, summary["resultPath"]) if args.compact and summary.get("resultPath") else summary)
|
|
10921
11138
|
if args.verify:
|
|
10922
11139
|
verified = sum(
|
|
10923
11140
|
1 for item in results
|
|
@@ -11750,8 +11967,12 @@ def _main_impl():
|
|
|
11750
11967
|
raise _CliUsageError("use --input for several mappings, or --source/--target for one mapping")
|
|
11751
11968
|
if args.input_file and args.only_empty_target:
|
|
11752
11969
|
raise _CliUsageError("with --input put per-row onlyEmptyTarget inside mappings")
|
|
11753
|
-
if not args.input_file and not all((args.condition_field, args.operator, args.
|
|
11754
|
-
raise _CliUsageError("single mapping requires condition-field, operator,
|
|
11970
|
+
if not args.input_file and not all((args.condition_field, args.operator, args.source, args.target)):
|
|
11971
|
+
raise _CliUsageError("single mapping requires condition-field, operator, source and target")
|
|
11972
|
+
if not args.input_file and args.operator not in {"empty", "not-empty"} and not args.value:
|
|
11973
|
+
raise _CliUsageError("comparison operator requires a value")
|
|
11974
|
+
if not args.input_file and args.operator in {"empty", "not-empty"} and args.value not in (None, ""):
|
|
11975
|
+
raise _CliUsageError("empty and not-empty do not accept a value")
|
|
11755
11976
|
token = do_auth(cfg)
|
|
11756
11977
|
blocked = _bind_rule_domain_target(cfg, token, args, args.cmd)
|
|
11757
11978
|
if blocked is not None:
|
|
@@ -13663,7 +13884,8 @@ def _main_impl():
|
|
|
13663
13884
|
form_number=args.formNumber)
|
|
13664
13885
|
pjson(_attach_report_readback(
|
|
13665
13886
|
cfg, token, form_id, "columns", columns,
|
|
13666
|
-
{"formId": form_id, "formNumber": args.formNumber, "columnIds": column_ids}
|
|
13887
|
+
{"formId": form_id, "formNumber": args.formNumber, "columnIds": column_ids},
|
|
13888
|
+
app_root=args.app_root, schema_before=schema_before))
|
|
13667
13889
|
|
|
13668
13890
|
elif args.cmd == "addReportColumns":
|
|
13669
13891
|
columns = args._report_payload
|
|
@@ -13685,7 +13907,12 @@ def _main_impl():
|
|
|
13685
13907
|
{"before": schema_before.get("reportColumns") or [], "requested": columns},
|
|
13686
13908
|
{"formId": form_id, "formNumber": args.formNumber,
|
|
13687
13909
|
"plannedAppendFieldKeys": plan["plannedAppendFieldKeys"],
|
|
13688
|
-
"preexistingFieldKeys": plan["preexistingFieldKeys"]}
|
|
13910
|
+
"preexistingFieldKeys": plan["preexistingFieldKeys"]},
|
|
13911
|
+
app_root=args.app_root, schema_before=schema_before))
|
|
13912
|
+
|
|
13913
|
+
elif args.cmd == "removeReportColumn":
|
|
13914
|
+
token = None if getattr(args, "dry_run", False) else do_auth(cfg)
|
|
13915
|
+
pjson(_remove_owned_report_column(cfg, token, args))
|
|
13689
13916
|
|
|
13690
13917
|
elif args.cmd == "setReportFilters":
|
|
13691
13918
|
filters = args._report_payload
|
|
@@ -13700,32 +13927,17 @@ def _main_impl():
|
|
|
13700
13927
|
schema_before = do_get_report_schema(cfg, token, form_id=form_id)
|
|
13701
13928
|
bound_filters = validate_report_references(
|
|
13702
13929
|
"filters", filters, schema_before)
|
|
13930
|
+
filter_editors = {}
|
|
13703
13931
|
filter_ids = do_set_report_filters(
|
|
13704
13932
|
cfg, token, form_id=form_id, filters=bound_filters,
|
|
13705
|
-
form_number=args.formNumber)
|
|
13933
|
+
form_number=args.formNumber, outcome=filter_editors)
|
|
13706
13934
|
pjson(_attach_report_readback(
|
|
13707
13935
|
cfg, token, form_id, "filters", filters,
|
|
13708
|
-
{"formId": form_id, "formNumber": args.formNumber, "filterIds": filter_ids}
|
|
13936
|
+
{"formId": form_id, "formNumber": args.formNumber, "filterIds": filter_ids},
|
|
13937
|
+
filter_editors=filter_editors or None, app_root=args.app_root, schema_before=schema_before))
|
|
13709
13938
|
|
|
13710
13939
|
elif args.cmd == "setReportSorts":
|
|
13711
|
-
|
|
13712
|
-
if getattr(args, "dry_run", False):
|
|
13713
|
-
pjson(do_set_report_sorts(
|
|
13714
|
-
cfg, None, form_id=args.formId or "", sorts=sorts,
|
|
13715
|
-
dry_run=True, form_number=args.formNumber))
|
|
13716
|
-
return 0
|
|
13717
|
-
token = do_auth(cfg)
|
|
13718
|
-
target = _resolve_owned_report_target(cfg, token, args, args.cmd)
|
|
13719
|
-
form_id = target["formId"]
|
|
13720
|
-
schema_before = do_get_report_schema(cfg, token, form_id=form_id)
|
|
13721
|
-
validate_report_references(
|
|
13722
|
-
"sorts", sorts, schema_before)
|
|
13723
|
-
do_set_report_sorts(
|
|
13724
|
-
cfg, token, form_id=form_id, sorts=sorts,
|
|
13725
|
-
form_number=args.formNumber)
|
|
13726
|
-
pjson(_attach_report_readback(
|
|
13727
|
-
cfg, token, form_id, "sorts", sorts,
|
|
13728
|
-
{"formId": form_id, "formNumber": args.formNumber, "ok": True}))
|
|
13940
|
+
raise RuntimeError(REPORT_SORTS_API_UNSAFE)
|
|
13729
13941
|
|
|
13730
13942
|
elif args.cmd == "registerReportPlugin":
|
|
13731
13943
|
plugin = args._report_payload
|
|
@@ -13737,12 +13949,14 @@ def _main_impl():
|
|
|
13737
13949
|
token = do_auth(cfg)
|
|
13738
13950
|
target = _resolve_owned_report_target(cfg, token, args, args.cmd)
|
|
13739
13951
|
form_id = target["formId"]
|
|
13952
|
+
schema_before = do_get_report_schema(cfg, token, form_id=form_id)
|
|
13740
13953
|
plugin_id = do_register_report_plugin(
|
|
13741
13954
|
cfg, token, form_id=form_id, plugin_spec=plugin,
|
|
13742
13955
|
form_number=args.formNumber)
|
|
13743
13956
|
pjson(_attach_report_readback(
|
|
13744
13957
|
cfg, token, form_id, "plugin", plugin,
|
|
13745
|
-
{"formId": form_id, "formNumber": args.formNumber, "pluginId": plugin_id}
|
|
13958
|
+
{"formId": form_id, "formNumber": args.formNumber, "pluginId": plugin_id},
|
|
13959
|
+
app_root=args.app_root, schema_before=schema_before))
|
|
13746
13960
|
|
|
13747
13961
|
elif args.cmd == "setReportQueryDataSource":
|
|
13748
13962
|
if getattr(args, "dry_run", False):
|
|
@@ -13862,8 +14076,7 @@ def _main_impl():
|
|
|
13862
14076
|
_prr_id = str(_prr_row.get("formId") or "").strip()
|
|
13863
14077
|
_prr_schema = do_get_report_schema(cfg, token, form_id=_prr_id)
|
|
13864
14078
|
_prr_number = str(_prr_schema.get("formNumber") or args.formNumber or "").strip()
|
|
13865
|
-
#
|
|
13866
|
-
# silently omit the sorts and plugins that have to be restored.
|
|
14079
|
+
# 设计态导出补充插件证据;InitField 不证明排序,默认排序需求仍需完整 Artifact 对账。
|
|
13867
14080
|
try:
|
|
13868
14081
|
_prr_evidence = parse_report_dym(
|
|
13869
14082
|
_export_report_dym_evidence(cfg, token, _prr_number, args.app_root)
|
|
@@ -13886,7 +14099,21 @@ def _main_impl():
|
|
|
13886
14099
|
except Exception as exc:
|
|
13887
14100
|
print(f"[planReportRecreate] could not read the application menu tree: {exc}",
|
|
13888
14101
|
file=sys.stderr, flush=True)
|
|
13889
|
-
|
|
14102
|
+
# deleteForm takes the plugins on the report form itself with it and run does not
|
|
14103
|
+
# register them, so they are read now, while the form still exists.
|
|
14104
|
+
_prr_plugin_rows = None
|
|
14105
|
+
try:
|
|
14106
|
+
_prr_plugin_result = do_query_editable_plugins(cfg, token, form_number=_prr_number)
|
|
14107
|
+
if _is_api_success(_prr_plugin_result):
|
|
14108
|
+
_prr_plugin_rows = _prr_plugin_result.get("data") or []
|
|
14109
|
+
else:
|
|
14110
|
+
print("[planReportRecreate] could not read the report form's plugins: "
|
|
14111
|
+
f"{(_prr_plugin_result or {}).get('errorCode') or 'failed'}",
|
|
14112
|
+
file=sys.stderr, flush=True)
|
|
14113
|
+
except Exception as exc:
|
|
14114
|
+
print(f"[planReportRecreate] could not read the report form's plugins: {exc}",
|
|
14115
|
+
file=sys.stderr, flush=True)
|
|
14116
|
+
_prr_plan = plan_report_recreate(_prr_schema, _prr_artifact, _prr_menus, _prr_plugin_rows)
|
|
13890
14117
|
if not args.no_backup:
|
|
13891
14118
|
_prr_plan["backupPath"] = write_report_recreate_backup(
|
|
13892
14119
|
args.app_root, _prr_number, _prr_schema, _prr_plan)
|
|
@@ -14038,6 +14265,14 @@ def _resolve_form_id_for_schema(cfg, token, args):
|
|
|
14038
14265
|
|
|
14039
14266
|
def main():
|
|
14040
14267
|
global _CLI_MACHINE_MODE, _CLI_RESULT_EMITTED, _CLI_DELIVERY_ARGS
|
|
14268
|
+
from _core import formatters
|
|
14269
|
+
original_print = builtins.print
|
|
14270
|
+
previous_cli = (_CLI_MACHINE_MODE, _CLI_RESULT_EMITTED, _CLI_DELIVERY_ARGS)
|
|
14271
|
+
previous_output = (formatters._stdout_mode, formatters._output_file,
|
|
14272
|
+
formatters._current_cmd, formatters._current_arg_hash)
|
|
14273
|
+
set_output_file(None)
|
|
14274
|
+
set_current_command(None)
|
|
14275
|
+
set_stdout_mode(False)
|
|
14041
14276
|
_CLI_DELIVERY_ARGS = None
|
|
14042
14277
|
sys.argv[1:] = _normalize_argv(sys.argv[1:])
|
|
14043
14278
|
_CLI_MACHINE_MODE = "--stdout" in sys.argv[1:]
|
|
@@ -14069,12 +14304,23 @@ def main():
|
|
|
14069
14304
|
_emit_machine_error("CLI_EXIT_ERROR", f"Command exited with code {code}")
|
|
14070
14305
|
return code
|
|
14071
14306
|
except Exception as exc:
|
|
14307
|
+
failure = _report_mutation_failure(exc) if isinstance(exc, ReportMutationError) else None
|
|
14308
|
+
if failure and _CLI_DELIVERY_ARGS is not None:
|
|
14309
|
+
_invalidate_unmerged_report_state(failure, _CLI_DELIVERY_ARGS.cmd,
|
|
14310
|
+
getattr(_CLI_DELIVERY_ARGS, "app_root", None), getattr(_CLI_DELIVERY_ARGS, "formNumber", None),
|
|
14311
|
+
getattr(_CLI_DELIVERY_ARGS, "dry_run", False))
|
|
14072
14312
|
if _CLI_MACHINE_MODE and not _CLI_RESULT_EMITTED:
|
|
14073
14313
|
error_code, message = _exception_error_code(exc)
|
|
14074
|
-
_emit_machine_error(error_code, message)
|
|
14314
|
+
_emit_machine_error(error_code, message, data=failure["data"] if failure else None)
|
|
14075
14315
|
else:
|
|
14076
14316
|
print(f"[ERROR] {exc}", file=sys.stderr)
|
|
14077
14317
|
return 1
|
|
14318
|
+
finally:
|
|
14319
|
+
# CLI 嵌入同一进程时,日志路由不能吞掉后续插件或卡片的 stdout。
|
|
14320
|
+
builtins.print = original_print
|
|
14321
|
+
(_CLI_MACHINE_MODE, _CLI_RESULT_EMITTED, _CLI_DELIVERY_ARGS) = previous_cli
|
|
14322
|
+
(formatters._stdout_mode, formatters._output_file,
|
|
14323
|
+
formatters._current_cmd, formatters._current_arg_hash) = previous_output
|
|
14078
14324
|
|
|
14079
14325
|
|
|
14080
14326
|
if __name__ == "__main__":
|