hap-cli 0.8.6__tar.gz → 0.8.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. {hap_cli-0.8.6 → hap_cli-0.8.8}/PKG-INFO +17 -23
  2. {hap_cli-0.8.6/hap_cli → hap_cli-0.8.8}/README.md +16 -22
  3. {hap_cli-0.8.6 → hap_cli-0.8.8/hap_cli}/README.md +16 -22
  4. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/README_CN.md +8 -16
  5. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/__init__.py +1 -1
  6. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/auth_cmd.py +49 -8
  7. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/icon_cmd.py +17 -11
  8. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/record_cmd.py +6 -1
  9. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/workflow_cmd.py +1 -1
  10. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/worksheet_cmd.py +19 -2
  11. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/action_spec_adapter.py +17 -6
  12. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/auth.py +6 -0
  13. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/chat.py +28 -2
  14. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/cli_access.py +81 -13
  15. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/editor/apply.py +12 -1
  16. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/record.py +114 -29
  17. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/session.py +31 -22
  18. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/update.py +3 -9
  19. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/upload.py +9 -5
  20. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/view_spec_adapter.py +61 -4
  21. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/workflow.py +34 -12
  22. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/workflow_node_dsl.py +124 -8
  23. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/worksheet.py +174 -14
  24. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/worksheet_templates.py +7 -1
  25. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_app_editor.py +20 -0
  26. hap_cli-0.8.8/hap_cli/tests/test_cli_access.py +663 -0
  27. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_core.py +681 -8
  28. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_update.py +4 -3
  29. hap_cli-0.8.8/hap_cli/tests/test_workflow_list_cli.py +73 -0
  30. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_worksheet_v3_semantic_cli.py +10 -4
  31. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli.egg-info/PKG-INFO +17 -23
  32. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli.egg-info/SOURCES.txt +1 -0
  33. hap_cli-0.8.6/hap_cli/tests/test_cli_access.py +0 -320
  34. {hap_cli-0.8.6 → hap_cli-0.8.8}/MANIFEST.in +0 -0
  35. {hap_cli-0.8.6 → hap_cli-0.8.8}/app_live_tests/__init__.py +0 -0
  36. {hap_cli-0.8.6 → hap_cli-0.8.8}/app_live_tests/__main__.py +0 -0
  37. {hap_cli-0.8.6 → hap_cli-0.8.8}/app_live_tests/config.py +0 -0
  38. {hap_cli-0.8.6 → hap_cli-0.8.8}/app_live_tests/harness.py +0 -0
  39. {hap_cli-0.8.6 → hap_cli-0.8.8}/app_live_tests/smoke.py +0 -0
  40. {hap_cli-0.8.6 → hap_cli-0.8.8}/app_live_tests/state.py +0 -0
  41. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/__main__.py +0 -0
  42. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/__init__.py +0 -0
  43. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/app_cmd.py +0 -0
  44. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/app_editor_cmd.py +0 -0
  45. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/calendar_cmd.py +0 -0
  46. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/chart_cmd.py +0 -0
  47. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/chat_cmd.py +0 -0
  48. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/chatbot_cmd.py +0 -0
  49. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/config_cmd.py +0 -0
  50. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/contact_cmd.py +0 -0
  51. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/department_cmd.py +0 -0
  52. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/group_cmd.py +0 -0
  53. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/instance_cmd.py +0 -0
  54. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/node_cmd.py +0 -0
  55. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/optionset_cmd.py +0 -0
  56. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/page_cmd.py +0 -0
  57. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/post_cmd.py +0 -0
  58. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/region_cmd.py +0 -0
  59. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/role_cmd.py +0 -0
  60. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/update_cmd.py +0 -0
  61. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/upload_cmd.py +0 -0
  62. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/commands/v3_registry.py +0 -0
  63. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/context.py +0 -0
  64. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/__init__.py +0 -0
  65. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/app.py +0 -0
  66. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/calendar_mod.py +0 -0
  67. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/chart.py +0 -0
  68. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/chatbot.py +0 -0
  69. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/contact.py +0 -0
  70. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/control_type_codes.py +0 -0
  71. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/department.py +0 -0
  72. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/editor/__init__.py +0 -0
  73. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/editor/_hapmeta/__init__.py +0 -0
  74. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/editor/_hapmeta/control_type_codes.py +0 -0
  75. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/editor/componentlower.py +0 -0
  76. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/editor/editspec.py +0 -0
  77. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/editor/errors.py +0 -0
  78. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/editor/fieldlower.py +0 -0
  79. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/editor/jsonschema_mini.py +0 -0
  80. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/editor/models.py +0 -0
  81. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/editor/ops.py +0 -0
  82. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/editor/planner.py +0 -0
  83. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/editor/reader.py +0 -0
  84. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/field_normalizer.py +0 -0
  85. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/field_spec_adapter.py +0 -0
  86. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/filter_translator.py +0 -0
  87. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/flow_node.py +0 -0
  88. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/global_meta.py +0 -0
  89. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/group.py +0 -0
  90. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/icon_index.py +0 -0
  91. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/instance.py +0 -0
  92. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/logger.py +0 -0
  93. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/optionset.py +0 -0
  94. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/page.py +0 -0
  95. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/post.py +0 -0
  96. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/response_crypto.py +0 -0
  97. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/role.py +0 -0
  98. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/role_perm_builder.py +0 -0
  99. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/token_crypto.py +0 -0
  100. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/v3/__init__.py +0 -0
  101. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/v3/dispatcher.py +0 -0
  102. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/v3/render.py +0 -0
  103. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/core/v3/schema.py +0 -0
  104. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/hap_cli.py +0 -0
  105. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/i18n.py +0 -0
  106. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/locale/__init__.py +0 -0
  107. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/locale/messages.json +0 -0
  108. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/locale/messages.schema.json +0 -0
  109. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/__init__.py +0 -0
  110. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/conftest.py +0 -0
  111. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_app_export_usage.py +0 -0
  112. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_auth_prerelease.py +0 -0
  113. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_bug_036430.py +0 -0
  114. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_chart.py +0 -0
  115. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_config_cmd.py +0 -0
  116. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_destructive_confirm_cli.py +0 -0
  117. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_full_e2e.py +0 -0
  118. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_global_meta.py +0 -0
  119. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_i18n.py +0 -0
  120. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_instance_history_cli.py +0 -0
  121. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_integration.py +0 -0
  122. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_integration_approval.py +0 -0
  123. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_integration_approval_actions.py +0 -0
  124. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_integration_calendar.py +0 -0
  125. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_integration_destructive.py +0 -0
  126. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_integration_misc.py +0 -0
  127. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_integration_post.py +0 -0
  128. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_integration_social.py +0 -0
  129. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_integration_v3.py +0 -0
  130. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_integration_workflow.py +0 -0
  131. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_integration_worksheet_extra.py +0 -0
  132. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_multi_profile.py +0 -0
  133. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_org_approval_v3_semantic_cli.py +0 -0
  134. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_org_id_cli.py +0 -0
  135. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_org_id_docs.py +0 -0
  136. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_parameter_conventions.py +0 -0
  137. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_parameter_mapping_registry.py +0 -0
  138. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_record_batch_v3_semantic_cli.py +0 -0
  139. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_record_field_alias.py +0 -0
  140. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_record_v3_semantic_cli.py +0 -0
  141. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_semantic_types_registry.py +0 -0
  142. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_v3_api_schema_loader.py +0 -0
  143. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_v3_dispatcher.py +0 -0
  144. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_v3_registry_coverage.py +0 -0
  145. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_v3_session.py +0 -0
  146. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_v3_yaml_translation.py +0 -0
  147. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_workflow_v3_semantic_cli.py +0 -0
  148. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/tests/test_worksheet_crud_cli.py +0 -0
  149. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/utils/__init__.py +0 -0
  150. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/utils/formatting.py +0 -0
  151. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/utils/options.py +0 -0
  152. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli/utils/parameter_mapping.py +0 -0
  153. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli.egg-info/dependency_links.txt +0 -0
  154. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli.egg-info/entry_points.txt +0 -0
  155. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli.egg-info/requires.txt +0 -0
  156. {hap_cli-0.8.6 → hap_cli-0.8.8}/hap_cli.egg-info/top_level.txt +0 -0
  157. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/__init__.py +0 -0
  158. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/__main__.py +0 -0
  159. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/_wftest.py +0 -0
  160. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/charts.py +0 -0
  161. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/cleanup.py +0 -0
  162. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/compiler.py +0 -0
  163. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/config.py +0 -0
  164. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/errors.py +0 -0
  165. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/executor.py +0 -0
  166. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/fields.py +0 -0
  167. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/hap.py +0 -0
  168. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/recording/__init__.py +0 -0
  169. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/recording/console.py +0 -0
  170. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/recording/jsonl.py +0 -0
  171. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/recording/mirror.py +0 -0
  172. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/recording/report.py +0 -0
  173. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/schema.py +0 -0
  174. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/seed/__init__.py +0 -0
  175. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/seed/cli.py +0 -0
  176. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/seed/executor.py +0 -0
  177. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/seed/template.py +0 -0
  178. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/selftest.py +0 -0
  179. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/smoke.py +0 -0
  180. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/step.py +0 -0
  181. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/steps.py +0 -0
  182. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/store.py +0 -0
  183. {hap_cli-0.8.6 → hap_cli-0.8.8}/live_tests/workflow_dsl.py +0 -0
  184. {hap_cli-0.8.6 → hap_cli-0.8.8}/setup.cfg +0 -0
  185. {hap_cli-0.8.6 → hap_cli-0.8.8}/setup.py +0 -0
  186. {hap_cli-0.8.6 → hap_cli-0.8.8}/skills/hap-cli-app-editor/scripts/editspec/component.schema.json +0 -0
  187. {hap_cli-0.8.6 → hap_cli-0.8.8}/skills/hap-cli-app-editor/scripts/editspec/custom-action.schema.json +0 -0
  188. {hap_cli-0.8.6 → hap_cli-0.8.8}/skills/hap-cli-app-editor/scripts/editspec/envelope.schema.json +0 -0
  189. {hap_cli-0.8.6 → hap_cli-0.8.8}/skills/hap-cli-app-editor/scripts/editspec/field.schema.json +0 -0
  190. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/INDEX.json +0 -0
  191. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/add_member_to_role.yaml +0 -0
  192. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/batch_delete_records.yaml +0 -0
  193. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/create_optionset.yaml +0 -0
  194. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/create_role.yaml +0 -0
  195. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/delete_optionset.yaml +0 -0
  196. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/delete_record.yaml +0 -0
  197. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/delete_role.yaml +0 -0
  198. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/delete_worksheet.yaml +0 -0
  199. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/get_app_info.yaml +0 -0
  200. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/get_app_knowledge_list.yaml +0 -0
  201. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/get_app_worksheets_list.yaml +0 -0
  202. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/get_optionset_list.yaml +0 -0
  203. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/get_record_details.yaml +0 -0
  204. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/get_record_discussions.yaml +0 -0
  205. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/get_record_list.yaml +0 -0
  206. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/get_record_logs.yaml +0 -0
  207. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/get_record_pivot_data.yaml +0 -0
  208. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/get_record_relations.yaml +0 -0
  209. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/get_record_share_link.yaml +0 -0
  210. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/get_regions.yaml +0 -0
  211. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/get_role_details.yaml +0 -0
  212. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/get_role_list.yaml +0 -0
  213. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/knowledge_search.yaml +0 -0
  214. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/leave_all_roles.yaml +0 -0
  215. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/remove_member_from_role.yaml +0 -0
  216. {hap_cli-0.8.6 → hap_cli-0.8.8}/sources/v3-api-schema/update_optionset.yaml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hap-cli
