@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.
Files changed (245) hide show
  1. package/cordis.patch.yml +5 -5
  2. package/package.json +1 -1
  3. package/skills/cosmic-build/CHANGELOG.md +4 -0
  4. package/skills/cosmic-build/LOCAL-PATCHES.md +91 -40
  5. package/skills/cosmic-build/SKILL.md +46 -13
  6. package/skills/cosmic-build/assets/platform-report-filters/TypedReportFilterFields.java +169 -0
  7. package/skills/cosmic-build/assets/platform-report-filters/platform.patch +98 -0
  8. package/skills/cosmic-build/assets/report-algo-benchmark/ReportAlgoBenchmark.java +48 -0
  9. package/skills/cosmic-build/assets/report-algo-benchmark/ReportBenchmarkLogFactory.java +7 -0
  10. package/skills/cosmic-build/examples/java-rules/CosmicEntryQuery.java +26 -0
  11. package/skills/cosmic-build/examples/java-rules/CosmicReportAggregation.java +35 -0
  12. package/skills/cosmic-build/examples/java-rules/CosmicReportFilters.java +77 -0
  13. package/skills/cosmic-build/examples/java-rules/CosmicTimeAdapter.java +25 -0
  14. package/skills/cosmic-build/examples/java-rules/CosmicTimeAdapterCheck.java +26 -0
  15. package/skills/cosmic-build/knowledge/cosmic/platform/api/algo/GroupbyDataSet.md +47 -0
  16. package/skills/cosmic-build/knowledge/cosmic/platform/api/entity/report/FilterInfo.md +12 -12
  17. package/skills/cosmic-build/knowledge/cosmic/platform/api/entity/report/FilterItemInfo.md +2 -0
  18. package/skills/cosmic-build/knowledge/cosmic/platform/form-plugin.md +2 -4
  19. package/skills/cosmic-build/knowledge/cosmic/platform/java-type-contracts.md +11 -2
  20. package/skills/cosmic-build/knowledge/cosmic/platform/list-plugin.md +18 -14
  21. package/skills/cosmic-build/knowledge/cosmic/platform/operation-plugin.md +4 -4
  22. package/skills/cosmic-build/knowledge/cosmic/platform/reportlistdata-plugin.md +17 -9
  23. package/skills/cosmic-build/knowledge/cosmic/platform/scenes/operation/cross-entity-aggregate-writeback.md +2 -0
  24. package/skills/cosmic-build/knowledge/cosmic/platform/scenes/operation/pre-post-operation.md +15 -7
  25. package/skills/cosmic-build/knowledge/cosmic/platform/sdk/sdk-algo.md +24 -68
  26. package/skills/cosmic-build/knowledge/cosmic/platform/workflow-plugin.md +2 -7
  27. package/skills/cosmic-build/references/application-context.md +35 -1
  28. package/skills/cosmic-build/references/common-reference.md +1 -1
  29. package/skills/cosmic-build/references/compile-guide.md +55 -68
  30. package/skills/cosmic-build/references/delivery.md +59 -7
  31. package/skills/cosmic-build/references/execution-contract.md +38 -0
  32. package/skills/cosmic-build/references/form-discovery.md +7 -1
  33. package/skills/cosmic-build/references/java-plugin-delivery.md +32 -162
  34. package/skills/cosmic-build/references/operation-dispatch.md +17 -0
  35. package/skills/cosmic-build/references/plugin-handoff-input.md +131 -0
  36. package/skills/cosmic-build/references/plugin-runtime-routing.md +1 -1
  37. package/skills/cosmic-build/references/report-filter-contract.md +78 -0
  38. package/skills/cosmic-build/references/sdk-inspection.md +23 -0
  39. package/skills/cosmic-build/schemas/data-model-authoring.schema.json +2 -3
  40. package/skills/cosmic-build/scripts/_http_client.py +55 -55
  41. package/skills/cosmic-build/scripts/appconfig_load.py +2 -2
  42. package/skills/cosmic-build/scripts/apply_report_filter_extension.py +39 -0
  43. package/skills/cosmic-build/scripts/bootstrap_cosmic_context.py +37 -2
  44. package/skills/cosmic-build/scripts/compile_plugin_source.py +279 -156
  45. package/skills/cosmic-build/scripts/execution_binding.py +40 -0
  46. package/skills/cosmic-build/scripts/inspect_platform_sdk.py +169 -0
  47. package/skills/cosmic-build/scripts/kd_api.py +23 -22
  48. package/skills/cosmic-build/scripts/kd_auth.py +1 -1
  49. package/skills/cosmic-build/scripts/kd_env_loader.py +19 -10
  50. package/skills/cosmic-build/scripts/kd_token_cache.py +2 -2
  51. package/skills/cosmic-build/scripts/kingscript_sdk_sync.py +350 -0
  52. package/skills/cosmic-build/scripts/kingscript_source_gate.py +11 -8
  53. package/skills/cosmic-build/scripts/platform_api_contract.py +246 -11
  54. package/skills/cosmic-build/scripts/plugin_corpus/build_index.py +403 -0
  55. package/skills/cosmic-build/scripts/plugin_corpus/jvm_classfile.py +281 -0
  56. package/skills/cosmic-build/scripts/plugin_corpus/measure_api_usage.py +446 -0
  57. package/skills/cosmic-build/scripts/plugin_source_gate.py +48 -7
  58. package/skills/cosmic-build/scripts/plugin_target_sdk.py +45 -0
  59. package/skills/cosmic-build/scripts/prepare_plugin_handoff.py +493 -47
  60. package/skills/cosmic-build/scripts/preview_url.py +35 -6
  61. package/skills/cosmic-build/scripts/query_plugin_handoff.py +250 -0
  62. package/skills/cosmic-build/scripts/register_plugins.py +28 -2
  63. package/skills/cosmic-build/scripts/render_output_cards.py +42 -9
  64. package/skills/cosmic-build/scripts/report_algo_benchmark.py +46 -0
  65. package/skills/cosmic-build/scripts/run.py +2 -2
  66. package/skills/cosmic-build/scripts/sync_generated_locale_assets.py +43 -0
  67. package/skills/cosmic-build/scripts/test/fixtures/ReportSdkCheck.java +64 -0
  68. package/skills/cosmic-build/scripts/test/fixtures/java_context_booking_native.json +541 -0
  69. package/skills/cosmic-build/scripts/test/test_add_rule_business_contract.py +85 -14
  70. package/skills/cosmic-build/scripts/test/test_batch5_drift_governance.py +12 -3
  71. package/skills/cosmic-build/scripts/test/test_build_meta_order.py +0 -16
  72. package/skills/cosmic-build/scripts/test/test_cli_continuation.py +87 -0
  73. package/skills/cosmic-build/scripts/test/test_compile_plugin_source.py +224 -3
  74. package/skills/cosmic-build/scripts/test/test_control_authoring.py +123 -4
  75. package/skills/cosmic-build/scripts/test/test_cosmic_sdk_examples.py +141 -0
  76. package/skills/cosmic-build/scripts/test/test_data_model_contract.py +30 -5
  77. package/skills/cosmic-build/scripts/test/test_delivery_stage_boundary.py +2 -10
  78. package/skills/cosmic-build/scripts/test/test_dym_sync_background.py +11 -0
  79. package/skills/cosmic-build/scripts/test/test_dynamic_form_metadata_only_contract.py +59 -1
  80. package/skills/cosmic-build/scripts/test/test_guide_skeleton_contract.py +87 -43
  81. package/skills/cosmic-build/scripts/test/test_inspect_platform_sdk.py +71 -0
  82. package/skills/cosmic-build/scripts/test/test_kd_api.py +67 -19
  83. package/skills/cosmic-build/scripts/test/test_kingscript_sdk_sync.py +221 -0
  84. package/skills/cosmic-build/scripts/test/test_kingscript_source_gate.py +10 -0
  85. package/skills/cosmic-build/scripts/test/test_list_configuration_closure.py +18 -0
  86. package/skills/cosmic-build/scripts/test/test_long_session_regressions.py +116 -0
  87. package/skills/cosmic-build/scripts/test/test_mcp_cli.py +524 -0
  88. package/skills/cosmic-build/scripts/test/test_modeling_input_recovery.py +141 -0
  89. package/skills/cosmic-build/scripts/test/test_open_world_cli_catalog.py +36 -2
  90. package/skills/cosmic-build/scripts/test/test_platform_api_contract.py +161 -1
  91. package/skills/cosmic-build/scripts/test/test_plugin_business_contract.py +91 -0
  92. package/skills/cosmic-build/scripts/test/test_plugin_corpus.py +195 -0
  93. package/skills/cosmic-build/scripts/test/test_plugin_handoff.py +346 -1
  94. package/skills/cosmic-build/scripts/test/test_plugin_target_sdk.py +70 -0
  95. package/skills/cosmic-build/scripts/test/test_preview_url.py +44 -1
  96. package/skills/cosmic-build/scripts/test/test_property_batch.py +22 -0
  97. package/skills/cosmic-build/scripts/test/test_property_input_discovery.py +13 -11
  98. package/skills/cosmic-build/scripts/test/test_query_plugin_handoff.py +160 -0
  99. package/skills/cosmic-build/scripts/test/test_register_plugins.py +31 -1
  100. package/skills/cosmic-build/scripts/test/test_render_output_cards.py +50 -4
  101. package/skills/cosmic-build/scripts/test/test_report_business_contract.py +27 -0
  102. package/skills/cosmic-build/scripts/test/test_report_doc_contract_sync.py +5 -4
  103. package/skills/cosmic-build/scripts/test/test_report_sdk_optimization.py +36 -0
  104. package/skills/cosmic-build/scripts/test/test_rule_batch_evidence.py +1 -1
  105. package/skills/cosmic-build/scripts/test/test_rule_domain_contract.py +20 -0
  106. package/skills/cosmic-build/scripts/test/test_rule_function_formula.py +16 -6
  107. package/skills/cosmic-build/scripts/test/test_skill_entry_contract.py +1 -0
  108. package/skills/cosmic-build/scripts/test/test_test_environment.py +45 -0
  109. package/skills/cosmic-build/scripts/test/test_verify_plugin_loading.py +79 -0
  110. package/skills/cosmic-build/scripts/test_environment.py +49 -0
  111. package/skills/cosmic-build/scripts/verify_plugin_loading.py +71 -0
  112. package/skills/cosmic-build/skills/cosmic-coding-impl/SKILL.md +86 -162
  113. package/skills/cosmic-build/skills/cosmic-coding-script/ATTRIBUTION.md +1 -1
  114. package/skills/cosmic-build/skills/cosmic-coding-script/SKILL.md +45 -14
  115. package/skills/cosmic-build/skills/cosmic-coding-script/references/kwc-controller-authoring.md +6 -0
  116. package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/README.md +29 -19
  117. package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/docs//350/204/232/346/234/254SDK.md +3 -4
  118. package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/indexes/package-index.md +1 -1
  119. package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/strategy.md +27 -18
  120. package/skills/cosmic-build/skills/cosmic-meta-api/SKILL.md +11 -17
  121. package/skills/cosmic-build/skills/cosmic-meta-api/apis/ai_meta.md +1 -1
  122. package/skills/cosmic-build/skills/cosmic-meta-api/apis/app_menu.md +1 -1
  123. package/skills/cosmic-build/skills/cosmic-meta-api/apis/meta_log.md +1 -1
  124. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/control-authoring.json +45 -4
  125. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/form-control-traits.json +1 -1
  126. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/layout-ui.json +18 -0
  127. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/menu-publish.json +8 -2
  128. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/property-batch.json +7 -0
  129. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/property-input-index.json +3 -3
  130. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/report-write-contracts.json +1 -0
  131. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/rule-domain.json +37 -5
  132. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/rule-event-contract.json +24 -3
  133. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/run-build-meta.json +61 -12
  134. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/dropdown-menu.schema.json +69 -0
  135. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/report-write.schema.json +2 -1
  136. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/rule-set.schema.json +1 -0
  137. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/rule-write.schema.json +14 -7
  138. package/skills/cosmic-build/skills/cosmic-meta-api/docs/api-summary.md +2 -2
  139. package/skills/cosmic-build/skills/cosmic-meta-api/modules/app-action/SKILL.md +6 -3
  140. package/skills/cosmic-build/skills/cosmic-meta-api/modules/develop/SKILL.md +1 -2
  141. package/skills/cosmic-build/skills/cosmic-meta-api/modules/export/SKILL.md +5 -6
  142. package/skills/cosmic-build/skills/cosmic-meta-api/modules/init/SKILL.md +13 -36
  143. package/skills/cosmic-build/skills/cosmic-meta-api/modules/pdm/SKILL.md +8 -9
  144. package/skills/cosmic-build/skills/cosmic-meta-api/modules/pdm/scripts/config.json.example +5 -15
  145. package/skills/cosmic-build/skills/cosmic-meta-api/modules/reset/SKILL.md +6 -6
  146. package/skills/cosmic-build/skills/cosmic-meta-api/modules/usage/SKILL.md +20 -148
  147. package/skills/cosmic-build/skills/cosmic-meta-api/modules/verify/SKILL.md +1 -1
  148. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/build_receipts.py +171 -0
  149. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_apps.py +25 -6
  150. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_controls.py +55 -21
  151. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_fields.py +10 -3
  152. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_formactions.py +63 -6
  153. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_forms.py +59 -2
  154. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_listui.py +8 -0
  155. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_metaops.py +36 -1
  156. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_plugins.py +115 -90
  157. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_properties.py +666 -4
  158. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_rules.py +1415 -87
  159. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/commands.py +6 -1
  160. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/config.py +28 -15
  161. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/execution_errors.py +40 -0
  162. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/formatters.py +32 -5
  163. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/property_policy_contract.py +6 -0
  164. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/report_ops.py +113 -17
  165. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/reset.py +3 -3
  166. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/rule_contract.py +107 -26
  167. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/build_meta_order.py +50 -49
  168. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/cosmic_api.py +856 -150
  169. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/field_decorator.py +47 -14
  170. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_build_receipt_resume.py +374 -0
  171. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_cli_failure_contract.py +24 -0
  172. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_creation_identity_boundary.py +4 -2
  173. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_dropdown_menu_contract.py +382 -0
  174. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_existing_form_ui.py +0 -25
  175. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_field_decorator.py +50 -6
  176. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_functional_group_resolution.py +83 -16
  177. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_identity_template_resolution.py +103 -0
  178. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_plugin_contract.py +28 -2
  179. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_readback_derivation.py +22 -0
  180. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_typed_filters.py +65 -0
  181. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_rule_write_closure.py +1041 -15
  182. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_run_batch_post_build_recovery.py +65 -0
  183. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_run_batch_verification_evidence.py +17 -0
  184. package/skills/cosmic-build/skills/cosmic-meta-knowledge/generation/api-param-checklist.md +1 -1
  185. package/skills/cosmic-build/skills/cosmic-meta-knowledge/generation/rule-modeling-guide.md +7 -4
  186. package/skills/cosmic-build/skills/cosmic-meta-modeling/SKILL.md +61 -13
  187. package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/app-menu/SKILL.md +8 -0
  188. package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/formtemplate/SKILL.md +5 -0
  189. package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/formtemplate/dynamic-form-artifact-schema.md +5 -0
  190. package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/report/SKILL.md +21 -9
  191. package/skills/cosmic-build/skills/cosmic-meta-modeling/references/authoring-entity-graphs.md +1 -1
  192. package/skills/cosmic-build/skills/cosmic-meta-modeling/references/authoring-storage-constraints.md +5 -3
  193. package/skills/cosmic-build/skills/cosmic-meta-modeling/references/authoring-ui-composition.md +6 -3
  194. package/skills/cosmic-build/skills/cosmic-meta-modeling/references/creation-recovery.md +13 -0
  195. package/skills/cosmic-build/skills/cosmic-meta-modeling/references/parse-core.md +3 -0
  196. package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/data_model_contract.py +6 -1
  197. package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/data_model_emit.py +135 -87
  198. package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/field_type_registry.py +11 -1
  199. package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/isv_resolver.py +1 -3
  200. package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/report_validator.py +29 -0
  201. package/skills/cosmic-build/skills/cosmic-meta-modifier/SKILL.md +4 -2
  202. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/context/SKILL.md +2 -2
  203. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/execute/SKILL.md +1 -1
  204. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/operation/SKILL.md +5 -4
  205. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/operation/operation-write.md +6 -2
  206. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/operation/validation.md +2 -0
  207. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/property/SKILL.md +20 -5
  208. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/property/complex-apis.md +1 -1
  209. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/property/policy-grammar.md +4 -1
  210. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/report-op/SKILL.md +9 -0
  211. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/SKILL.md +61 -4
  212. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/raw-rule-authoring.md +3 -1
  213. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/rule-actions.md +2 -2
  214. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/rule-reference.md +6 -6
  215. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/state.md +1 -1
  216. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/unit/SKILL.md +6 -3
  217. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/verify/usage-guide.md +4 -4
  218. package/skills/cosmic-build/skills/cosmic-meta-modifier/references/list-filter-modification.md +4 -1
  219. package/skills/cosmic-build/skills/cosmic-meta-ui/SKILL.md +9 -1
  220. package/skills/cosmic-build/skills/cosmic-meta-ui/modules/button/SKILL.md +3 -0
  221. package/skills/cosmic-build/skills/mcp-server/SKILL.md +210 -0
  222. package/skills/cosmic-build/skills/mcp-server/scripts/mcp_cli.py +431 -0
  223. package/skills/cosmic-build/skills/openapi-gen/SKILL.md +3 -3
  224. package/skills/cosmic-build/skills/openapi-gen/scripts/api/gen_runner.py +2 -2
  225. package/skills/cosmic-dev-best-practices/references/bill-dev-convention.md +19 -9
  226. package/skills/cosmic-dev-best-practices/references/cosmic-meta-api.md +14 -11
  227. package/skills/cosmic-dev-best-practices/references/design-examples/basedata-design-example.md +1 -1
  228. package/skills/cosmic-dev-best-practices/references/design-examples/bill-design-example.md +1 -1
  229. package/skills/cosmic-dev-best-practices/references/elements/AssistantField.md +1 -1
  230. package/skills/cosmic-dev-best-practices/references/elements/BasedataField.md +2 -2
  231. package/skills/cosmic-dev-best-practices/references/elements/BasedataPropField.md +3 -3
  232. package/skills/cosmic-dev-best-practices/references/elements/CreaterField.md +2 -2
  233. package/skills/cosmic-dev-best-practices/references/elements/CurrencyField.md +2 -2
  234. package/skills/cosmic-dev-best-practices/references/elements/CustomerField.md +2 -2
  235. package/skills/cosmic-dev-best-practices/references/elements/FlexField.md +1 -1
  236. package/skills/cosmic-dev-best-practices/references/elements/MaterielField.md +2 -2
  237. package/skills/cosmic-dev-best-practices/references/elements/OrgField.md +2 -2
  238. package/skills/cosmic-dev-best-practices/references/elements/SupplierField.md +2 -2
  239. package/skills/cosmic-dev-best-practices/references/elements/UnitField.md +1 -1
  240. package/skills/cosmic-dev-best-practices/references/elements/UserField.md +3 -3
  241. package/skills/cosmic-dev-best-practices/references/elements/common-field-property-conventions.md +16 -11
  242. package/skills/cosmic-dev-best-practices/references/layout-control-convention.md +5 -4
  243. package/skills/erp-analysis/references/delivery-contract.md +4 -2
  244. package/skills/erp-analysis/templates/AGENTS.template.md +1 -1
  245. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/.dsh/cosmic/.kd/config.json +0 -21
