@shundoo-ai/dsh-cosmic 1.0.19 → 1.0.21
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/cordis.patch.yml +5 -5
- package/package.json +1 -1
- package/skills/cosmic-build/CHANGELOG.md +4 -0
- package/skills/cosmic-build/LOCAL-PATCHES.md +91 -40
- package/skills/cosmic-build/SKILL.md +46 -13
- package/skills/cosmic-build/assets/platform-report-filters/TypedReportFilterFields.java +169 -0
- package/skills/cosmic-build/assets/platform-report-filters/platform.patch +98 -0
- package/skills/cosmic-build/assets/report-algo-benchmark/ReportAlgoBenchmark.java +48 -0
- package/skills/cosmic-build/assets/report-algo-benchmark/ReportBenchmarkLogFactory.java +7 -0
- package/skills/cosmic-build/examples/java-rules/CosmicEntryQuery.java +26 -0
- package/skills/cosmic-build/examples/java-rules/CosmicReportAggregation.java +35 -0
- package/skills/cosmic-build/examples/java-rules/CosmicReportFilters.java +77 -0
- package/skills/cosmic-build/examples/java-rules/CosmicTimeAdapter.java +25 -0
- package/skills/cosmic-build/examples/java-rules/CosmicTimeAdapterCheck.java +26 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/api/algo/GroupbyDataSet.md +47 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/api/entity/report/FilterInfo.md +12 -12
- package/skills/cosmic-build/knowledge/cosmic/platform/api/entity/report/FilterItemInfo.md +2 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/form-plugin.md +2 -4
- package/skills/cosmic-build/knowledge/cosmic/platform/java-type-contracts.md +11 -2
- package/skills/cosmic-build/knowledge/cosmic/platform/list-plugin.md +18 -14
- package/skills/cosmic-build/knowledge/cosmic/platform/operation-plugin.md +4 -4
- package/skills/cosmic-build/knowledge/cosmic/platform/reportlistdata-plugin.md +17 -9
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/operation/cross-entity-aggregate-writeback.md +2 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/operation/pre-post-operation.md +15 -7
- package/skills/cosmic-build/knowledge/cosmic/platform/sdk/sdk-algo.md +24 -68
- package/skills/cosmic-build/knowledge/cosmic/platform/workflow-plugin.md +2 -7
- package/skills/cosmic-build/references/application-context.md +35 -1
- package/skills/cosmic-build/references/common-reference.md +1 -1
- package/skills/cosmic-build/references/compile-guide.md +55 -68
- package/skills/cosmic-build/references/delivery.md +59 -7
- package/skills/cosmic-build/references/execution-contract.md +38 -0
- package/skills/cosmic-build/references/form-discovery.md +7 -1
- package/skills/cosmic-build/references/java-plugin-delivery.md +32 -162
- package/skills/cosmic-build/references/operation-dispatch.md +17 -0
- package/skills/cosmic-build/references/plugin-handoff-input.md +131 -0
- package/skills/cosmic-build/references/plugin-runtime-routing.md +1 -1
- package/skills/cosmic-build/references/report-filter-contract.md +78 -0
- package/skills/cosmic-build/references/sdk-inspection.md +23 -0
- package/skills/cosmic-build/schemas/data-model-authoring.schema.json +2 -3
- package/skills/cosmic-build/scripts/_http_client.py +55 -55
- package/skills/cosmic-build/scripts/appconfig_load.py +2 -2
- package/skills/cosmic-build/scripts/apply_report_filter_extension.py +39 -0
- package/skills/cosmic-build/scripts/bootstrap_cosmic_context.py +37 -2
- package/skills/cosmic-build/scripts/compile_plugin_source.py +279 -156
- package/skills/cosmic-build/scripts/execution_binding.py +40 -0
- package/skills/cosmic-build/scripts/inspect_platform_sdk.py +169 -0
- package/skills/cosmic-build/scripts/kd_api.py +23 -22
- package/skills/cosmic-build/scripts/kd_auth.py +1 -1
- package/skills/cosmic-build/scripts/kd_env_loader.py +19 -10
- package/skills/cosmic-build/scripts/kd_token_cache.py +2 -2
- package/skills/cosmic-build/scripts/kingscript_sdk_sync.py +350 -0
- package/skills/cosmic-build/scripts/kingscript_source_gate.py +11 -8
- package/skills/cosmic-build/scripts/platform_api_contract.py +246 -11
- package/skills/cosmic-build/scripts/plugin_corpus/build_index.py +403 -0
- package/skills/cosmic-build/scripts/plugin_corpus/jvm_classfile.py +281 -0
- package/skills/cosmic-build/scripts/plugin_corpus/measure_api_usage.py +446 -0
- package/skills/cosmic-build/scripts/plugin_source_gate.py +48 -7
- package/skills/cosmic-build/scripts/plugin_target_sdk.py +45 -0
- package/skills/cosmic-build/scripts/prepare_plugin_handoff.py +493 -47
- package/skills/cosmic-build/scripts/preview_url.py +35 -6
- package/skills/cosmic-build/scripts/query_plugin_handoff.py +250 -0
- package/skills/cosmic-build/scripts/register_plugins.py +28 -2
- package/skills/cosmic-build/scripts/render_output_cards.py +42 -9
- package/skills/cosmic-build/scripts/report_algo_benchmark.py +46 -0
- package/skills/cosmic-build/scripts/run.py +2 -2
- package/skills/cosmic-build/scripts/sync_generated_locale_assets.py +43 -0
- package/skills/cosmic-build/scripts/test/fixtures/ReportSdkCheck.java +64 -0
- package/skills/cosmic-build/scripts/test/fixtures/java_context_booking_native.json +541 -0
- package/skills/cosmic-build/scripts/test/test_add_rule_business_contract.py +85 -14
- package/skills/cosmic-build/scripts/test/test_batch5_drift_governance.py +12 -3
- package/skills/cosmic-build/scripts/test/test_build_meta_order.py +0 -16
- package/skills/cosmic-build/scripts/test/test_cli_continuation.py +87 -0
- package/skills/cosmic-build/scripts/test/test_compile_plugin_source.py +224 -3
- package/skills/cosmic-build/scripts/test/test_control_authoring.py +123 -4
- package/skills/cosmic-build/scripts/test/test_cosmic_sdk_examples.py +141 -0
- package/skills/cosmic-build/scripts/test/test_data_model_contract.py +30 -5
- package/skills/cosmic-build/scripts/test/test_delivery_stage_boundary.py +2 -10
- package/skills/cosmic-build/scripts/test/test_dym_sync_background.py +11 -0
- package/skills/cosmic-build/scripts/test/test_dynamic_form_metadata_only_contract.py +59 -1
- package/skills/cosmic-build/scripts/test/test_guide_skeleton_contract.py +87 -43
- package/skills/cosmic-build/scripts/test/test_inspect_platform_sdk.py +71 -0
- package/skills/cosmic-build/scripts/test/test_kd_api.py +67 -19
- package/skills/cosmic-build/scripts/test/test_kingscript_sdk_sync.py +221 -0
- package/skills/cosmic-build/scripts/test/test_kingscript_source_gate.py +10 -0
- package/skills/cosmic-build/scripts/test/test_list_configuration_closure.py +18 -0
- package/skills/cosmic-build/scripts/test/test_long_session_regressions.py +116 -0
- package/skills/cosmic-build/scripts/test/test_mcp_cli.py +524 -0
- package/skills/cosmic-build/scripts/test/test_modeling_input_recovery.py +141 -0
- package/skills/cosmic-build/scripts/test/test_open_world_cli_catalog.py +36 -2
- package/skills/cosmic-build/scripts/test/test_platform_api_contract.py +161 -1
- package/skills/cosmic-build/scripts/test/test_plugin_business_contract.py +91 -0
- package/skills/cosmic-build/scripts/test/test_plugin_corpus.py +195 -0
- package/skills/cosmic-build/scripts/test/test_plugin_handoff.py +346 -1
- package/skills/cosmic-build/scripts/test/test_plugin_target_sdk.py +70 -0
- package/skills/cosmic-build/scripts/test/test_preview_url.py +44 -1
- package/skills/cosmic-build/scripts/test/test_property_batch.py +22 -0
- package/skills/cosmic-build/scripts/test/test_property_input_discovery.py +13 -11
- package/skills/cosmic-build/scripts/test/test_query_plugin_handoff.py +160 -0
- package/skills/cosmic-build/scripts/test/test_register_plugins.py +31 -1
- package/skills/cosmic-build/scripts/test/test_render_output_cards.py +50 -4
- package/skills/cosmic-build/scripts/test/test_report_business_contract.py +27 -0
- package/skills/cosmic-build/scripts/test/test_report_doc_contract_sync.py +5 -4
- package/skills/cosmic-build/scripts/test/test_report_sdk_optimization.py +36 -0
- package/skills/cosmic-build/scripts/test/test_rule_batch_evidence.py +1 -1
- package/skills/cosmic-build/scripts/test/test_rule_domain_contract.py +20 -0
- package/skills/cosmic-build/scripts/test/test_rule_function_formula.py +16 -6
- package/skills/cosmic-build/scripts/test/test_skill_entry_contract.py +1 -0
- package/skills/cosmic-build/scripts/test/test_test_environment.py +45 -0
- package/skills/cosmic-build/scripts/test/test_verify_plugin_loading.py +79 -0
- package/skills/cosmic-build/scripts/test_environment.py +49 -0
- package/skills/cosmic-build/scripts/verify_plugin_loading.py +71 -0
- package/skills/cosmic-build/skills/cosmic-coding-impl/SKILL.md +86 -162
- package/skills/cosmic-build/skills/cosmic-coding-script/ATTRIBUTION.md +1 -1
- package/skills/cosmic-build/skills/cosmic-coding-script/SKILL.md +45 -14
- package/skills/cosmic-build/skills/cosmic-coding-script/references/kwc-controller-authoring.md +6 -0
- package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/README.md +29 -19
- package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/docs//350/204/232/346/234/254SDK.md +3 -4
- package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/indexes/package-index.md +1 -1
- package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/strategy.md +27 -18
- package/skills/cosmic-build/skills/cosmic-meta-api/SKILL.md +11 -17
- package/skills/cosmic-build/skills/cosmic-meta-api/apis/ai_meta.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/apis/app_menu.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/apis/meta_log.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/control-authoring.json +45 -4
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/form-control-traits.json +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/layout-ui.json +18 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/menu-publish.json +8 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/property-batch.json +7 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/property-input-index.json +3 -3
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/report-write-contracts.json +1 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/rule-domain.json +37 -5
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/rule-event-contract.json +24 -3
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/run-build-meta.json +61 -12
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/dropdown-menu.schema.json +69 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/report-write.schema.json +2 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/rule-set.schema.json +1 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/rule-write.schema.json +14 -7
- package/skills/cosmic-build/skills/cosmic-meta-api/docs/api-summary.md +2 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/app-action/SKILL.md +6 -3
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/develop/SKILL.md +1 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/export/SKILL.md +5 -6
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/init/SKILL.md +13 -36
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/pdm/SKILL.md +8 -9
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/pdm/scripts/config.json.example +5 -15
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/reset/SKILL.md +6 -6
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/usage/SKILL.md +20 -148
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/verify/SKILL.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/build_receipts.py +171 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_apps.py +25 -6
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_controls.py +55 -21
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_fields.py +10 -3
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_formactions.py +63 -6
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_forms.py +59 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_listui.py +8 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_metaops.py +36 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_plugins.py +115 -90
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_properties.py +666 -4
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_rules.py +1415 -87
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/commands.py +6 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/config.py +28 -15
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/execution_errors.py +40 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/formatters.py +32 -5
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/property_policy_contract.py +6 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/report_ops.py +113 -17
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/reset.py +3 -3
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/rule_contract.py +107 -26
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/build_meta_order.py +50 -49
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/cosmic_api.py +856 -150
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/field_decorator.py +47 -14
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_build_receipt_resume.py +374 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_cli_failure_contract.py +24 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_creation_identity_boundary.py +4 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_dropdown_menu_contract.py +382 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_existing_form_ui.py +0 -25
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_field_decorator.py +50 -6
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_functional_group_resolution.py +83 -16
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_identity_template_resolution.py +103 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_plugin_contract.py +28 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_readback_derivation.py +22 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_typed_filters.py +65 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_rule_write_closure.py +1041 -15
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_run_batch_post_build_recovery.py +65 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_run_batch_verification_evidence.py +17 -0
- package/skills/cosmic-build/skills/cosmic-meta-knowledge/generation/api-param-checklist.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-knowledge/generation/rule-modeling-guide.md +7 -4
- package/skills/cosmic-build/skills/cosmic-meta-modeling/SKILL.md +61 -13
- package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/app-menu/SKILL.md +8 -0
- package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/formtemplate/SKILL.md +5 -0
- package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/formtemplate/dynamic-form-artifact-schema.md +5 -0
- package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/report/SKILL.md +21 -9
- package/skills/cosmic-build/skills/cosmic-meta-modeling/references/authoring-entity-graphs.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-modeling/references/authoring-storage-constraints.md +5 -3
- package/skills/cosmic-build/skills/cosmic-meta-modeling/references/authoring-ui-composition.md +6 -3
- package/skills/cosmic-build/skills/cosmic-meta-modeling/references/creation-recovery.md +13 -0
- package/skills/cosmic-build/skills/cosmic-meta-modeling/references/parse-core.md +3 -0
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/data_model_contract.py +6 -1
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/data_model_emit.py +135 -87
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/field_type_registry.py +11 -1
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/isv_resolver.py +1 -3
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/report_validator.py +29 -0
- package/skills/cosmic-build/skills/cosmic-meta-modifier/SKILL.md +4 -2
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/context/SKILL.md +2 -2
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/execute/SKILL.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/operation/SKILL.md +5 -4
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/operation/operation-write.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 +20 -5
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/property/complex-apis.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/property/policy-grammar.md +4 -1
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/report-op/SKILL.md +9 -0
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/SKILL.md +61 -4
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/raw-rule-authoring.md +3 -1
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/rule-actions.md +2 -2
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/rule-reference.md +6 -6
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/state.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/unit/SKILL.md +6 -3
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/verify/usage-guide.md +4 -4
- package/skills/cosmic-build/skills/cosmic-meta-modifier/references/list-filter-modification.md +4 -1
- package/skills/cosmic-build/skills/cosmic-meta-ui/SKILL.md +9 -1
- package/skills/cosmic-build/skills/cosmic-meta-ui/modules/button/SKILL.md +3 -0
- package/skills/cosmic-build/skills/mcp-server/SKILL.md +210 -0
- package/skills/cosmic-build/skills/mcp-server/scripts/mcp_cli.py +431 -0
- package/skills/cosmic-build/skills/openapi-gen/SKILL.md +3 -3
- package/skills/cosmic-build/skills/openapi-gen/scripts/api/gen_runner.py +2 -2
- package/skills/cosmic-dev-best-practices/references/bill-dev-convention.md +19 -9
- package/skills/cosmic-dev-best-practices/references/cosmic-meta-api.md +14 -11
- package/skills/cosmic-dev-best-practices/references/design-examples/basedata-design-example.md +1 -1
- package/skills/cosmic-dev-best-practices/references/design-examples/bill-design-example.md +1 -1
- package/skills/cosmic-dev-best-practices/references/elements/AssistantField.md +1 -1
- package/skills/cosmic-dev-best-practices/references/elements/BasedataField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/BasedataPropField.md +3 -3
- package/skills/cosmic-dev-best-practices/references/elements/CreaterField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/CurrencyField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/CustomerField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/FlexField.md +1 -1
- package/skills/cosmic-dev-best-practices/references/elements/MaterielField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/OrgField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/SupplierField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/UnitField.md +1 -1
- package/skills/cosmic-dev-best-practices/references/elements/UserField.md +3 -3
- package/skills/cosmic-dev-best-practices/references/elements/common-field-property-conventions.md +16 -11
- package/skills/cosmic-dev-best-practices/references/layout-control-convention.md +5 -4
- package/skills/erp-analysis/references/delivery-contract.md +4 -2
- package/skills/erp-analysis/templates/AGENTS.template.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/.dsh/cosmic/.kd/config.json +0 -21
|
@@ -441,12 +441,16 @@ from .cmd_rules import ( # noqa: F401
|
|
|
441
441
|
do_ensure_conditional_entry_style,
|
|
442
442
|
do_ensure_conditional_control_state,
|
|
443
443
|
do_ensure_conditional_clear_fields,
|
|
444
|
+
do_ensure_conditional_field_change,
|
|
444
445
|
do_ensure_conditional_copy_field_value,
|
|
446
|
+
do_ensure_copy_field_mappings,
|
|
445
447
|
do_ensure_conditional_carry_reference_property,
|
|
448
|
+
do_ensure_carry_reference_mappings,
|
|
446
449
|
do_ensure_conditional_calculation,
|
|
447
450
|
do_ensure_quantity_conversion,
|
|
448
451
|
do_ensure_conditional_field_state,
|
|
449
452
|
do_ensure_field_calculation,
|
|
453
|
+
do_ensure_time_difference_calculation,
|
|
450
454
|
do_ensure_rule_function_formula,
|
|
451
455
|
do_ensure_rule_set,
|
|
452
456
|
do_update_rule,
|
|
@@ -502,7 +506,7 @@ from .cmd_properties import ( # noqa: F401
|
|
|
502
506
|
do_set_display_prop,
|
|
503
507
|
do_set_permission_control,
|
|
504
508
|
do_set_business_control,
|
|
505
|
-
do_set_complex_property, do_set_custom_style, do_set_collapse_summary,
|
|
509
|
+
do_set_complex_property, do_configure_dropdown_menu, do_set_custom_style, do_set_collapse_summary,
|
|
506
510
|
do_set_edit_search_prop,
|
|
507
511
|
do_set_ref_layout,
|
|
508
512
|
do_set_summary_to_field_resolved,
|
|
@@ -559,6 +563,7 @@ from .cmd_tabpage import ( # noqa: F401
|
|
|
559
563
|
|
|
560
564
|
from .cmd_controls import ( # noqa: F401
|
|
561
565
|
control_catalog,
|
|
566
|
+
control_input_schema,
|
|
562
567
|
validate_control_batch_input,
|
|
563
568
|
do_add_controls,
|
|
564
569
|
)
|
|
@@ -30,6 +30,7 @@ if str(_ROOT_SCRIPTS_P) not in sys.path:
|
|
|
30
30
|
|
|
31
31
|
from project_paths import (
|
|
32
32
|
ensure_app_runtime_ignore,
|
|
33
|
+
get_app_identity,
|
|
33
34
|
get_cosmic_metadata_runtime_dir,
|
|
34
35
|
get_metadata_dir,
|
|
35
36
|
get_modify_dir,
|
|
@@ -163,10 +164,16 @@ def _init_paths(temp_dir=None, app_root=None):
|
|
|
163
164
|
resolved_app_root = (
|
|
164
165
|
_Path(app_root).expanduser().resolve() if app_root is not None else None
|
|
165
166
|
)
|
|
166
|
-
_BOUND_APP_ROOT = resolved_app_root
|
|
167
167
|
if resolved_app_root is not None:
|
|
168
168
|
if not resolved_app_root.is_dir():
|
|
169
169
|
raise ValueError(f"app root does not exist: {resolved_app_root}")
|
|
170
|
+
if not get_app_identity(resolved_app_root):
|
|
171
|
+
raise ValueError(
|
|
172
|
+
"APP_ROOT_IDENTITY_INVALID: appRoot must be the bound Cosmic application directory, "
|
|
173
|
+
"not the project root or app container"
|
|
174
|
+
)
|
|
175
|
+
_BOUND_APP_ROOT = resolved_app_root
|
|
176
|
+
if resolved_app_root is not None:
|
|
170
177
|
ensure_app_runtime_ignore(resolved_app_root)
|
|
171
178
|
temp_dir = str(
|
|
172
179
|
resolved_app_root / "_runtime" / "cosmic-metadata"
|
|
@@ -211,8 +218,10 @@ def _init_paths(temp_dir=None, app_root=None):
|
|
|
211
218
|
# Ensure directories exist
|
|
212
219
|
os.makedirs(temp_dir, exist_ok=True)
|
|
213
220
|
os.makedirs(os.path.join(temp_dir, "ops"), exist_ok=True) # transient ops files
|
|
214
|
-
|
|
215
|
-
|
|
221
|
+
# Global discovery/auth may need session state, but has no application artifacts.
|
|
222
|
+
if resolved_app_root is not None or _read_context_json().get("appRoot"):
|
|
223
|
+
os.makedirs(ARTIFACTS_DIR, exist_ok=True)
|
|
224
|
+
os.makedirs(BATCH_MANIFESTS_DIR, exist_ok=True)
|
|
216
225
|
|
|
217
226
|
# Proactively create workspace.json (write business cloud fixed defaults), ensuring the file always exists
|
|
218
227
|
# isv / standard are not written here; they are dynamically obtained by bootstrapWorkspace → getDevInfo
|
|
@@ -361,7 +370,8 @@ _API_PATH = {
|
|
|
361
370
|
"metalogQuery": "/kapi/v2/devportal/ai-meta/metalog/query",
|
|
362
371
|
"metalogCompare": "/kapi/v2/devportal/ai-meta/metalog/compare",
|
|
363
372
|
"metalogRestore": "/kapi/v2/devportal/ai-meta/metalog/restore",
|
|
364
|
-
|
|
373
|
+
|
|
374
|
+
# ─── 本地补丁(LOCAL-PATCHES #13 / #14):上游 0.0.326 仍无这些端点 ───
|
|
365
375
|
"ksqlListDbRoutes": "/kapi/v2/devportal/ai-meta/ksql/listDbRoutes",
|
|
366
376
|
"ksqlListDbTypes": "/kapi/v2/devportal/ai-meta/ksql/listDbTypes",
|
|
367
377
|
"ksqlListTables": "/kapi/v2/devportal/ai-meta/ksql/listTables",
|
|
@@ -369,11 +379,9 @@ _API_PATH = {
|
|
|
369
379
|
"ksqlTranslate": "/kapi/v2/devportal/ai-meta/ksql/translate",
|
|
370
380
|
"exportKSQLByTable": "/kapi/v2/devportal/ai-meta/ksql/exportByTable",
|
|
371
381
|
"exportKSQLByObject": "/kapi/v2/devportal/ai-meta/ksql/exportByObject",
|
|
372
|
-
# 运行时元数据查询(数据分析 / entity-download 依赖)
|
|
373
382
|
"getEntityOperate": "/kapi/v2/devportal/ai-meta/getEntityOperate",
|
|
374
383
|
"getIsv": "/kapi/v2/devportal/ai-meta/getIsv",
|
|
375
384
|
"getControl": "/kapi/v2/devportal/ai-meta/getControl",
|
|
376
|
-
# 自定义数据查询 API(数据分析核心)
|
|
377
385
|
"dataQuery": "/kapi/v2/open/openapi/data/query",
|
|
378
386
|
"dataQueryWithPagination": "/kapi/v2/open/openapi/data/queryWithPagination",
|
|
379
387
|
"getApiByUrl": "/kapi/v2/open/openapi_apilist/queryByUrl",
|
|
@@ -496,15 +504,16 @@ def config_is_initialized():
|
|
|
496
504
|
_md._md_has_section(cfg_path, "Business Cloud / App Info"))
|
|
497
505
|
|
|
498
506
|
|
|
499
|
-
# ─── dataQuery
|
|
507
|
+
# ─── 本地补丁(LOCAL-PATCHES #15):dataQuery 参数 hex 编码 ─────────────────────
|
|
508
|
+
# 服务端 DataServiceController.decodeHex 解码还原;用于绕过网关 SQL 注入检测。
|
|
500
509
|
|
|
501
510
|
_HEX_ENCODE_FIELDS = ("filters", "selectFields", "orderBys")
|
|
502
511
|
|
|
503
512
|
|
|
504
513
|
def _encode_api_params(payload):
|
|
505
|
-
"""dataQuery / dataQueryWithPagination
|
|
506
|
-
三个字符串参数 hex 编码(网关 SQL
|
|
507
|
-
|
|
514
|
+
"""dataQuery / dataQueryWithPagination 发送前把 filters / selectFields / orderBys
|
|
515
|
+
三个字符串参数 hex 编码(网关 SQL 检测绕过;服务端解码,agent 无感)。
|
|
516
|
+
其余参数(entityId/top/pageSize 等)原样。
|
|
508
517
|
"""
|
|
509
518
|
if not isinstance(payload, dict):
|
|
510
519
|
return payload
|
|
@@ -523,25 +532,29 @@ def _api_call(cfg, token, command, payload, method="GET"):
|
|
|
523
532
|
(kd_api internally manages token retrieval/encrypted caching/401 forced refresh). Endpoint
|
|
524
533
|
routing is still provided by this module's ``_api_url`` / ``_API_PATH``.
|
|
525
534
|
|
|
526
|
-
|
|
527
|
-
|
|
535
|
+
本地补丁(LOCAL-PATCHES #13 / #15):
|
|
536
|
+
- ``callApiByUrl``:payload['url'] 为相对路径(如 /v2/xxx/query),动态拼 base_url 调用;
|
|
537
|
+
- dataQuery / dataQueryWithPagination 发送前自动 hex 编码。
|
|
528
538
|
"""
|
|
529
539
|
import kd_api
|
|
530
540
|
|
|
531
|
-
# dataQuery 参数自动 hex
|
|
541
|
+
# dataQuery 参数自动 hex 编码(本地补丁 #15)
|
|
532
542
|
if command in ("dataQuery", "dataQueryWithPagination"):
|
|
533
543
|
_encode_api_params(payload)
|
|
534
544
|
|
|
535
|
-
|
|
545
|
+
# 按 URL 直调(本地补丁 #13):拆 base(token 缓存 key 用根 URL)与 path,
|
|
546
|
+
# 避免 get_token 用错 base 而重新登录。
|
|
536
547
|
if command == "callApiByUrl":
|
|
548
|
+
base_url = (cfg.get("base_url") or cfg.get("baseUrl", "")).rstrip("/")
|
|
537
549
|
rel_url = payload.get("url", "")
|
|
538
550
|
rest = {k: v for k, v in payload.items() if k != "url"}
|
|
539
551
|
if not rel_url.startswith("/kapi/"):
|
|
540
552
|
rel_url = "/kapi" + rel_url
|
|
541
|
-
# 拆 base(token 缓存 key 用根 URL)+ path(相对路径),避免 get_token 用错 base 重新登录
|
|
542
553
|
if method == "GET":
|
|
543
554
|
return kd_api.get(base_url, rel_url, cfg, params=rest)
|
|
544
555
|
return kd_api.post(base_url, rel_url, cfg, rest)
|
|
556
|
+
|
|
557
|
+
base_url = (cfg.get("base_url") or cfg.get("baseUrl", "")).rstrip("/")
|
|
545
558
|
_api_url(cfg, command) # Validate endpoint is registered (raise ValueError if unknown)
|
|
546
559
|
api_path = _API_PATH[command]
|
|
547
560
|
if method == "GET":
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Evidence-based error categories shared by machine results and batch receipts."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def classify_execution_error(result):
|
|
5
|
+
code = str(result.get("errorCode") or "")
|
|
6
|
+
data = result.get("data") if isinstance(result.get("data"), dict) else {}
|
|
7
|
+
attempted = result.get("writeAttempted", data.get("writeAttempted"))
|
|
8
|
+
if code == "RULE_SET_ITEM_FAILED" and data.get("results"):
|
|
9
|
+
return classify_execution_error(data["results"][-1]["result"])
|
|
10
|
+
if code == "RULE_SET_ITEM_EXCEPTION":
|
|
11
|
+
return "unknown_write"
|
|
12
|
+
if attempted is not False and (result.get("outcome") == "unknown_after_write"
|
|
13
|
+
or result.get("phase") == "writeUnknown"):
|
|
14
|
+
return "unknown_write"
|
|
15
|
+
if code == "FULL_METADATA_API_UNAVAILABLE":
|
|
16
|
+
return "capability_limit"
|
|
17
|
+
if code.endswith("LOOKUP_UNCONFIRMED"):
|
|
18
|
+
return "environment"
|
|
19
|
+
if code.startswith("BATCH_WRITE_"):
|
|
20
|
+
return "unknown_write"
|
|
21
|
+
if code == "COMMAND_UNAVAILABLE":
|
|
22
|
+
return "input"
|
|
23
|
+
if code == "CONDITIONAL_CARRY_SOURCE_PROPERTY_UNAVAILABLE":
|
|
24
|
+
return "identity_resolution"
|
|
25
|
+
if code.endswith(("_UNRESOLVED", "_AMBIGUOUS", "_NOT_FOUND")) or code.startswith(("REF_", "BD-REFERENCE", "TARGET_", "FORM_", "CREATED_IDENTITY", "CALLER_CONTEXT")):
|
|
26
|
+
return "identity_resolution"
|
|
27
|
+
if code.startswith(("SKILL_", "AUTH", "TOKEN", "HTTP", "NETWORK", "ENV", "CLI_EXIT")):
|
|
28
|
+
return "environment"
|
|
29
|
+
if code.startswith(("CLI_ARGUMENT", "INLINE_JSON", "RULE_SET_ARGS", "RULE_SET_INPUT", "BATCH_INPUT", "ARTIFACT_", "RULE_INPUT_", "RULE_FUNCTION_ARGUMENT", "RULE_SET_COMMAND")):
|
|
30
|
+
return "input"
|
|
31
|
+
return "business_validation" if attempted is False else "unknown"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def attach_execution_error(result):
|
|
35
|
+
if not isinstance(result, dict) or result.get("status") is not False:
|
|
36
|
+
return result
|
|
37
|
+
result = dict(result)
|
|
38
|
+
result["errorCategory"] = classify_execution_error(result)
|
|
39
|
+
result["capabilityLimitConfirmed"] = result["errorCategory"] == "capability_limit"
|
|
40
|
+
return result
|
|
@@ -11,6 +11,7 @@ import hashlib
|
|
|
11
11
|
import json
|
|
12
12
|
import os
|
|
13
13
|
import sys
|
|
14
|
+
import time
|
|
14
15
|
|
|
15
16
|
from .cache import _iter_biz_tree
|
|
16
17
|
|
|
@@ -639,6 +640,18 @@ def _last_result_legacy_path():
|
|
|
639
640
|
return os.path.join(output_dir, "last_result.json")
|
|
640
641
|
|
|
641
642
|
|
|
643
|
+
def save_run_batch_result(result, app_root, artifact_paths):
|
|
644
|
+
"""Save the original batch receipt for downstream verified Java preparation."""
|
|
645
|
+
root = os.path.abspath(app_root)
|
|
646
|
+
destination = os.path.join(root, "_runtime", "output", f"runBatch.{time.time_ns()}.json")
|
|
647
|
+
receipt = {**result, "appRoot": root, "artifactPaths": [os.path.abspath(p) for p in artifact_paths],
|
|
648
|
+
"resultPath": destination}
|
|
649
|
+
os.makedirs(os.path.dirname(destination), exist_ok=True)
|
|
650
|
+
with open(destination, "w", encoding="utf-8") as handle:
|
|
651
|
+
json.dump(receipt, handle, ensure_ascii=False, indent=2)
|
|
652
|
+
return receipt
|
|
653
|
+
|
|
654
|
+
|
|
642
655
|
def pjson(obj, force_stdout=False):
|
|
643
656
|
"""Output JSON result.
|
|
644
657
|
|
|
@@ -679,11 +692,25 @@ def pjson(obj, force_stdout=False):
|
|
|
679
692
|
f.write(text)
|
|
680
693
|
except OSError:
|
|
681
694
|
pass
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
flush=True
|
|
686
|
-
|
|
695
|
+
if _stdout_mode or force_stdout:
|
|
696
|
+
print(text, file=sys.stdout, flush=True)
|
|
697
|
+
else:
|
|
698
|
+
print(f"[output] Result written to: {target_file}", file=sys.stdout, flush=True)
|
|
699
|
+
if isinstance(obj, dict) and (obj.get("delivery") or obj.get("results")):
|
|
700
|
+
# Keep the complete receipt on disk, while exposing the facts
|
|
701
|
+
# needed to continue. Never infer verification from exit status.
|
|
702
|
+
summary = {key: obj[key] for key in (
|
|
703
|
+
"status", "errorCode", "errorCategory", "message", "total", "completed", "success", "failed",
|
|
704
|
+
"forms", "delivery", "executionFinished", "writeAttempted", "metadataRetained",
|
|
705
|
+
"doNotRetryBuildMeta", "resume", "reconcile", "reconciliation",
|
|
706
|
+
) if key in obj}
|
|
707
|
+
summary["resultPath"] = os.path.abspath(target_file)
|
|
708
|
+
if isinstance(obj.get("results"), list):
|
|
709
|
+
summary["results"] = [{**{key: row[key] for key in ("artifactPath", "ok", "phase", "error") if key in row},
|
|
710
|
+
**({"verification": {key: row["verification"][key] for key in ("performed", "status", "verified")
|
|
711
|
+
if key in row["verification"]}} if isinstance(row.get("verification"), dict) else {})}
|
|
712
|
+
for row in obj["results"] if isinstance(row, dict)]
|
|
713
|
+
print("RESULT_SUMMARY=" + json.dumps(summary, ensure_ascii=False, separators=(",", ":")), file=sys.stdout, flush=True)
|
|
687
714
|
else:
|
|
688
715
|
print(text, file=sys.stdout, flush=True)
|
|
689
716
|
|
|
@@ -235,7 +235,7 @@ def normalize_report_filters_input(value):
|
|
|
235
235
|
if not isinstance(value, list) or not value:
|
|
236
236
|
_input_error("filters must be a non-empty array")
|
|
237
237
|
allowed = {
|
|
238
|
-
"fieldPath", "displayName", "compare", "defaultValue", "mustInput", "visible",
|
|
238
|
+
"fieldPath", "displayName", "compare", "defaultValue", "mustInput", "visible", "source",
|
|
239
239
|
}
|
|
240
240
|
result = []
|
|
241
241
|
seen = set()
|
|
@@ -250,6 +250,10 @@ def normalize_report_filters_input(value):
|
|
|
250
250
|
if item["compare"] not in {"=", "in", "between"}:
|
|
251
251
|
_input_error(
|
|
252
252
|
f"filters[{index}].compare is not in the verified set (=, in, between)")
|
|
253
|
+
if "source" in item:
|
|
254
|
+
source = _object(item["source"], f"filters[{index}].source", {"formNumber", "fieldKey"})
|
|
255
|
+
item["source"] = {key: _text(source.get(key), f"filters[{index}].source.{key}", identifier=True)
|
|
256
|
+
for key in ("formNumber", "fieldKey")}
|
|
253
257
|
for key in ("mustInput", "visible"):
|
|
254
258
|
if key in item:
|
|
255
259
|
item[key] = _boolean(item[key], f"filters[{index}].{key}")
|
|
@@ -617,28 +621,57 @@ def set_report_filters(cfg, token, form_id, filters, dry_run=False, form_number=
|
|
|
617
621
|
file=sys.stderr, flush=True,
|
|
618
622
|
)
|
|
619
623
|
|
|
620
|
-
#
|
|
621
|
-
# platform
|
|
622
|
-
# range renders as a plain filter box. Say it once per write, and let the plugin contract
|
|
623
|
-
# carry each comparison as something query() has to apply itself.
|
|
624
|
+
# Comparison semantics remain a query requirement; editor shape depends on the
|
|
625
|
+
# deployed platform version and must be observed instead of assumed to be plain text.
|
|
624
626
|
print(
|
|
625
|
-
"[setReportFilters]
|
|
627
|
+
"[setReportFilters] query comparisons: "
|
|
626
628
|
+ ", ".join(
|
|
627
629
|
f"{f.get('fieldPath', '')}={f.get('compare', '')}" for f in filters
|
|
628
630
|
)
|
|
629
|
-
+ ".
|
|
630
|
-
"
|
|
631
|
+
+ ". Verify actual filter editor types from report read-back; compare is not an "
|
|
632
|
+
"arbitrary control-type selector. Apply the requested query conditions in query().",
|
|
631
633
|
file=sys.stderr, flush=True,
|
|
632
634
|
)
|
|
633
635
|
|
|
634
636
|
form_number = _ensure_form_number(cfg, token, form_id, form_number)
|
|
637
|
+
if any(f.get("source") for f in filters):
|
|
638
|
+
report_filter_source_expectations(cfg, token, filters)
|
|
635
639
|
_assert_report_entity_writable(
|
|
636
640
|
cfg, token, form_id, form_number, requested_filter_keys=filter_ids)
|
|
637
|
-
|
|
641
|
+
# A separate route makes an old platform reject before mutation instead of silently
|
|
642
|
+
# ignoring source and creating TextField. Never fall back after an unsupported write.
|
|
643
|
+
complex_type = "ReportFilters.typed" if any(f.get("source") for f in filters) else "ReportFilters"
|
|
644
|
+
result = _set_complex(cfg, token, form_number, complex_type, filter_payload)
|
|
638
645
|
_check_result(result, "setReportFilters", form_mutation_possible=True)
|
|
639
646
|
return filter_ids
|
|
640
647
|
|
|
641
648
|
|
|
649
|
+
def report_filter_source_expectations(cfg, token, filters):
|
|
650
|
+
"""Read only the selected source forms once; no inferred reference IDs or enum values."""
|
|
651
|
+
sources = {}
|
|
652
|
+
expected = {}
|
|
653
|
+
for item in filters:
|
|
654
|
+
source = item.get("source")
|
|
655
|
+
if not source:
|
|
656
|
+
continue
|
|
657
|
+
number = source["formNumber"]
|
|
658
|
+
if number not in sources:
|
|
659
|
+
data = (_get_schema(cfg, token, number) or {}).get("data") or {}
|
|
660
|
+
sources[number] = data.get("fieldSchemas")
|
|
661
|
+
if not isinstance(sources[number], list):
|
|
662
|
+
raise RuntimeError("REPORT_TYPED_FILTER_PLATFORM_UNSUPPORTED: source field schema unavailable; install the typed filter platform extension")
|
|
663
|
+
matches = [row for row in sources[number] if row.get("fieldPath") == source["fieldKey"]]
|
|
664
|
+
if len(matches) != 1:
|
|
665
|
+
raise ValueError("REPORT_FILTER_SOURCE_FIELD_AMBIGUOUS_OR_MISSING: " + source["fieldKey"])
|
|
666
|
+
wanted = {key: value for key, value in matches[0].items() if key not in {"fieldPath", "displayName", "mustInput"}}
|
|
667
|
+
if item["compare"] == "between" and wanted.get("fieldType") != "DateRangeField":
|
|
668
|
+
if wanted.get("fieldType") not in {"DateField", "DateTimeField"}:
|
|
669
|
+
raise ValueError("REPORT_FILTER_RANGE_TYPE_UNSUPPORTED: " + str(wanted.get("fieldType")))
|
|
670
|
+
wanted["fieldType"] = "DateRangeField"
|
|
671
|
+
expected[item["fieldPath"]] = wanted
|
|
672
|
+
return expected
|
|
673
|
+
|
|
674
|
+
|
|
642
675
|
def set_report_sorts(cfg, token, form_id, sorts, dry_run=False, form_number=None):
|
|
643
676
|
"""Set report sort configuration.
|
|
644
677
|
|
|
@@ -923,9 +956,20 @@ def get_report_schema(cfg, token, form_id):
|
|
|
923
956
|
"unverifiableSections": [],
|
|
924
957
|
}
|
|
925
958
|
|
|
959
|
+
typed = data.get("reportFilterSchema")
|
|
960
|
+
if isinstance(typed, dict) and typed.get("schemaVersion") == "app-build-typed-report-filters/v1":
|
|
961
|
+
report_schema["reportFilters"] = typed.get("reportFilters") or []
|
|
962
|
+
report_schema["typedFiltersReadBack"] = True
|
|
963
|
+
|
|
926
964
|
if report_schema["readBackAvailable"]:
|
|
927
965
|
return report_schema
|
|
928
966
|
|
|
967
|
+
if report_schema.get("typedFiltersReadBack"):
|
|
968
|
+
report_schema["readBackAvailable"] = True
|
|
969
|
+
report_schema["readBackSource"] = "typedFilters"
|
|
970
|
+
report_schema["unverifiableSections"] = ["reportColumns", "reportSorts", "reportPlugins"]
|
|
971
|
+
report_schema["undecidableFilterProperties"] = ["compare", "visible", "defaultValue"]
|
|
972
|
+
|
|
929
973
|
# Derived read-back. The tested deployment exposes no data.reportSchema, but
|
|
930
974
|
# data.formLayout is the same ControlAp tree that setReportColumns / setReportFilters
|
|
931
975
|
# write, so the requested structure is provable from it. Returning empty arrays here used
|
|
@@ -935,7 +979,9 @@ def get_report_schema(cfg, token, form_id):
|
|
|
935
979
|
if isinstance(layout, dict):
|
|
936
980
|
report_schema["_raw_formLayout"] = layout
|
|
937
981
|
report_schema["reportColumns"] = _columns_from_layout(layout)
|
|
938
|
-
report_schema["reportFilters"] = _filters_from_layout(layout)
|
|
982
|
+
report_schema["reportFilters"] = _filters_from_layout(layout, data.get("schemaText") or "")
|
|
983
|
+
if report_schema.get("typedFiltersReadBack"):
|
|
984
|
+
report_schema["reportFilters"] = typed.get("reportFilters") or []
|
|
939
985
|
report_schema["readBackAvailable"] = True
|
|
940
986
|
report_schema["readBackSource"] = "formLayout"
|
|
941
987
|
# formLayout carries the control tree only. Default sort lives in the ReportListAp
|
|
@@ -954,6 +1000,8 @@ def get_report_schema(cfg, token, form_id):
|
|
|
954
1000
|
report_schema["undecidableFilterProperties"] = [
|
|
955
1001
|
"compare", "mustInput", "visible", "defaultValue",
|
|
956
1002
|
]
|
|
1003
|
+
if report_schema.get("typedFiltersReadBack"):
|
|
1004
|
+
report_schema["undecidableFilterProperties"].remove("mustInput")
|
|
957
1005
|
|
|
958
1006
|
schema_text = data.get("schemaText") or ""
|
|
959
1007
|
if schema_text:
|
|
@@ -1006,17 +1054,22 @@ def _columns_from_layout(layout):
|
|
|
1006
1054
|
]
|
|
1007
1055
|
|
|
1008
1056
|
|
|
1009
|
-
def _filters_from_layout(layout):
|
|
1057
|
+
def _filters_from_layout(layout, schema_text=""):
|
|
1010
1058
|
"""Derive report filter controls from the ReportFilterAp subtree of formLayout."""
|
|
1011
1059
|
panel = _layout_node(layout, "ReportCommFilterPanelAp")
|
|
1012
1060
|
if not isinstance(panel, dict):
|
|
1013
1061
|
return []
|
|
1062
|
+
entities = parse_schema_text(schema_text)
|
|
1063
|
+
fields = (entities[0].get("fields") or []) if entities else []
|
|
1064
|
+
field_types = {field["fieldKey"]: field["fieldType"] for field in fields if field.get("fieldType")}
|
|
1014
1065
|
result = []
|
|
1015
1066
|
for child in panel.get("children") or []:
|
|
1016
1067
|
if not isinstance(child, dict):
|
|
1017
1068
|
continue
|
|
1018
1069
|
node_type = str(child.get("type") or child.get("$type") or "")
|
|
1019
1070
|
control = next((name for name in _FILTER_CONTROL_COMPARE if name in node_type), "")
|
|
1071
|
+
if node_type.rsplit(".", 1)[-1] == "FieldAp":
|
|
1072
|
+
control = "FieldAp"
|
|
1020
1073
|
if not control:
|
|
1021
1074
|
continue
|
|
1022
1075
|
item = {
|
|
@@ -1024,6 +1077,8 @@ def _filters_from_layout(layout):
|
|
|
1024
1077
|
"displayName": child.get("name") or "",
|
|
1025
1078
|
"controlType": control,
|
|
1026
1079
|
}
|
|
1080
|
+
if item["fieldPath"] in field_types:
|
|
1081
|
+
item["fieldType"] = field_types[item["fieldPath"]]
|
|
1027
1082
|
# The layout's own `visible` is a control-phase list ("init,new,edit,...") and is not
|
|
1028
1083
|
# the filter contract's boolean `visible`. Exposing it under the same key would make a
|
|
1029
1084
|
# dropped `visible: false` look persisted, so keep the names apart.
|
|
@@ -1649,9 +1704,32 @@ def compile_report_plugin_contract(artifact, form_number=""):
|
|
|
1649
1704
|
entry["requiredBy"] = bound_by
|
|
1650
1705
|
|
|
1651
1706
|
enforcement = []
|
|
1707
|
+
value_contracts = []
|
|
1708
|
+
field_config = (artifact.get("reportProperties") or {}).get("filterFieldConfig") or []
|
|
1652
1709
|
for item in filters:
|
|
1653
1710
|
filter_key = str(item.get("fieldPath") or "")
|
|
1654
|
-
|
|
1711
|
+
binding = next((row for row in field_config if row.get("key") == filter_key), {})
|
|
1712
|
+
candidates = list(dict.fromkeys(key for key in (
|
|
1713
|
+
binding.get("fieldName"), filter_key,
|
|
1714
|
+
binding["fieldName"].split("_", 1)[0] + "_" + filter_key[4:]
|
|
1715
|
+
if filter_key.startswith("flt_") and "_" in binding.get("fieldName", "") else None,
|
|
1716
|
+
) if key))
|
|
1717
|
+
between = item.get("compare") == "between"
|
|
1718
|
+
accessor = ('ReportQueryParam.getFilter().getFilterItems()' if between
|
|
1719
|
+
else f'ReportQueryParam.getFilter().getValue("{filter_key}")')
|
|
1720
|
+
value_contracts.append({
|
|
1721
|
+
"filterKey": filter_key,
|
|
1722
|
+
"compare": item.get("compare"),
|
|
1723
|
+
"candidateValueKeys": candidates,
|
|
1724
|
+
"runtimeKeysVerified": False,
|
|
1725
|
+
"valueChannel": "getFilterItems" if between else "getValue",
|
|
1726
|
+
"rangeItemKeys": {"start": filter_key + "_startdate", "end": filter_key + "_enddate"} if between else None,
|
|
1727
|
+
"sourceBinding": item.get("source") or {key: binding[key] for key in ("dataSourceId", "fieldName") if binding.get(key)},
|
|
1728
|
+
"requiredEvidence": ["source field type and editor/reference/enum configuration",
|
|
1729
|
+
"actual runtime key mapping and comparison semantics",
|
|
1730
|
+
"query entity, field and value type",
|
|
1731
|
+
"F7 organization scope and number uniqueness when applicable"],
|
|
1732
|
+
})
|
|
1655
1733
|
# Every filter carries its comparison here. The platform stores one plain control per
|
|
1656
1734
|
# key whatever the compare is, so `between` / `in` / `=` exist only as a requirement on
|
|
1657
1735
|
# query() — without this entry they reached Java delivery as nothing at all.
|
|
@@ -1696,6 +1774,8 @@ def compile_report_plugin_contract(artifact, form_number=""):
|
|
|
1696
1774
|
"dataSetColumnTypes": column_types,
|
|
1697
1775
|
"columnPresentation": presentation,
|
|
1698
1776
|
"filterEnforcement": enforcement,
|
|
1777
|
+
"filterValueContracts": value_contracts,
|
|
1778
|
+
"permissionFilterChannel": "getQFilters",
|
|
1699
1779
|
"notes": [
|
|
1700
1780
|
"dataSetColumns are the column names query() must return, case-sensitive, and "
|
|
1701
1781
|
"dataSetColumnTypes is the Java type each one must carry. Nothing in metadata can "
|
|
@@ -1708,10 +1788,13 @@ def compile_report_plugin_contract(artifact, form_number=""):
|
|
|
1708
1788
|
"Bind columnPresentation in getColumns() using each java call plus its "
|
|
1709
1789
|
"javaFollowUp setters; do not guess ReportColumn.TYPE_* names. Recurse into "
|
|
1710
1790
|
"ReportColumnGroup.getChildren(): a grouped column is not in the top-level list.",
|
|
1711
|
-
"Enforce
|
|
1712
|
-
"
|
|
1713
|
-
"
|
|
1714
|
-
"
|
|
1791
|
+
"Enforce filterEnforcement using filterValueContracts. candidateValueKeys are "
|
|
1792
|
+
"unverified candidates, not a universal prefix rule; confirm actual keys and reject "
|
|
1793
|
+
"conflicting values. Date ranges may use separate start/end FilterItemInfo values. "
|
|
1794
|
+
"Use target-SDK accessors, not DynamicObject casts or toString date parsing. "
|
|
1795
|
+
"getQFilters carries permissions and never substitutes for extracting user values. "
|
|
1796
|
+
"F7 number filters are String comparisons on field.number, while field/id comparisons "
|
|
1797
|
+
"require Long; preserve organization and permission scope.",
|
|
1715
1798
|
],
|
|
1716
1799
|
}
|
|
1717
1800
|
return contract
|
|
@@ -1989,7 +2072,18 @@ def report_readback_verification(section, expected, schema):
|
|
|
1989
2072
|
result["unverifiableRequestedProperties"] = sorted(unverifiable_requested)
|
|
1990
2073
|
result["unverifiedProperties"] = sorted(undecidable)
|
|
1991
2074
|
else:
|
|
1992
|
-
mismatches = _subset_mismatches(_build_filters_payload(expected), observed, f"/{key}")
|
|
2075
|
+
mismatches = _subset_mismatches(_build_filters_payload([{k: v for k, v in item.items() if k != "source"} for item in expected]), observed, f"/{key}")
|
|
2076
|
+
# Structure-only receipts cannot prove source-derived editor configuration.
|
|
2077
|
+
by_key = {row.get("fieldPath"): row for row in observed or []}
|
|
2078
|
+
for index, item in enumerate(expected):
|
|
2079
|
+
if not item.get("source"):
|
|
2080
|
+
continue
|
|
2081
|
+
actual = by_key.get(item["fieldPath"], {})
|
|
2082
|
+
wanted = (schema.get("filterSourceExpectations") or {}).get(item["fieldPath"])
|
|
2083
|
+
if (not schema.get("typedFiltersReadBack") or not wanted
|
|
2084
|
+
or any(actual.get(name) != value for name, value in wanted.items())):
|
|
2085
|
+
mismatches.append({"path": f"/{key}/{index}/source", "expected": item["source"],
|
|
2086
|
+
"actual": actual.get("fieldType"), "reason": "typed-editor-source-not-proven"})
|
|
1993
2087
|
else:
|
|
1994
2088
|
mismatches = _subset_mismatches(expected, observed, f"/{key}")
|
|
1995
2089
|
|
|
@@ -2151,6 +2245,8 @@ def _build_filters_payload(filters):
|
|
|
2151
2245
|
"displayName": f.get("displayName", ""),
|
|
2152
2246
|
"compare": _map_compare_operator(f.get("compare", "=")),
|
|
2153
2247
|
}
|
|
2248
|
+
if f.get("source"):
|
|
2249
|
+
item["source"] = f["source"]
|
|
2154
2250
|
# Only forward keys the normalized contract accepts. The previous version also
|
|
2155
2251
|
# emitted required / enableFuzzy / basedataFilter, which normalize_report_filters_input
|
|
2156
2252
|
# already rejects — dead branches that could only reintroduce silent drift.
|
|
@@ -287,16 +287,16 @@ _CONTEXT_TEMPLATE = """# 当前会话上下文
|
|
|
287
287
|
_CONFIG_MD_TEMPLATE = """# 苍穹 Open API 配置说明
|
|
288
288
|
|
|
289
289
|
> **数据分工**:
|
|
290
|
-
> -
|
|
290
|
+
> - **`~/.kd/config.json`**(唯一真实来源):连接参数、密钥等**机器级**配置,代码直接读取
|
|
291
291
|
> - **本文件 `config.md`**(人类可读 + AI 可读):ISV 信息、业务云列表等**项目级**持久配置,由 API 自动写入
|
|
292
|
-
> - 两者存在重复的字段(如 `isv`),以
|
|
292
|
+
> - 两者存在重复的字段(如 `isv`),以 `~/.kd/config.json` 为准;config.md 仅作展示和 AI 快速查阅
|
|
293
293
|
|
|
294
294
|
---
|
|
295
295
|
|
|
296
296
|
## 开发商 ISV 信息
|
|
297
297
|
|
|
298
298
|
> 由 `getDevInfo` 接口自动写入,供 Skill 生成字段/实体 key 时使用。
|
|
299
|
-
>
|
|
299
|
+
> **重置环境后此处已清空**,请在 `~/.kd/config.json` 切换环境后运行 `getDevInfo` 或由建模/改单流程触发刷新。
|
|
300
300
|
|
|
301
301
|
| 字段 | 值 |
|
|
302
302
|
|------|-----|
|