3
- Version: 0.8.6
3
+ Version: 0.8.8
4
4
  Summary: CLI harness for MingDAO HAP - Enterprise no-code platform
5
5
  Author: hap-cli
6
6
  License: Apache-2.0
@@ -40,6 +40,15 @@ pip install hap-cli
40
40
  The package ships with the v3 tool schemas it needs, so no extra setup is
41
41
  required after `pip install`.
42
42
 
43
+ ## Prerequisite: enable CLI access for your organization
44
+
45
+ **`hap` can only access an organization's data after the organization has
46
+ enabled CLI access.** Ask an organization administrator to turn on the
47
+ switch under Organization Admin → Security → Data & Access → CLI access
48
+ policy. Commands are blocked until it is enabled; once an administrator
49
+ turns it on, just re-run the command. Use `hap auth list-my-orgs` to see
50
+ each organization's status (`CLI:on/off`).
51
+
43
52
  ## Quick start
44
53
 
45
54
  ### 1. Login
@@ -102,8 +111,9 @@ hap app select APP_ID
102
111
  hap app unselect # clear it
103
112
  ```
104
113
 
105
- `hap auth set-current-org` only changes the default organization. The default app
106
- is managed independently with `hap app select` / `hap app unselect`.
114
+ `hap auth set-current-org` switches the default organization; moving to a
115
+ different organization also clears the default app (apps belong to an
116
+ organization). Pick a new one with `hap app select`.
107
117
 
108
118
  ### 3. Explore worksheets and records
109
119
 
@@ -140,8 +150,8 @@ discover every subcommand.
140
150
  | `auth use NAME` | Switch the environment/account used next |
141
151
  | `auth logout` | Log out the current account (`-p NAME` for a specific one, `-a/--all` for every one) |
142
152
  | `auth whoami` | Show current user, current environment/account, and current organization |
143
- | `auth list-my-orgs` | List every org for the current account (current marked `*`) |
144
- | `auth set-current-org ORG_ID` | Switch the saved current organization |
153
+ | `auth list-my-orgs` | List every org for the current account (current marked `*`; each row shows whether the org allows CLI access, `CLI:on/off`, checked live; omitted where the environment has no such switch) |
154
+ | `auth set-current-org ORG_ID` | Switch the saved current organization (clears the default app when the org changes) |
145
155
 
146
156
  ### app — application management
147
157
 
@@ -322,22 +332,6 @@ overrides the persisted level.
322
332
 
323
333
  ---
324
334
 
325
- ## Organization CLI access control
326
-
327
- Organizations can control whether CLI tools are allowed to call their
328
- APIs. Before each command runs, `hap` checks this setting for the
329
- current organization:
330
-
331
- - **Enabled** — the command runs normally; the result is remembered for
332
- 5 minutes, so back-to-back commands stay fast.
333
- - **Disabled** — the command is blocked with a message asking you to
334
- contact an organization administrator to enable CLI access.
335
- - **Setting not available** (older server versions) — the command runs
336
- normally; the check is retried about once an hour.
337
-
338
- If an administrator enables access after a command was blocked, just
339
- re-run the command — the change takes effect immediately.
340
-
341
335
  ## Default app & organization
342
336
 
343
337
  Every command that needs an `--app-id` resolves it in this order:
@@ -346,8 +340,8 @@ Every command that needs an `--app-id` resolves it in this order:
346
340
  2. The default app saved by `hap app select`;
347
341
  3. Otherwise the command exits with an error suggesting `hap app select APP_ID`.
348
342
 
349
- `hap auth set-current-org` changes the default *organization* only it does not
350
- touch the default app.
343
+ `hap auth set-current-org` switches the default *organization*; switching to a
344
+ different organization also clears the default app.
351
345
 
352
346
  ## REPL mode
353
347
 
@@ -11,6 +11,15 @@ pip install hap-cli
11
11
  The package ships with the v3 tool schemas it needs, so no extra setup is
12
12
  required after `pip install`.
13
13
 
14
+ ## Prerequisite: enable CLI access for your organization
15
+
16
+ **`hap` can only access an organization's data after the organization has
17
+ enabled CLI access.** Ask an organization administrator to turn on the
18
+ switch under Organization Admin → Security → Data & Access → CLI access
19
+ policy. Commands are blocked until it is enabled; once an administrator
20
+ turns it on, just re-run the command. Use `hap auth list-my-orgs` to see
21
+ each organization's status (`CLI:on/off`).
22
+
14
23
  ## Quick start
15
24
 
16
25
  ### 1. Login
@@ -73,8 +82,9 @@ hap app select APP_ID
73
82
  hap app unselect # clear it
74
83
  ```