@@ -0,0 +1,431 @@
1
+ #!/usr/bin/env python3
2
+ """MCP service management CLI for open_mcp_ext.
3
+
4
+ 调用平台 devportal/ai-meta/mcpserver/* 接口族(9 个端点:listByForm/get 为 GET,
5
+ 其余 7 个为 POST),覆盖 MCP 服务列表的对话式全生命周期:查询、按单据查询、
6
+ 新增/修改、删除、YAML 批量导入、注册状态重置、下架、导出。
7
+
8
+ 接口契约来源:kd.bos.mcp.McpServerApiController(@ApiController("devportal") +
9
+ @ApiMapping("/ai-meta/mcpserver"))。平台响应为 CustomApiResult 包装
10
+ ({status, errorCode, message, data}),与 kd_api 消费的现有 ai-meta 家族同构。
11
+
12
+ 用法(机器模式统一加 --stdout,输出单条 JSON):
13
+ mcp_cli.py list [--status CODE] [--source-type V] [--api-type V] [--tool-name S]
14
+ [--number S] [--api-number S] [--page-index N] [--page-size N]
15
+ mcp_cli.py listByForm --form-number FORMNUMBER
16
+ mcp_cli.py get --id ID
17
+ mcp_cli.py save --api-type openapi_apilist|open_rest_api --api-id ID --description D
18
+ [--operate-type V] [--domain D] [--module D]
19
+ [--before-condition S] [--after-condition S] [--err-recovery S]
20
+ [--cus-param-ext-cfg JSON] [--tool-name S] [--source-yaml S]
21
+ mcp_cli.py save --id ID [--description D] [同上可选字段…]
22
+ mcp_cli.py delete --ids 1,2,3 --confirm
23
+ mcp_cli.py importYaml --file PATH [--mode override|ignore] [--save-yaml]
24
+ mcp_cli.py resetStatus --ids 1,2,3 --confirm
25
+ mcp_cli.py unshelves --ids 1,2,3 --confirm
26
+ mcp_cli.py export --ids 1,2,3 --format dts|yaml [--output PATH]
27
+
28
+ destructive 命令(delete/resetStatus/unshelves)必须显式带 --confirm,缺省时
29
+ 拒绝执行并以退出码 2 结束,防脚本误触。
30
+ """
31
+
32
+ import argparse
33
+ import json
34
+ import os
35
+ import re
36
+ import sys
37
+ import urllib.error
38
+
39
+ # 引导到 app-build/scripts,复用 kd_api / kd_env_loader 认证与传输基建
40
+ _ROOT_SCRIPTS = os.path.normpath(
41
+ os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "..", "scripts")
42
+ )
43
+ if _ROOT_SCRIPTS not in sys.path:
44
+ sys.path.insert(0, _ROOT_SCRIPTS)
45
+
46
+ import kd_api # noqa: E402
47
+ from kd_env_loader import load_effective_skill_config # noqa: E402
48
+
49
+ # ─── 平台端点契约 ────────────────────────────────────────────────────────────
50
+ _API_PREFIX = "/kapi/v2/devportal/ai-meta/mcpserver"
51
+
52
+ ENDPOINTS = {
53
+ "list": _API_PREFIX + "/list",
54
+ "listByForm": _API_PREFIX + "/listByForm",
55
+ "get": _API_PREFIX + "/get",
56
+ "save": _API_PREFIX + "/save",
57
+ "delete": _API_PREFIX + "/delete",
58
+ "importYaml": _API_PREFIX + "/importYaml",
59
+ "resetStatus": _API_PREFIX + "/resetStatus",
60
+ "unshelves": _API_PREFIX + "/unshelves",
61
+ "export": _API_PREFIX + "/export",
62
+ }
63
+
64
+ # 平台侧只读端点走 GET(query 参数),POST 会命中 HTTP 405 HttpMethod POST is
65
+ # not allowed;写端点仍为 POST + JSON body。GET 分支的 payload 直接作为 query
66
+ # 参数(值需为字符串或可 urlencode 的标量),本 CLI 现有的 formNumber/id 均满足。
67
+ GET_ENDPOINTS = frozenset({"listByForm", "get"})
68
+
69
+ # McpRegisterStatusEnum 枚举 code(code → 显示名映射见 SKILL.md「注册状态生命周期」)
70
+ REGISTER_STATUS = frozenset({
71
+ "SUCCESS", "FAILED", "UNPUBLISH", "UNSHELVES", "UNSHELVESED", "PENDING_UPDATE",
72
+ })
73
+
74
+ # MCP 服务指向的目标 API 实体:V2 零码 API / V3 RESTful API
75
+ API_TYPES = ("openapi_apilist", "open_rest_api")
76
+
77
+ EXPORT_FORMATS = ("dts", "yaml")
78
+
79
+ # importYaml mode:override=已存在则覆盖更新(默认);ignore=已存在则跳过
80
+ IMPORT_MODES = ("override", "ignore")
81
+
82
+ DESTRUCTIVE_COMMANDS = frozenset({"delete", "resetStatus", "unshelves"})
83
+
84
+
85
+ def _load_config():
86
+ """加载运行时配置并展平成 kd_api 消费的形状。
87
+
88
+ load_effective_skill_config 返回 {server, pdm, preview, featureServer}
89
+ 嵌套结构(server.baseUrl 等),而 kd_api 读取顶层 baseUrl/appId/appSecret/
90
+ accountId/tenantId。测试打桩点。
91
+ """
92
+ config = load_effective_skill_config()
93
+ server = config.get("server") or {}
94
+ flat = dict(server)
95
+ flat.update(config.get("pdm") or {})
96
+ for key in ("baseUrl", "appId", "appSecret", "accountId", "tenantId"):
97
+ if not flat.get(key):
98
+ flat[key] = server.get(key)
99
+ return flat
100
+
101
+
102
+ def _ok(data):
103
+ return {"status": True, "errorCode": None, "message": None, "data": data}
104
+
105
+
106
+ def _fail(error_code, message):
107
+ return {"status": False, "errorCode": error_code, "message": message, "data": None}
108
+
109
+
110
+ # 灵基与苍穹发版解耦:目标环境可能未部署 ai-meta/mcpserver 接口族。两类特征归并
111
+ # 为 MCP_API_NOT_DEPLOYED——网关 NPE 无 TraceId(API 条目已登记、后端控制器未部署)
112
+ # 与 404 Cannot found OpenAPI(API 条目未登记)。
113
+ _NOT_DEPLOYED_MESSAGE = (
114
+ "the devportal/ai-meta/mcpserver API family is not deployed on this "
115
+ "environment (Lingee and Cosmic release on independent schedules); "
116
+ "deploy the platform package or operate via the OpenAPI MCP UI"
117
+ )
118
+
119
+ # 平台失败 message 可携带 TraceId/WebInstance/完整 Java 栈(如 get 命中已删除记录的
120
+ # bos.orm.read.dataNotExist 响应,栈迹数 KB);栈迹对诊断无价值(TraceId 在其前),
121
+ # 剥离后仍设长度上限,保持单条 JSON 机器输出契约紧凑。
122
+ _STACK_MARKER = "====Stack===="
123
+ _MESSAGE_LIMIT = 500
124
+
125
+
126
+ def _sanitize_message(message):
127
+ text = message or ""
128
+ stack_at = text.find(_STACK_MARKER)
129
+ if stack_at != -1:
130
+ text = text[:stack_at]
131
+ if len(text) > _MESSAGE_LIMIT:
132
+ text = text[:_MESSAGE_LIMIT] + "...(truncated)"
133
+ return text
134
+
135
+
136
+ def _read_http_error_body(exc):
137
+ try:
138
+ return exc.read()
139
+ except Exception:
140
+ return b""
141
+
142
+
143
+ def _classify_transport_failure(command, detail):
144
+ """区分「接口族未部署」与一般传输故障,兼容灵基/苍穹发版解耦场景。
145
+
146
+ 404 用词边界匹配:真实 TraceId 的十六进制串可能恰好含 "404" 子串
147
+ (如 a41f404c81fe2eec37),裸子串匹配会把带 TraceId 的真实服务端缺陷
148
+ 误判为未部署、且丢弃 TraceId——必须保持 PLATFORM_ERROR 并保留原样。
149
+ """
150
+ if "NullPointerException" in detail and ("TraceId:null" in detail or "TraceId:null" in detail):
151
+ return "MCP_API_NOT_DEPLOYED", _NOT_DEPLOYED_MESSAGE
152
+ if re.search(r"\b404\b", detail) or "Cannot found OpenAPI" in detail:
153
+ return "MCP_API_NOT_DEPLOYED", _NOT_DEPLOYED_MESSAGE
154
+ return "PLATFORM_ERROR", f"{command} call failed: {detail}"
155
+
156
+
157
+ def _call(command, payload, cfg):
158
+ """按 GET_ENDPOINTS 路由到 kd_api.get/post 并把 CustomApiResult 折叠为 CLI 结果。
159
+
160
+ listByForm/get 走 GET(payload 作为 query 参数),其余命令走 POST + JSON body。
161
+ 平台成功时 data 为业务对象;失败时 status=false 且 message 携带原因,
162
+ 继续透传平台 errorCode(如 STATUS_LOCKED / API_NOT_FOUND)。HTTP 层异常
163
+ 折叠为受控错误码(不让 traceback 泄漏到机器输出流):MCP_API_NOT_DEPLOYED
164
+ 表示环境未部署接口族,其余为 PLATFORM_ERROR。
165
+ """
166
+ try:
167
+ if command in GET_ENDPOINTS:
168
+ result = kd_api.get(None, ENDPOINTS[command], cfg, params=payload)
169
+ else:
170
+ result = kd_api.post(None, ENDPOINTS[command], cfg, payload)
171
+ except urllib.error.HTTPError as exc:
172
+ body = _read_http_error_body(exc).decode("utf-8", errors="replace")
173
+ detail = f"HTTP {exc.code}: {body[:200]}" if body else str(exc)
174
+ return _fail(*_classify_transport_failure(command, detail))
175
+ except Exception as exc: # noqa: BLE001 — transport/token/gateway failures all fold
176
+ return _fail(*_classify_transport_failure(command, str(exc)))
177
+ if result.get("status"):
178
+ return _ok(result.get("data"))
179
+ if str(result.get("errorCode") or "") == "404":
180
+ # body 级 404(HTTP 200 + "Cannot found OpenAPI"):该环境未登记本接口族
181
+ return _fail("MCP_API_NOT_DEPLOYED", _NOT_DEPLOYED_MESSAGE)
182
+ return _fail(
183
+ result.get("errorCode") or "PLATFORM_ERROR",
184
+ _sanitize_message(result.get("message")) or "platform call failed",
185
+ )
186
+
187
+
188
+ def _parse_ids(raw):
189
+ """'1,2,3'(或空白分隔)→ [1,2,3];非法输入抛 ValueError。"""
190
+ parts = [part for part in raw.replace(" ", ",").split(",") if part]
191
+ ids = []
192
+ for part in parts:
193
+ if not part.isdigit():
194
+ raise ValueError(f"invalid id value: {part!r} (positive integers expected)")
195
+ ids.append(int(part))
196
+ if not ids:
197
+ raise ValueError("ids must not be empty")
198
+ return ids
199
+
200
+
201
+ def _read_file(path):
202
+ if not os.path.isfile(path):
203
+ raise ValueError(f"file not found: {path}")
204
+ with open(path, "r", encoding="utf-8") as handle:
205
+ return handle.read()
206
+
207
+
208
+ def _parse_json(raw, field):
209
+ try:
210
+ return json.loads(raw)
211
+ except json.JSONDecodeError as exc:
212
+ raise ValueError(f"--{field} is not valid JSON: {exc}") from exc
213
+
214
+
215
+ def build_list_payload(args):
216
+ payload = {
217
+ "pageIndex": args.page_index,
218
+ "pageSize": args.page_size,
219
+ }
220
+ filters = {
221
+ "registerStatus": args.status,
222
+ "sourceType": args.source_type,
223
+ "apiType": args.api_type,
224
+ "toolName": args.tool_name,
225
+ "number": args.number,
226
+ "apiNumber": args.api_number,
227
+ }
228
+ for key, value in filters.items():
229
+ if value:
230
+ payload[key] = value
231
+ return payload
232
+
233
+
234
+ def build_save_payload(args):
235
+ payload = {
236
+ "id": args.id,
237
+ "apiType": args.api_type,
238
+ "apiId": args.api_id,
239
+ "description": args.description,
240
+ "operateType": args.operate_type,
241
+ "domain": args.domain,
242
+ "module": args.module,
243
+ "beforeCondition": args.before_condition,
244
+ "afterCondition": args.after_condition,
245
+ "errRecovery": args.err_recovery,
246
+ "cusParamExtCfg": args.cus_param_ext_cfg,
247
+ "toolNameNew": args.tool_name,
248
+ "sourceYaml": args.source_yaml,
249
+ }
250
+ return {key: value for key, value in payload.items() if value is not None}
251
+
252
+
253
+ def build_import_payload(args):
254
+ return {
255
+ "yamlContent": _read_file(args.file),
256
+ "fileName": os.path.basename(args.file),
257
+ "mode": args.mode,
258
+ "saveYaml": args.save_yaml,
259
+ }
260
+
261
+
262
+ def build_export_payload(args):
263
+ return {"ids": _parse_ids(args.ids), "format": args.format}
264
+
265
+
266
+ def save_export_content(args, data):
267
+ """导出内容落盘,stdout 只回元数据(content 可能极大,不进 JSON 流)。"""
268
+ if not data:
269
+ raise ValueError("export response has no data")
270
+ output_path = args.output or os.path.abspath(data.get("fileName") or "mcp-export.txt")
271
+ with open(output_path, "w", encoding="utf-8") as handle:
272
+ handle.write(data.get("content") or "")
273
+ return {
274
+ "format": data.get("format"),
275
+ "fileName": os.path.basename(output_path),
276
+ "savedTo": output_path,
277
+ "count": data.get("count"),
278
+ }
279
+
280
+
281
+ def run_command(args):
282
+ """分发表。返回 (result_dict, exit_code)。"""
283
+ command = args.command
284
+ if command in DESTRUCTIVE_COMMANDS and not args.confirm:
285
+ return _fail(
286
+ "CONFIRM_REQUIRED",
287
+ f"'{command}' is destructive and modifies platform records. "
288
+ "Re-run with --confirm after the user has explicitly approved.",
289
+ ), 2
290
+
291
+ try:
292
+ if command == "list":
293
+ payload = build_list_payload(args)
294
+ elif command == "listByForm":
295
+ payload = {"formNumber": args.form_number}
296
+ elif command == "get":
297
+ payload = {"id": args.id}
298
+ elif command == "save":
299
+ # cusParamExtCfg 必须是 JSON 对象串,客户端先行校验(服务端 CUS_PARAM_INVALID 兜底)
300
+ if args.cus_param_ext_cfg:
301
+ parsed = _parse_json(args.cus_param_ext_cfg, "cus-param-ext-cfg")
302
+ if not isinstance(parsed, dict):
303
+ raise ValueError('--cus-param-ext-cfg must be a JSON object, e.g. {"key": "value"}')
304
+ payload = build_save_payload(args)
305
+ elif command in ("delete", "resetStatus", "unshelves"):
306
+ payload = {"ids": _parse_ids(args.ids)}
307
+ elif command == "importYaml":
308
+ payload = build_import_payload(args)
309
+ elif command == "export":
310
+ payload = build_export_payload(args)
311
+ else:
312
+ return _fail("UNKNOWN_COMMAND", f"unknown command: {command}"), 2
313
+ except (ValueError, OSError) as exc:
314
+ # OSError 并入:--file 指向存在但无读权限的文件时 _read_file 抛
315
+ # PermissionError,属参数指向的文件不可读,归 CLI_ARGUMENT_ERROR(exit 2)
316
+ return _fail("CLI_ARGUMENT_ERROR", str(exc)), 2
317
+
318
+ result = _call(command, payload, _load_config())
319
+ if not result["status"]:
320
+ return result, 1
321
+ if command == "export":
322
+ try:
323
+ result = _ok(save_export_content(args, result["data"]))
324
+ except (ValueError, OSError) as exc:
325
+ return _fail("EXPORT_WRITE_ERROR", str(exc)), 1
326
+ return result, 0
327
+
328
+
329
+ class _JsonArgumentParser(argparse.ArgumentParser):
330
+ """argparse 层错误(无效枚举/缺参/未知子命令)也输出单条 JSON,对齐 cosmic_api.py 的机器模式契约。"""
331
+
332
+ def error(self, message):
333
+ print(json.dumps(_fail("CLI_ARGUMENT_ERROR", message), ensure_ascii=False))
334
+ raise SystemExit(2)
335
+
336
+
337
+ def build_parser():
338
+ parser = _JsonArgumentParser(
339
+ prog="mcp_cli.py",
340
+ description="Manage Kingdee OpenAPI MCP services (open_mcp_ext) via devportal/ai-meta/mcpserver endpoints.",
341
+ )
342
+ parser.add_argument("--stdout", action="store_true", help="machine-readable single-JSON output")
343
+ sub = parser.add_subparsers(dest="command", required=True)
344
+
345
+ p_list = sub.add_parser("list", help="List MCP services with optional filters")
346
+ p_list.add_argument("--status", choices=sorted(REGISTER_STATUS), help="register status code, e.g. SUCCESS")
347
+ p_list.add_argument("--source-type", help="source type filter, e.g. custom (tenant-built)")
348
+ p_list.add_argument("--api-type", choices=list(API_TYPES), help="target API type filter")
349
+ p_list.add_argument("--tool-name", help="tool name keyword filter")
350
+ p_list.add_argument("--number", help="MCP record number (billno) filter")
351
+ p_list.add_argument("--api-number", help="target API number filter")
352
+ p_list.add_argument("--page-index", type=int, default=1)
353
+ p_list.add_argument("--page-size", type=int, default=20)
354
+
355
+ p_list_by_form = sub.add_parser(
356
+ "listByForm",
357
+ help="List APIs and registered MCP tools of one form (end-to-end pipeline query)",
358
+ )
359
+ p_list_by_form.add_argument("--form-number", required=True,
360
+ help="form number, e.g. kdtest_food")
361
+
362
+ p_get = sub.add_parser("get", help="Get one MCP service detail by id")
363
+ p_get.add_argument("--id", type=int, required=True)
364
+
365
+ p_save = sub.add_parser("save", help="Create or update an MCP service (update: pass --id)")
366
+ p_save.add_argument("--id", type=int, help="record id; omit to create")
367
+ p_save.add_argument("--api-type", choices=list(API_TYPES), help="target API entity: openapi_apilist (V2) or open_rest_api (V3)")
368
+ p_save.add_argument("--api-id", type=int, help="target API primary key")
369
+ p_save.add_argument("--description", help="tool description (required by entity)")
370
+ p_save.add_argument(
371
+ "--operate-type",
372
+ help="operation type enum: query/create/update/save/delete/submit/unsubmit/"
373
+ "audit/unaudit/enable/disable/execute/invoke/action/cancel",
374
+ )
375
+ p_save.add_argument("--domain", help="x-ai-domain")
376
+ p_save.add_argument("--module", help="x-ai-module")
377
+ p_save.add_argument("--before-condition", help="x-ai-preconditions text")
378
+ p_save.add_argument("--after-condition", help="x-ai-postconditions text")
379
+ p_save.add_argument("--err-recovery", help="x-ai-error-recovery text")
380
+ p_save.add_argument("--cus-param-ext-cfg", help="custom param extension config, JSON object string")
381
+ p_save.add_argument("--tool-name", help="explicit tool name; server builds one when omitted")
382
+ p_save.add_argument("--source-yaml", help="source YAML text")
383
+
384
+ for name, help_text in (
385
+ ("delete", "Delete MCP services by ids"),
386
+ ("resetStatus", "Reset register status to UNPUBLISH (FAILED/UNSHELVESED only)"),
387
+ ("unshelves", "Unpublish MCP services (SUCCESS/PENDING_UPDATE only)"),
388
+ ):
389
+ p_batch = sub.add_parser(name, help=help_text)
390
+ p_batch.add_argument("--ids", required=True, help="comma-separated record ids, e.g. 1,2,3")
391
+ p_batch.add_argument("--confirm", action="store_true", help="required: acknowledge the destructive effect")
392
+
393
+ p_import = sub.add_parser("importYaml", help="Batch import MCP services from an OpenAPI YAML file")
394
+ p_import.add_argument("--file", required=True, help="local OpenAPI YAML file path")
395
+ p_import.add_argument("--mode", choices=list(IMPORT_MODES), default="override",
396
+ help="override: update existing records (default); ignore: skip existing")
397
+ p_import.add_argument("--save-yaml", action="store_true",
398
+ help="store the raw YAML into source_yaml (default off)")
399
+
400
+ p_export = sub.add_parser("export", help="Export MCP services as DTS or YAML")
401
+ p_export.add_argument("--ids", required=True, help="comma-separated record ids")
402
+ p_export.add_argument("--format", required=True, choices=list(EXPORT_FORMATS))
403
+ p_export.add_argument("--output", help="output file path (default: server-provided fileName in cwd)")
404
+
405
+ return parser
406
+
407
+
408
+ def main(argv=None):
409
+ """Parse argv, run the command, print the single-JSON result. Returns exit code.
410
+
411
+ --stdout is accepted for convention parity with cosmic_api.py but output is
412
+ always a single machine-readable JSON line — this CLI has no human mode.
413
+ run_command 之外的意外异常(如 _load_config 里 kd_env_loader 的 RuntimeError、
414
+ 磁盘故障等)也折叠为 CLI_EXECUTION_ERROR 单条 JSON(对齐 cosmic_api.py 的
415
+ _emit_machine_error 兜底),绝不向 stdout 泄漏 traceback。
416
+ """
417
+ args = build_parser().parse_args(argv)
418
+ try:
419
+ result, exit_code = run_command(args)
420
+ except Exception as exc: # noqa: BLE001 — fold into the single-JSON contract
421
+ result = _fail(
422
+ "CLI_EXECUTION_ERROR",
423
+ _sanitize_message(f"{type(exc).__name__}: {exc}") or type(exc).__name__,
424
+ )
425
+ exit_code = 1
426
+ print(json.dumps(result, ensure_ascii=False))
427
+ return exit_code
428
+
429
+
430
+ if __name__ == "__main__":
431
+ raise SystemExit(main())
@@ -150,7 +150,7 @@ app-build 进入本技能后,直接根据用户要求和已验证表单身份
150
150
  - **bizobject**:实体编码