75
84
 
76
- `hap auth set-current-org` only changes the default organization. The default app
77
- is managed independently with `hap app select` / `hap app unselect`.
85
+ `hap auth set-current-org` switches the default organization; moving to a
86
+ different organization also clears the default app (apps belong to an
87
+ organization). Pick a new one with `hap app select`.
78
88
 
79
89
  ### 3. Explore worksheets and records
80
90
 
@@ -111,8 +121,8 @@ discover every subcommand.
111
121
  | `auth use NAME` | Switch the environment/account used next |
112
122
  | `auth logout` | Log out the current account (`-p NAME` for a specific one, `-a/--all` for every one) |
113
123
  | `auth whoami` | Show current user, current environment/account, and current organization |
114
- | `auth list-my-orgs` | List every org for the current account (current marked `*`) |
115
- | `auth set-current-org ORG_ID` | Switch the saved current organization |
124
+ | `auth list-my-orgs` | List every org for the current account (current marked `*`; each row shows whether the org allows CLI access, `CLI:on/off`, checked live; omitted where the environment has no such switch) |
125
+ | `auth set-current-org ORG_ID` | Switch the saved current organization (clears the default app when the org changes) |
116
126
 
117
127
  ### app — application management
118
128
 
@@ -293,22 +303,6 @@ overrides the persisted level.
293
303
 
294
304
  ---
295
305
 
296
- ## Organization CLI access control
297
-
298
- Organizations can control whether CLI tools are allowed to call their
299
- APIs. Before each command runs, `hap` checks this setting for the
300
- current organization:
301
-
302
- - **Enabled** — the command runs normally; the result is remembered for
303
- 5 minutes, so back-to-back commands stay fast.
304
- - **Disabled** — the command is blocked with a message asking you to
305
- contact an organization administrator to enable CLI access.
306
- - **Setting not available** (older server versions) — the command runs
307
- normally; the check is retried about once an hour.
308
-
309
- If an administrator enables access after a command was blocked, just
310
- re-run the command — the change takes effect immediately.
311
-
312
306
  ## Default app & organization
313
307
 
314
308
  Every command that needs an `--app-id` resolves it in this order:
@@ -317,8 +311,8 @@ Every command that needs an `--app-id` resolves it in this order:
317
311
  2. The default app saved by `hap app select`;
318
312
  3. Otherwise the command exits with an error suggesting `hap app select APP_ID`.
319
313
 
320
- `hap auth set-current-org` changes the default *organization* only it does not
321
- touch the default app.
314
+ `hap auth set-current-org` switches the default *organization*; switching to a
315
+ different organization also clears the default app.
322
316
 
323
317
  ## REPL mode
324
318
 
@@ -11,6 +11,15 @@ pip install hap-cli
11
11
  The package ships with the v3 tool schemas it needs, so no extra setup is
12
12
  required after `pip install`.
13
13
 
14
+ ## Prerequisite: enable CLI access for your organization
15
+
16
+ **`hap` can only access an organization's data after the organization has
17
+ enabled CLI access.** Ask an organization administrator to turn on the
18
+ switch under Organization Admin → Security → Data & Access → CLI access
19
+ policy. Commands are blocked until it is enabled; once an administrator
20
+ turns it on, just re-run the command. Use `hap auth list-my-orgs` to see
21
+ each organization's status (`CLI:on/off`).
22
+
14
23
  ## Quick start
15
24
 
16
25
  ### 1. Login
@@ -73,8 +82,9 @@ hap app select APP_ID
73
82
  hap app unselect # clear it
74
83
  ```
75
84
 
76
- `hap auth set-current-org` only changes the default organization. The default app
77
- is managed independently with `hap app select` / `hap app unselect`.
85
+ `hap auth set-current-org` switches the default organization; moving to a
86
+ different organization also clears the default app (apps belong to an
87
+ organization). Pick a new one with `hap app select`.
78
88
 
79
89
  ### 3. Explore worksheets and records
80
90
 
@@ -111,8 +121,8 @@ discover every subcommand.
111
121
  | `auth use NAME` | Switch the environment/account used next |
112
122
  | `auth logout` | Log out the current account (`-p NAME` for a specific one, `-a/--all` for every one) |
113
123
  | `auth whoami` | Show current user, current environment/account, and current organization |
114
- | `auth list-my-orgs` | List every org for the current account (current marked `*`) |
115
- | `auth set-current-org ORG_ID` | Switch the saved current organization |
124
+ | `auth list-my-orgs` | List every org for the current account (current marked `*`; each row shows whether the org allows CLI access, `CLI:on/off`, checked live; omitted where the environment has no such switch) |
125
+ | `auth set-current-org ORG_ID` | Switch the saved current organization (clears the default app when the org changes) |
116
126
 
117
127
  ### app — application management
118
128
 
@@ -293,22 +303,6 @@ overrides the persisted level.
293
303
 
294
304
  ---
295
305
 
296
- ## Organization CLI access control
297
-
298
- Organizations can control whether CLI tools are allowed to call their
299
- APIs. Before each command runs, `hap` checks this setting for the
300
- current organization:
301
-
302
- - **Enabled** — the command runs normally; the result is remembered for
303
- 5 minutes, so back-to-back commands stay fast.
304
- - **Disabled** — the command is blocked with a message asking you to
305
- contact an organization administrator to enable CLI access.
306
- - **Setting not available** (older server versions) — the command runs
307
- normally; the check is retried about once an hour.
308
-
309
- If an administrator enables access after a command was blocked, just
310
- re-run the command — the change takes effect immediately.
311
-
312
306
  ## Default app & organization
313
307
 
314
308
  Every command that needs an `--app-id` resolves it in this order:
@@ -317,8 +311,8 @@ Every command that needs an `--app-id` resolves it in this order:
317
311
  2. The default app saved by `hap app select`;
318
312
  3. Otherwise the command exits with an error suggesting `hap app select APP_ID`.
319
313
 
320
- `hap auth set-current-org` changes the default *organization* only it does not
321
- touch the default app.
314
+ `hap auth set-current-org` switches the default *organization*; switching to a
315
+ different organization also clears the default app.
322
316
 
323
317
  ## REPL mode
324
318
 
@@ -10,6 +10,10 @@ pip install hap-cli
10
10
 
11
11
  安装包内已附带 CLI 启动需要的 v3 工具 schema,`pip install` 之后无需额外配置。
12
12
 
13
+ ## 使用前提:开启组织的 CLI 访问权限
14
+
15
+ **只有组织开启了 CLI 访问权限,`hap` 才能访问该组织的数据。** 请组织管理员前往「组织管理后台 → 安全 → 数据与访问 → CLI 访问策略」开启允许访问开关。未开启时命令会被拦截;管理员开启后直接重跑命令即可。可用 `hap auth list-my-orgs` 查看各组织的开启状态(`CLI:on/off`)。
16
+
13
17
  ## 快速上手
14
18
 
15
19
  ### 1. 登录
@@ -67,7 +71,7 @@ hap app select APP_ID
67
71
  hap app unselect # 清除默认应用
68
72
  ```