151
151
  - **operations**:要生成的 API 操作(如 save,query,submit)
152
152
  - **实体中文名**:用于 API 命名
153
- - **appid**:从 context.json 或 config.json 获取
153
+ - **appid**:从 context.json 或 `~/.kd/config.json` 获取
154
154
 
155
155
  ### 进入标准流程
156
156
 
@@ -188,7 +188,7 @@ app-build 进入本技能后,直接根据用户要求和已验证表单身份
188
188
  - operations(必须):只使用用户明确要求的操作,如 save,query,submit
189
189
  · 若未提供 operations,立即阻断并请求明确 API 操作;不读取计划产物,不回退为"全部生成"
190
190
  · appendentryrows / deleteentryrows 还需 --target-entry <分录字段名>
191
- - appid(可选):默认元数据 BizAppNumber → config.json 的 server.appNumber → CLI --appid 覆盖
191
+ - appid(可选):默认元数据 BizAppNumber → `~/.kd/config.json` 的 server.appNumber → CLI --appid 覆盖
192
192
 
193
193
  2. 跑命令(一条搞定,自动获取元数据 → 动态查操作 → 构造 body → 提交 → 归档):
194
194
  python scripts/api/gen_runner.py <bizobject> --operations <ops> [--app-root <appRoot>]