69
73
 
70
- `hap auth set-current-org` 只切换默认组织,不会改写默认应用。默认应用通过 `hap app select` / `hap app unselect` 单独管理。
74
+ `hap auth set-current-org` 切换默认组织;切换到不同组织时会同时清除默认应用(应用从属于组织)。之后用 `hap app select` 重新选择默认应用。
71
75
 
72
76
  ### 3. 浏览工作表与记录
73
77
 
@@ -102,8 +106,8 @@ hap --json worksheet record list WORKSHEET_ID
102
106
  | `auth use NAME` | 切换当前使用的环境/账号 |
103
107
  | `auth logout` | 登出当前账号(`-p NAME` 指定,`-a/--all` 全部) |
104
108
  | `auth whoami` | 当前用户、当前环境/账号与当前组织 |
105
- | `auth list-my-orgs` | 当前账号所属组织(当前组织标 `*`) |
106
- | `auth set-current-org ORG_ID` | 切换默认组织 |
109
+ | `auth list-my-orgs` | 当前账号所属组织(当前组织标 `*`,并实时显示各组织是否开启 CLI 访问权限 `CLI:on/off`,环境不支持该开关时不显示) |
110
+ | `auth set-current-org ORG_ID` | 切换默认组织(切到不同组织时会清除默认应用) |
107
111
 
108
112
  ### app — 应用管理
109
113
 
@@ -269,18 +273,6 @@ hap --json worksheet record list WORKSHEET_ID
269
273
 
270
274
  ---
271
275
 
272
- ## 组织 CLI 访问控制
273
-
274
- 组织可以控制是否允许 CLI 工具调用其接口。每条命令运行前,`hap`
275
- 会检查当前组织的这项设置:
276
-
277
- - **已开启** — 命令正常执行;结果保留 5 分钟,连续命令不会变慢。
278
- - **已关闭** — 命令被拦截,并提示联系组织管理员开启 CLI 访问权限。
279
- - **服务器暂不支持该设置**(旧版本环境)— 命令正常执行,约每小时
280
- 重试一次检查。
281
-
282
- 如果命令被拦后管理员开启了权限,直接重跑命令即可,立即生效。
283
-
284
276
  ## 默认应用与组织
285
277
 
286
278
  任何需要 `--app-id` 的命令解析顺序:
@@ -289,7 +281,7 @@ hap --json worksheet record list WORKSHEET_ID
289
281
  2. 否则使用 `hap app select APP_ID` 保存的默认应用;
290
282
  3. 仍为空时报错并提示设置默认应用。
291
283
 
292
- `hap auth set-current-org` 切换的是默认**组织**,**不**会改默认应用。
284
+ `hap auth set-current-org` 切换默认**组织**;切到不同组织时会同时清除默认应用。
293
285
 
294
286
  ## REPL 模式
295
287
 
@@ -1,3 +1,3 @@
1
1
  """CLI harness for MingDAO HAP (hap-cli)."""
2
2
 
3
- __version__ = "0.8.6"
3
+ __version__ = "0.8.8"
@@ -102,6 +102,21 @@ def _save_and_report(ctx, token, webui, user_info, meta, profile_name):
102
102
  session.save(profile=profile_name)
103
103
  set_active_profile(profile_name)
104
104
 
105
+ # Probe the org CLI-access switch for the org we just saved as
106
+ # current, so the user learns right away that commands will be
107
+ # blocked. Only an explicit "off" verdict prints the warning
108
+ # (404 / network trouble stays silent — same fail-open policy as
109
+ # the request gate). Covers all login paths (browser, paste,
110
+ # --token), unlike the browser success page.
111
+ from hap_cli.core import cli_access
112
+
113
+ access_denied = False
114
+ if cli_access.GATE_ENABLED and current_org.get("projectId"):
115
+ access_denied = (
116
+ cli_access.probe_cli_access(webui, token, current_org["projectId"])
117
+ is False
118
+ )
119
+
105
120
  data = {
106
121
  "status": "ok",
107
122
  "profile": profile_name,
@@ -109,17 +124,24 @@ def _save_and_report(ctx, token, webui, user_info, meta, profile_name):
109
124
  "user": user_info,
110
125
  "current_org": current_org,
111
126
  }
112
- ctx.output(
113
- data,
114
- lambda d: click.echo(
127
+ if access_denied:
128
+ data["cli_access_denied"] = True
129
+
130
+ def _human(_d):
131
+ click.echo(
115
132
  f"Logged in as: {user_info.get('name', '')} "
116
133
  f"({user_info.get('email', '')})\n"
117
134
  f"Saved as: {profile_name}\n"
118
135
  f"Server: {webui}\n"
119
136
  f"Current org: {current_org.get('projectId', '')} "
120
137
  f"{current_org.get('companyName', '')}".rstrip()
121
- ),
122
- )
138
+ )
139
+ if access_denied:
140
+ # Deliberately NOT localized: the surrounding login summary
141
+ # is English-only, so this line stays English too.
142
+ click.echo(f"Error: {cli_access.DENIED_MESSAGE_EN}")
143
+
144
+ ctx.output(data, _human)
123
145
 
124
146
 
125
147
  @auth.command("login")
@@ -290,17 +312,33 @@ def _print_orgs(session, data):
290
312
  pid = p.get("projectId", "")
291
313
  name = p.get("companyName", p.get("name", ""))
292
314
  role = p.get("roleName", "")
293
- marker = "*" if pid and pid == current_org_id else " "
294
- click.echo(f"{marker} {pid} {name} {role}".rstrip())
315
+ # Only render the CLI column when the server gave an explicit
316
+ # verdict; environments without the org switch show no column.
317
+ enabled = p.get("cliAccessEnabled")
318
+ cli_col = ""
319
+ if isinstance(enabled, bool):
320
+ cli_col = "CLI:on" if enabled else "CLI:off"
321
+ click.echo(
322
+ f"{'*' if pid and pid == current_org_id else ' '} "
323
+ f"{pid} {name} {role} {cli_col}".rstrip()
324
+ )
295
325
 
296
326
 
297
327
  @auth.command("list-my-orgs")
298
328
  @pass_context
299
329
  def auth_list_my_orgs(ctx):
300
- """List all organizations the current user belongs to."""
330
+ """List all organizations the current user belongs to.
331
+
332
+ Each row also shows whether the organization currently allows
333
+ CLI access (checked live against the server).
334
+ """
301
335
  try:
336
+ from hap_cli.core import cli_access
337
+
302
338
  session = ctx.get_session()
303
339
  data = auth_mod.list_my_orgs(session)
340
+ if cli_access.GATE_ENABLED:
341
+ cli_access.annotate_orgs_cli_access(session, data)
304
342
  ctx.output(data, lambda d: _print_orgs(session, d))
305
343
  except Exception as e:
306
344
  ctx.handle_error(e)
@@ -314,6 +352,9 @@ def auth_set_current_org(ctx, org_id):
314
352
 
315
353
  Run 'hap auth list-my-orgs' first to see the organizations you
316
354
  belong to and their IDs.
355
+
356
+ Switching to a different organization also clears the saved
357
+ default app — pick a new one with 'hap app select' afterwards.
317
358
  """
318
359
  try:
319
360
  session = ctx.get_session()
@@ -31,9 +31,10 @@ def _icon_table(rows):
31
31
  @click.option(
32
32
  "--limit",
33
33
  type=int,
34
- default=20,
35
- show_default=True,
36
- help="Maximum number of icons to return.",
34
+ default=None,
35
+ help="Maximum number of icons to return. Caps the result exactly — "
36
+ "--limit 5 returns at most 5. Defaults to 20 for a keyword search, "
37
+ "or the whole catalogue when browsing with no keyword.",
37
38
  )
38
39
  @pass_context
39
40
  def icon_search(ctx, query, limit):
@@ -41,19 +42,24 @@ def icon_search(ctx, query, limit):
41
42
 
42
43
  Pass one or more keywords; an icon must relate to every keyword to
43
44
  match. With no keyword, lists the whole catalogue. When fewer than
44
- 10 icons match, random suggestions top the list up to 10 so you
45
- always have something to pick from. Use the returned icon name with
46
- the --icon option of app/worksheet creation.
45
+ 10 icons match, random suggestions top the list up to 10 (never more
46
+ than --limit) so you always have something to pick from. Use the
47
+ returned icon name with the --icon option of app/worksheet creation.
47
48
  """
48
49
  try:
49
- # With no keyword the command acts as "browse all"; the limit
50
- # only narrows an actual keyword search.
51
- effective_limit = limit if query else None
52
- rows = ic_mod.search_icons(list(query), limit=effective_limit)
53
50
  if query:
51
+ # Keyword search: default to 20 matches; an explicit --limit
52
+ # is the exact upper bound, and the random-suggestion floor
53
+ # never exceeds it either.
54
+ effective_limit = limit if limit is not None else 20
55
+ rows = ic_mod.search_icons(list(query), limit=effective_limit)
54
56
  rows = ic_mod.pad_with_random_icons(
55
- rows, target=min(10, max(0, limit))
57
+ rows, target=min(10, max(0, effective_limit))
56
58
  )
59
+ else:
60
+ # Browse all by default; honor an explicit --limit if given.
61
+ # search_icons treats None as "no truncation".
62
+ rows = ic_mod.search_icons(list(query), limit=limit)
57
63
  ctx.output(rows, _icon_table)