@@ -402,7 +402,7 @@ python scripts/api/gen_runner.py <bizobject> --operations deleteentryrows \
402
402
  6. **`resp_from_body` 每次调用必须重新生成 id**,不能跨 API 复用同一份返回参数。
403
403
  7. `urlformat` 全局唯一,重复提交时脚本自动降级为更新(upsert 逻辑)。
404
404
  8. `apiservicetype` 固定 `"0"`,`version` 固定 `"2"`,`enable` 传 `"1"`。
405
- 9. **APPID 来源**:优先从 getEntityType 接口返回的 `BizAppNumber` 获取,没有则取 config.json 的 `server.appNumber`,也可通过 `--appid` 参数显式覆盖。
405
+ 9. **APPID 来源**:优先从 getEntityType 接口返回的 `BizAppNumber` 获取,没有则取 `~/.kd/config.json` 所选环境的 `server.appNumber`,也可通过 `--appid` 参数显式覆盖。
406
406
  10. **`paramtype`/`respparamtype` 只能用合法枚举值**(两者共 12 项:`String` / `Long` / `Integer` / `Boolean` / `Decimal` / `Date` / `DateTime` / `Array<String>` / `Array<Long>` / `Array<Integer>` / `Entries` / `Flex`)。`Object` / `Map` / `Array<Map>` 仅在固定返回分录 `respentryentity_s` 中合法,**本 skill 不生成该分录**,故禁止使用。
407
407
  11. **下拉列表当文本处理**(ComboProp/MulComboProp/BillStatusProp → `String`,不是 `Entries`)。
408
408
  12. **示例值必须是 JSON 字符串**(用双引号包裹),不能是裸值。
@@ -940,7 +940,7 @@ def run(bizobject, appid=None, name_prefix=None, operations=None, configs=None,
940
940
  v2 zero-code API batch generation public entry point.
941
941
 
942
942
  :param bizobject: entity code (required)
943
- :param appid: app code; defaults to metadata BizAppNumber first, then config.json server.appNumber
943
+ :param appid: app code; defaults to metadata BizAppNumber first, then ~/.kd/config.json server.appNumber
944
944
  :param name_prefix: API name prefix; defaults to entity display name from metadata
945
945
  :param operations: list of operations to generate (e.g. ['save','query']), must be explicitly provided
946
946
  :param configs: API config dict or 'k=v,k=v' string, normalized by parse_configs() and merged into body.data
@@ -1076,7 +1076,7 @@ if __name__ == '__main__':
1076
1076
  import argparse
1077
1077
  parser = argparse.ArgumentParser(description='v2 zero-code API batch generation')
1078
1078
  parser.add_argument('bizobject', help='Entity code (required)')
1079
- parser.add_argument('--appid', default=None, help='App code; defaults to metadata BizAppNumber first, then config.json server.appNumber')
1079
+ parser.add_argument('--appid', default=None, help='App code; defaults to metadata BizAppNumber first, then ~/.kd/config.json server.appNumber')
1080
1080
  parser.add_argument('--prefix', default=None, help='API name prefix; defaults to entity display name from metadata')
1081
1081
  parser.add_argument('--operations', required=True, help='Operations to generate, comma-separated (e.g. save,query,submit). query generates a GET query API')
1082
1082
  parser.add_argument('--config', default=None,
@@ -33,10 +33,12 @@
33
33
 
34
34
  - 模板编码:`bos_billorgtpl`(带组织单据,含主业务组织字段);
35
35
  - 实测继承路径(过磅单):`00305e8b000006ac,ab7efc31000010ac`(`ab7efc31000010ac` = `bos_billorgtpl`);
36
- - 主业务组织字段:`org`(OrgField,引用 `bos_org`),必填。
36
+ - 主业务组织字段:`org`(OrgField,引用 `bos_org`)——**模板未设必填,业务单据通常应设必填并指定为主业务组织**。
37
37
 
38
38
  > ⚠️ 这是统一要求——单据都走 `bos_billorgtpl`,不另选其他模板。
39
39
 
40
+ > 📌 **authoring 必须显式写 `templateKey: "bos_billorgtpl"`**:`data_model_emit` 省略时补的是 `bos_billtpl`(**不含 `org`**),不写即违反本条。
41
+
40
42
  ### 1.1 模板自带字段(继承 `bos_billorgtpl` 自动获得,无需开发)
41
43
 
42
44
  > 依据运行时模板 schema 实测(`getFormSchema bos_billorgtpl`),共 **9 个字段**(无分录——分录由开发单据自行添加)。
@@ -53,6 +55,8 @@
53
55
  | 创建时间 | `createtime` | CreateDateField | 否 | 审计字段 |
54
56
  | 组织 | `org` | OrgField [引用 `bos_org`] | 否 | 主业务组织(单据业务组织) |
55
57
 
58
+ > 📌 模板显示名是「组织」(既有单据多改为「业务组织」)——`uiComposition` 等按名选择时**用 fieldKey `org`**,避免解析不到。
59
+
56
60
  > **⚠️ 组织管控要求**:如果当前单据需要**组织管控**(权限控制、数据隔离),则 `org` 字段**必须录入**,且**必须设置为主业务组织字段**(单据属性中指定主业务组织)——否则权限/数据隔离不生效。
57
61
  > 参考:过磅单 `org` 为主组织(OrgField),且单据一般必填组织。
58
62
 
@@ -77,9 +81,13 @@
77
81
  > 附件面板 + 制单信息面板与基础资料一致(元素标识统一,见 `basedata-dev-...` 共性规范 + layout-control §〇)。
78
82
  > **面板可折叠(Collapsible)**:所有新建 FieldsetPanelAp 业务面板默认可折叠——命令与细节见 **layout-control §A**。
79
83
 
84
+ > 📌 **`uiComposition` 只排业务 Fieldset**:模板自带的 `attachmentpanel` 与平台补的 `advconap` 会留在原位,最终顺序要补一次 `applyPanelOrder`(**`order` 里带上 `advconap`**,否则"制单信息在最下方"会被顶掉):
85
+ > `applyPanelOrder --input '{"order":["fs_baseinfo","fs_payinfo","fs_platforminfo","fs_notifyinfo","attachmentpanel","fs_creator","advconap"]}'`
86
+ > 📌 **制单信息面板**须在 `uiComposition` 中显式列出 `creator`/`createtime`/`modifier`/`modifytime`/`auditor`/`auditdate`,否则这些字段不会被移动。
87
+
80
88
  > ⚠️ **无分录单据也躲不开"空分录骨架"**(2026-09-29 实测):
81
89
  > 平台会为**任何 `BillEntity`** 自动补出 `entryentity`(`EntryEntity`,**`table=""` 空表**,含默认字段 `modifierfield`/`modifydatefield`)
82
- > 与界面层 `advconap`(`AdvConAp → AdvConToolbarAp / AdvConChildPanelAp → EntryAp/entryentity`)。
90
+ > 与界面层 `advconap`(`AdvConAp →(AdvConToolbarAp、AdvConChildPanelAp → EntryAp/entryentity)`)。
83
91
  > - **与模板无关**:`bos_billorgtpl` 与 `bos_billtpl` **都会**补;`bos_basetpl` + `BaseEntity` **不会**(两臂对照实验)。
84
92
  > - **CLI 既无参数抑制、也无命令删除**:平台请求契约 `buildMeta-direct.json` 里根本没有该字段;200 条命令中 entry 相关只有 `addEntryEntity`(增)。
85
93
  > - ⇒ 无分录对象的正确处置:**设计器整块删「高级容器」**(让平台级联带走 `EntryAp`/`entryentity`)。
@@ -98,8 +106,6 @@
98
106
  | 必须动作 | **配置该单据的编码规则**(苍穹「编码规则」功能:前缀/日期段/流水号等) |
99
107
  | 校验 | 保存/新建时单据编号自动按规则生成;未配置则编号为空或报错 |
100
108
 
101
- > ⚠️ 每个单据都要单独配置自己的编码规则(按单据类型区分),不能共用。
102
-
103
109
  ### 3.2 单据类型、业务日期(一般必加)
104
110
 
105
111
  | 字段 | fieldKey | 类型 | 说明 |
@@ -110,6 +116,8 @@
110
116
 
111
117
  > ⚠️ **billtype agent 不创建(2026-08-25 用户确认)**:`BillTypeField` 属系统字段类型(`SYSTEM_FIELD_TYPES` 硬编码,见 field-property §〇·二),authoring/CLI 通道禁止创建(实测 `modifyMeta`/`addField` 报「'BillTypeField' 是系统字段类型,禁止手动创建」,源码 `FieldValidation` 硬校验)——**agent 建模时跳过 billtype**,**开发者设计器手工添加 BillTypeField** + 预置单据类型数据(`T_BAS_BILLTYPE`/编码规则,无 API,§6.0)。agent 在设计文档 §八 待办提醒。
112
118
 
119
+ > 📌 **系统字段(`billtype`/`paystatus` 等)交接**:① 后加字段落在面板末尾,需再排位置(`moveFormElement`);② 依赖它们的批次(锁定/默认值、`StatusItems`、列表列)必须等字段建好后再跑;③ 待办写清 **字段名 + 类型 + 面板与位置锚点 + 状态/候选值**(例:`paystatus`,BillStatusField,基本信息紧跟 `billstatus`,`wait`/`paid`,`DefValue=wait`)。
120
+
113
121
  ### 3.3 审核字段(模板自带,必须锁定)
114
122
 
115
123
  > `auditor`/`auditdate` **已在模板 `bos_billorgtpl` 中自带**(见 1.1),开发无需再加——只需锁定。
@@ -159,6 +167,7 @@
159
167
 
160
168
  > ⭐ **状态字段最终形态 = BillStatusField(单据状态)(2026-08-25 用户确认 + khxty 现有单据 dym 实测)**:`closestatus`/`cancelstatus` 的**标准类型是「单据状态」BillStatusField**(带 StatusItems 状态列表、DefValue=A)——khxty 全部开发单据实测一致(`sd_returnapp` 4 个、`sd_conord` 8 个、`sd_executeorder` 5 个、`sd_conpur` 7 个 `<BillStatusField>`)。
161
169
  > ⚠️ **agent 不创建状态字段(2026-08-25 用户确认)**:BillStatusField 属系统字段类型,authoring/CLI 通道禁止创建(实测契约校验 `FIELD_TYPE_MANUAL_FORBIDDEN`)——**agent 建模时跳过 closestatus/cancelstatus**,**开发者设计器手工添加 BillStatusField**;配套 closer/closedate/canceler/canceldate 由 agent 建模(UserField/DateTimeField)。
170
+ > 交接要求(位置 / 批次后置 / 待办要素)见 §3.2。
162
171
  >
163
172
  > ✅ **但「状态列表」(StatusItems)自 app-build 0.0.299 起有 API 通道**(本节旧文写的"StatusItems,无 API"**已过时**)——
164
173
  > 即:**字段本身**仍需设计器手工建,但**字段建好之后**其 StatusItems **可读可写**(**均已实证**):
@@ -266,20 +275,21 @@
266
275
 
267
276
  ## 七、建模后必做批次(buildMeta 默认缺口,2026-08-27 出口合同重建实测)
268
277
 
269
- > **buildMeta 只建「字段 + 基础布局」**,以下默认缺口必须后续批次补齐(固定五批次流程):
278
+ > **buildMeta 只建「字段 + 基础布局」**,以下默认缺口必须后续批次补齐(固定批次流程 0~5):
270
279
 
271
280
  | 批次 | 内容 | 说明 |
272
281
  |---|---|---|
273
282
  | **0 补字段** | 设计文档 §四 配套字段(`closer`/`closedate`/`canceler`/`canceldate` 等)buildMeta **不自动建** | 增量用 `decorate_ops(standard=True)` + `do_modify_meta` **脚本直调**(CLI 走 workspace standard 会拼前缀) |
274
- | **1 字段属性** | F 批次:org 职能+必录、客户/港口使用组织、币种默认 CNY、**汇率 5 项关联(传 UUID)**、单位关联物料、金额关联币种、必录日期缺省当天、金额族/状态族锁定、ViewDetail=false | `setProperties` / `setRefProps` / `setDefValueDesign` |
275
- | **2 面板布局** | 业务面板(`fs_financeinfo`/`fs_clause`/`fs_creator`)**不自动建**——所有字段初始堆在 `fs_baseinfo`(`runBatch` 的 `uiComposition` 步骤被前序阶段失败中止时尤其如此,见 cosmic-meta-api §9.2) | **优先 `applyFormComposition`**(0.0.299 定型命令:**一次创建多分区并归位字段**,字段用**显示名**,输入 `{sections:[{key,caption,rows:[{fields:[...]}]}]}`;2026-09-29 实测 43 ops 一次成功并独立验证);面板顺序用 `applyPanelOrder --input '{"order":[...]}'`。⚠️ 旧法 `modifyMeta` 手写 add/move op 属**已弃的低层路径**,仅在前者不覆盖时使用(move op:`target.value=字段key` + `extra.destination=面板key`;面板排序 `destination=contentpanel`+`index`) |
276
- | **3 状态族锁定** | `billstatus`/`auditor`/`auditdate`/`closer`/`closedate`/`canceler`/`canceldate` form 层全状态锁 | `setProperties {"Lock":"new,edit,view,submit,audit"}`(开发字段报假阴性,**以 getFormSchema formLayout 为准**) |
283
+ | **1 字段属性** | F 批次:org 职能+必录、客户/港口使用组织、币种默认 CNY、**汇率 5 项关联(传 UUID)**、单位关联物料、金额关联币种、必录日期缺省当天、金额族/状态族锁定、ViewDetail=false | `setProperties`(批量与锁定用 `--policy`;`--elementKey/--input` 对 Lock 报 `PROPERTY_READ_ONLY`)/ `setRefProps` / `setDefValueDesign` |
284
+ | **2 面板布局** | 业务面板(`fs_financeinfo`/`fs_clause`/`fs_creator`)**不自动建**——所有字段初始堆在 `fs_baseinfo`(`runBatch` 的 `uiComposition` 步骤被前序阶段失败中止时尤其如此,见 cosmic-meta-api §9.2) | **优先 `applyFormComposition`**(0.0.299 定型命令:**一次创建多分区并归位字段**,字段用**显示名**,输入 `{sections:[{key,caption,rows:[{fields:[...]}]}]}`;2026-09-29 实测 43 ops 一次成功并独立验证);面板顺序用 `applyPanelOrder --input '{"order":[...]}'`(`advconap` 也要进 `order`,见 §二)。⚠️ 旧法 `modifyMeta` 手写 add/move op 属**已弃的低层路径**,仅在前者不覆盖时使用(move op:`target.value=字段key` + `extra.destination=面板key`;面板排序 `destination=contentpanel`+`index`) |
285
+ | **3 状态族锁定** | `billstatus`/`auditor`/`auditdate`/`closer`/`closedate`/`canceler`/`canceldate` form 层全状态锁 | `setProperties --policy` 的 `{"set":{"Lock":"…"}}`(只走 `--policy`)。⚠️ 写 `submit,audit`(平台默认)时回执必报 `STATIC_FIELD_LOCK_READBACK_MISMATCH`(属确定性假阴性,写入已生效)——以 `formLayout.lock` 为准,不要重试;其它值均 `verified=true` |
277
286
  | **4 汇率/汇总** | `exchangerate` FireUpdEvt=true(含绑定 5 字段共 6 处);SummaryToField 金额三件套(input 写文件裸 JSON 字符串) | `setProperties` / `setSummaryToField` |
287
+ | **5 列表列** | buildMeta 后平台**按全部字段**建列;authoring 的 `listConfiguration` 只补列/设排序,**不裁剪、不排顺序**(实测声明 11 列得 37 列,且仍报 `verified`) | 要"只有这几列":`modifyMeta remove listcolumn` 删多余列 → `configureList` 按序补列(它只增不删,`order` 是排序不是列序);列序只能"全删后重建" |
278
288
 
279
289
  > **配套铁律**:
280
290
  > - buildMeta 后 formId 以 `discover`/`queryForms` **实时解析为准**(runBatch 响应 formId 不可信,moveForm 报 `FORM_NOT_FOUND`);
281
291
  > - 字段类型契约:**无 `BooleanField`**(布尔用 `CheckBoxField`);QtyField 必须 `unitFieldRef` 关联单位(见 cosmic-meta-api §8.1);
282
- > - 完整流程顺序:buildMeta → moveForm(归属功能分组)→ 批次 0~4 → getFormSchema 回读验证。
292
+ > - 完整流程顺序:authoring(显式 `templateKey`)→ runBatch(`bizUnitName` 在初始批次完成分组)→ 批次 0~5 → `getFormSchema` 回读验证。
283
293
 
284
294
  ---
285
295
 
@@ -53,7 +53,7 @@
53
53
 
54
54
  | 想做什么 | 标准写法 | 易错点 |
55
55
  |---|---|---|
56
- | 字段锁定 | `setProperties {"Lock":"new,edit,view,submit,audit"}`,**form 层(FieldAp)**(§2.1) | entity 层设置返回 success 但**不生效**;验证用 getFormSchema 读 formLayout 的 lock |
56
+ | 字段锁定 | `setProperties --policy`:`{"targets":{"fields":[...],"entities":["header"]},"set":{"Lock":"new,edit,submit,audit"}}`,**form 层(FieldAp)**(§2.1) | entity 层不生效;校验以 getFormSchema 的 formLayout.lock 为准 |
57
57
  | 列表列隐藏 | `modifyMeta` remove listcolumn `listcol_<fieldKey>`(§3.2) | `modify path=visible` 报「修改执行失败: null」不生效——用 remove 代替 |
58
58
  | 默认值 | `setProperties {"DefValue":"A"}` 或 `setDefValueDesign` | — |
59
59
  | 用户字段「查看详情」 | `setProperties {"ViewDetail": false}` | 制单信息面板用户字段默认关闭 |
@@ -74,27 +74,30 @@
74
74
  ### 2.1 setProperties(简单属性,最常用)
75
75
 
76
76
  ```bash
77
+ # 单元素(非 Lock 的简单属性)
77
78
  python cosmic_api.py setProperties --app-root <appRoot> --formNumber <表单> --elementKey <字段> --input <文件或JSON>
79
+ # 批量 / 字段锁定(Lock 只认这条路径)
80
+ python cosmic_api.py setProperties --app-root <appRoot> --form-name <表单> --policy <policy.json>
78
81
  ```
79
82
 
80
83
  **适用**:简单属性(editorType ≠ btnedit)——`Lock`、`DefValue`、`ViewDetail`、`FieldName`、`BackColor`、`Collapsible`、`Grow`/`Shrink` 等。
81
84
 
82
85
  **⚡ 关键坑(必读)**:
83
- 1. **`--input` 传属性映射本身**(`{"Lock": "new,edit,view,submit,audit"}`),**不要**包外层 `{"properties": {...}}`——包外层会报 `META_SAVE_FAIL`(本次实战踩过);
84
- 2. **字段锁定必须设置 form 层(FieldAp)才生效**:entity 层设置返回 success 但**不生效**(auditor 等开发字段 entity lock 仍为 null)——页面不可编辑依赖 form 层控件锁定;
85
- 3. 设置后用 `getProperties` 回读验证(`setProperty` 单属性快捷命令也可)。
86
+ 1. **`--input`(旧路径)传属性映射本身**(`{"Lock": "..."}`),**不要**包外层 `{"properties": {...}}`——包外层会报 `META_SAVE_FAIL`(本次实战踩过)。⚠️ **2026-10-19 复验:`--elementKey/--input` 对 `Lock` 已完全不可用**——业务字段与**模板字段都**恒报 `PROPERTY_READ_ONLY`;Lock 一律走 `--policy`,该条只对其它简单属性与旧版本有效;
87
+ 2. **字段锁定必须设置 form 层(FieldAp)才生效**:entity 层不生效(`getProperties` 读 entity 层恒为 null,正常)——页面不可编辑依赖 form 层控件锁定;
88
+ 3. 设置后按下方「锁定(Lock)验证方法」回读:**Lock 用 `getFormSchema`**,其它属性用 `getProperties`。
86
89
  4. **⚠️ 必填 `--app-root`(2026-08-25 实测)**:`setProperties`/`setComplexProperty` 缺 `--app-root` 报 `FORM_TARGET_UNVERIFIED: ... requires --app-root to prove form ownership`——所有写操作命令统一带 `--app-root <appRoot>`(modifyMeta 四参同款)。
87
90
 
88
- **⚡ 锁定(Lock)验证方法(2026-08-25 实测修正)**:
89
- - `setProperties {"Lock": ...}` 返回 success **不代表 entity 层已生效**——`getProperties --propertyNames Lock` 回读 entity 层 lock **仍为 null**(正常,entity 层本就不存);
90
- - **正确验证 = `getFormSchema` 读 formLayout 中对应 FieldAp 控件的 `lock` 字段**(如 `"lock": "new,edit,view,submit,audit"`)——form 层生效的唯一判据;
91
- - 切勿因 `getProperties` 读到 null 就误判失败重试(会做无用功);
92
- - ⚠️ **CLI 自身报错也是假阴性(2026-08-25 实测)**:`setProperties --elementKey <字段> --input '{"Lock":"..."}'` 对**业务/金额字段**会返回 `属性目标状态未满足,独立回读与请求值不一致`(其 verified 变体用 entity 层回读判败)——但 form 层 lock **实际已生效**。**以 formLayout 为准,勿因该报错重试**(仅模板自带字段如 billstatus/creator 的 entity 层有 lock,会返回 success)。
91
+ **⚡ 锁定(Lock)验证方法(2026-10-19 复验,覆盖旧结论)**:
92
+ - **写入只走 `setProperties --policy`**:`--elementKey/--input` 对 Lock 恒报 `PROPERTY_READ_ONLY`(模板字段同样被拒);
93
+ - **取值**:`new`/`edit`/`submit`/`audit`,顺序无关(CLI 会归一);
94
+ - **验证 = `getFormSchema` 读 formLayout 中对应 FieldAp 的 `lock`**——form 层生效的唯一判据(`getProperties` 读 entity 层恒为 null 属正常);
95
+ - ⚠️ **唯一需要特别注意的回执:请求值恰为 `submit,audit`**(= 平台默认锁定,新字段初始值)时,写入**已生效**,但回执**必报** `STATIC_FIELD_LOCK_READBACK_MISMATCH` / `outcome=unknown_after_write` / `actual:{"<字段>":""}`——因为平台元数据**省略"等于默认值"的 Lock 属性**,CLI 回读为空。**这是确定性假阴性,不要重试**,按 formLayout 复核即可;其它任意取值回执均 `verified=true`。
93
96
 
94
97
  **示例(字段锁定,全状态)**:
95
98
  ```bash
96
- # input: {"Lock": "new,edit,view,submit,audit"}
97
- python cosmic_api.py setProperties --app-root <appRoot> --formNumber sd_harbor --elementKey auditor --input lock.json
99
+ # policy: {"targets":{"fields":["auditor","auditdate"],"entities":["header"]},"set":{"Lock":"new,edit,submit,audit"}}
100
+ python cosmic_api.py setProperties --app-root <appRoot> --form-name sd_harbor --policy lock.json
98
101
  ```
99
102
 
100
103
  ### 2.2 setComplexProperty(复合/复杂属性)
@@ -63,7 +63,7 @@
63
63
  | 禁用人 | `disabler` | UserField [引用 `bos_user`] | 否 | 禁用后记录(框架自动写入) |
64
64
  | 禁用时间 | `disabledate` | DateTimeField | 否 | 禁用后记录(框架自动写入) |
65
65
 
66
- > 🔒 **锁定约束**:上述 4 个字段 + 制单信息面板的创建/修改字段(`creator`/`createtime`/`modifier`/`modifytime`)共 8 个,在**页面(form 层)锁定为 `new,edit,view,submit,audit`(全状态不可编辑)**——由框架自动写入,用户不可手改(属性按字段属性规范 **F.17** 用户字段 / **F.16** 长日期 / **F.18** 创建修改人套用;参考 `sd_agent` 同名字段配置)。
66
+ > 🔒 **锁定约束**:上述 4 个字段 + 制单信息面板的创建/修改字段(`creator`/`createtime`/`modifier`/`modifytime`)共 8 个,在**页面(form 层)锁定为 `new,edit,submit,audit`(全状态不可编辑)**——由框架自动写入,用户不可手改(属性按字段属性规范 **F.17** 用户字段 / **F.16** 长日期 / **F.18** 创建修改人套用;参考 `sd_agent` 同名字段配置)。
67
67
 
68
68
  ---
69
69