58
64
  except Exception as e:
59
65
  ctx.handle_error(e)
@@ -155,6 +155,10 @@ def record_update(ctx, worksheet_id, row_id, field, fields_json, no_workflow):
155
155
 
156
156
  Pass values either as repeated -f CONTROL_ID=VALUE pairs or as one
157
157
  --fields-json array.
158
+
159
+ A sub-table value is the full list of child rows (each a dict keyed
160
+ by child field name) and replaces the existing rows; an empty list
161
+ clears the sub-table.
158
162
  """
159
163
  if field and fields_json:
160
164
  raise click.UsageError("Pass exactly one of -f or --fields-json.")
@@ -164,7 +168,8 @@ def record_update(ctx, worksheet_id, row_id, field, fields_json, no_workflow):
164
168
  raw = _fields_json_to_raw(fields_json)
165
169
  else:
166
170
  raw = _parse_fields(field)
167
- controls = rec_mod.encode_controls_by_id(session, worksheet_id, raw)
171
+ controls = rec_mod.encode_controls_by_id(
172
+ session, worksheet_id, raw, for_update=True)
168
173
  data = rec_mod.update_record(
169
174
  session, worksheet_id, row_id, controls,
170
175
  trigger_workflow=not no_workflow,
@@ -63,7 +63,7 @@ def workflow_list(ctx, app_id, keyword, enabled, page_size, page):
63
63
  if not aid:
64
64
  raise click.UsageError("App ID required.")
65
65
  result = wf_mod.get_process_list(
66
- session, aid, keyword=keyword,
66
+ session, aid, keyword=keyword, enabled=enabled,
67
67
  page_index=page, page_size=page_size,
68
68
  )
69
69
  ctx.output(
@@ -605,17 +605,34 @@ def worksheet_delete_view(ctx, worksheet_id, view_id, app_id, yes):
605
605
  help="Comma-separated advancedSetting sub-keys to update "
606
606
  "(narrows an advancedSetting edit so unrelated "
607
607
  "settings survive).")
608
+ @click.option("--view-spec", default="",
609
+ help="High-level view JSON (same shape as 'view create "
610
+ "--view-spec') applied onto this existing view. "
611
+ "Everything the spec expresses is updated; other "
612
+ "settings are preserved. Field references may be "
613
+ "names, aliases or control IDs. When given, the "
614
+ "other options are ignored.")
608
615
  @click.option("--app-id", "-a", default="", help="Application ID")
609
616
  @pass_context
610
617
  def worksheet_update_view(ctx, worksheet_id, view_id, name, view_json,
611
- edit_attrs, edit_ad_keys, app_id):
618
+ edit_attrs, edit_ad_keys, view_spec, app_id):
612
619
  """Update a view's properties in place.
613
620
 
614
621
  Only the attributes named in --edit-attrs are changed; all other
615
622
  view settings are left as they are. For a simple rename, just pass
616
- --name.
623
+ --name. To rewrite the view from a high-level description (grouping,
624
+ filters, quick filters, left-nav categories, cards, action buttons),
625
+ pass --view-spec.
617
626
  """
618
627
  try:
628
+ if view_spec:
629
+ session = ctx.get_session()
630
+ data = ws_mod.update_view_spec(
631
+ session, worksheet_id, view_id, json.loads(view_spec),
632
+ app_id=app_id,
633
+ )
634
+ ctx.output(data, lambda d: output_json(d))
635
+ return
619
636
  view: dict = json.loads(view_json) if view_json else {}
620
637
  attrs = [a.strip() for a in edit_attrs.split(",") if a.strip()]
621
638
  if name:
@@ -28,10 +28,14 @@ Wire semantics (authoritative: pd-openweb
28
28
  * ``filters`` — the enableWhen gating condition (same wire shape as a
29
29
  view filter; built via ``filter_translator``)
30
30
 
31
- Every button, regardless of type, gets a behind-the-scenes "shadow"
32
- workflow on the server. Its ``processId`` (and trigger node id) is
33
- fetched after creation via
34
- ``GET /workflow/process/getProcessByTriggerId?appId=&triggerId=<btnId>``.
31
+ A button that drives a workflow (``clickType`` 1 or ``workflowType`` 1)
32
+ gets a behind-the-scenes "shadow" workflow on the server. Its
33
+ ``processId`` (and trigger node id) is resolved after creation via
34
+ ``GET /workflow/process/getProcessByTriggerId?appId=&triggerId=<btnId>``
35
+ — note that GET lazily *creates* the shadow process when missing, so it
36
+ must only be called for workflow-driving buttons (the frontend gates it
37
+ the same way: CreateCustomBtn.jsx ``getProcessByTriggerId``, and skips
38
+ the editor entirely for 填写指定内容+不执行 buttons).
35
39
  """
36
40
  from __future__ import annotations
37
41
 
@@ -62,19 +66,24 @@ def build_button_payload(spec: dict[str, Any]) -> dict[str, Any]:
62
66
  # wins. Evidence: sources/v3-design/2026-06-10-mcp-tools/
63
67
  # mcp_json_schema.json#create_custom_actions.
64
68
  "desc": spec.get("desc", spec.get("remark", "")),
65
- # workflowType 1 = the button drives a (shadow) worksheet workflow.
66
- "workflowType": 1,
67
69
  "isAllView": spec.get("isAllView", 1),
68
70
  }
69
71
 
70
72
  confirm = spec.get("confirm")
71
73
  confirm_msg = spec.get("confirmMsg")
72
74
 
75
+ # workflowType: 1 = 执行(按钮驱动一条 shadow 工作流) · 2 = 不执行。
76
+ # Fill-type buttons default to 2 (no workflow) — the frontend only
77
+ # creates the shadow process for clickType 1 / workflowType 1 buttons
78
+ # (CreateCustomBtn.jsx:353 "创建时,除'填写指定内容+不执行'外,直接进入
79
+ # 编辑流"). triggerWorkflow buttons are exactly the workflow-driving
80
+ # kind, so they keep 1. runWorkflowAfterSubmit (below) overrides.
73
81
  if action_type == "updateCurrentRecord":
74
82
  # 填写本记录字段。
75
83
  out["clickType"] = 3
76
84
  out["writeType"] = 1
77
85
  out["writeObject"] = 1
86
+ out["workflowType"] = 2
78
87
  out["writeControls"] = [
79
88
  {"controlId": cid, "type": _WRITE_CONTROL_FILL}
80
89
  for cid in (spec.get("updateFields") or [])
@@ -84,6 +93,7 @@ def build_button_payload(spec: dict[str, Any]) -> dict[str, Any]:
84
93
  out["clickType"] = 3
85
94
  out["writeType"] = 2
86
95
  out["writeObject"] = 2
96
+ out["workflowType"] = 2
87
97
  rel = spec.get("relationField", "")
88
98
  out["addRelationControlId"] = rel
89
99
  out["relationControl"] = spec.get("relationControl", "")
@@ -92,6 +102,7 @@ def build_button_payload(spec: dict[str, Any]) -> dict[str, Any]:
92
102
  out["clickType"] = 2 if (confirm or confirm_msg) else 1
93
103
  out["writeType"] = ""
94
104
  out["writeObject"] = ""
105
+ out["workflowType"] = 1
95
106
 
96
107
  # 二次确认文案(任意类型都可带)。
97
108
  if confirm or confirm_msg:
@@ -264,6 +264,12 @@ def switch_org(session, org_id: str) -> dict:
264
264
  orgs = list_my_orgs(session)
265
265
  for org in orgs:
266
266
  if org.get("projectId") == org_id:
267
+ # Apps live inside an organization, so a default app saved
268
+ # under the previous org is meaningless (or worse, wrong)
269
+ # after the switch — drop it. A no-op "switch" to the org
270
+ # already current keeps the default app.
271
+ if session.default_project_id != org_id:
272
+ session.default_app_id = ""
267
273
  session.default_project_id = org_id
268
274
  # Refresh routing table + default org name from the server of
269
275
  # record. Failures here should NOT block the org switch — the
@@ -37,6 +37,13 @@ def _chatmq_get(
37
37
 
38
38
  from hap_cli.core.session import hap_user_agent
39
39
 
40
+ # Chat is a cross-org service (sessions span networks), so chatmq has
41
+ # no org of its own to check — the CLI access gate runs against the
42
+ # CURRENT org instead, same as ``Session._post``. Lazy import to
43
+ # mirror the other transport hooks.
44
+ from hap_cli.core import cli_access
45
+
46
+ cli_access.ensure_before_request(session, url)
40
47
  headers = {
41
48
  "Authorization": f"md_pss_id {session.auth_token}",
42
49
  "X-Requested-With": "XMLHttpRequest",
@@ -389,6 +396,14 @@ def _socket_emit(
389
396
  return None
390
397
 
391
398
  ws_base = session.chat_ws_base()
399
+ # Chat is a cross-org service, so the websocket channel is gated
400
+ # against the CURRENT org (same policy as ``_chatmq_get``). The gate
401
+ # runs OUTSIDE the strict/swallow try below: a policy denial must
402
+ # propagate even for fire-and-forget emits, unlike transport errors.
403
+ from hap_cli.core import cli_access
404
+ from hap_cli.core.session import hap_user_agent
405
+
406
+ cli_access.ensure_before_request(session, ws_base)
392
407
  # pd-openweb passes the session token as a `pss_id` query string on
393
408
  # the socket.io handshake (src/socket/index.js -> `query: { pss_id }`).
394
409
  connect_url = f"{ws_base}?pss_id={session.auth_token}"
@@ -400,6 +415,7 @@ def _socket_emit(
400
415
  connect_url,
401
416
  socketio_path="/mds2",
402
417
  transports=["websocket"],
418
+ headers={"User-Agent": hap_user_agent()},
403
419
  wait_timeout=10,
404
420
  )
405
421
  logger.info("SOCKET emit %r payload=%s", event, payload)
@@ -407,10 +423,20 @@ def _socket_emit(
407
423
  logger.info("SOCKET %r -> ack=%s", event, ack)
408
424
  return ack
409
425
  except Exception as exc:
426
+ # engineio masks the underlying handshake failure (TLS verify,
427
+ # proxy, 4xx upgrade rejection) behind a generic 'Connection
428
+ # error' — log with exc_info so the chained original exception
429
+ # lands in the log for diagnosis.
410
430
  if strict:
411
- logger.error("Failed to emit %s payload=%s: %s", event, payload, exc)
431
+ logger.error(
432
+ "Failed to emit %s payload=%s: %s", event, payload, exc,
433
+ exc_info=True,
434
+ )
412
435
  raise
413
- logger.warning("Failed to emit %s payload=%s: %s", event, payload, exc)
436
+ logger.warning(
437
+ "Failed to emit %s payload=%s: %s", event, payload, exc,
438
+ exc_info=True,
439
+ )
414
440
  return None
415
441
  finally:
416
442
  try: