hap-cli 0.9.8__tar.gz → 0.9.9__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 (419) hide show
  1. {hap_cli-0.9.8 → hap_cli-0.9.9}/PKG-INFO +1 -1
  2. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/__init__.py +1 -1
  3. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/chat_cmd.py +118 -13
  4. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/upload.py +13 -2
  5. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/en/messages.md +1 -1
  6. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/zh-Hans/messages.md +1 -1
  7. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/locale/messages.json +44 -20
  8. hap_cli-0.9.9/hap_cli/tests/test_chat_args_and_tables.py +106 -0
  9. hap_cli-0.9.9/hap_cli/tests/test_command_catalog_in_sync.py +40 -0
  10. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_upload_mdpublic_parity.py +32 -0
  11. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli.egg-info/PKG-INFO +1 -1
  12. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli.egg-info/SOURCES.txt +2 -0
  13. {hap_cli-0.9.8 → hap_cli-0.9.9}/MANIFEST.in +0 -0
  14. {hap_cli-0.9.8 → hap_cli-0.9.9}/README.md +0 -0
  15. {hap_cli-0.9.8 → hap_cli-0.9.9}/app_live_tests/__init__.py +0 -0
  16. {hap_cli-0.9.8 → hap_cli-0.9.9}/app_live_tests/__main__.py +0 -0
  17. {hap_cli-0.9.8 → hap_cli-0.9.9}/app_live_tests/config.py +0 -0
  18. {hap_cli-0.9.8 → hap_cli-0.9.9}/app_live_tests/fixtures/__init__.py +0 -0
  19. {hap_cli-0.9.8 → hap_cli-0.9.9}/app_live_tests/fixtures/feedback_scenario.py +0 -0
  20. {hap_cli-0.9.8 → hap_cli-0.9.9}/app_live_tests/harness.py +0 -0
  21. {hap_cli-0.9.8 → hap_cli-0.9.9}/app_live_tests/smoke.py +0 -0
  22. {hap_cli-0.9.8 → hap_cli-0.9.9}/app_live_tests/state.py +0 -0
  23. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/README.md +0 -0
  24. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/README_CN.md +0 -0
  25. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/__main__.py +0 -0
  26. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/_entry.py +0 -0
  27. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/__init__.py +0 -0
  28. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/app_cmd.py +0 -0
  29. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/app_creator_cmd.py +0 -0
  30. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/app_editor_cmd.py +0 -0
  31. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/attachment_cmd.py +0 -0
  32. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/auth_cmd.py +0 -0
  33. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/calendar_cmd.py +0 -0
  34. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/chart_cmd.py +0 -0
  35. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/chatbot_cmd.py +0 -0
  36. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/config_cmd.py +0 -0
  37. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/contact_cmd.py +0 -0
  38. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/department_cmd.py +0 -0
  39. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/group_cmd.py +0 -0
  40. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/guide_cmd.py +0 -0
  41. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/icon_cmd.py +0 -0
  42. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/instance_cmd.py +0 -0
  43. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/node_cmd.py +0 -0
  44. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/optionset_cmd.py +0 -0
  45. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/page_cmd.py +0 -0
  46. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/post_cmd.py +0 -0
  47. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/record_cmd.py +0 -0
  48. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/region_cmd.py +0 -0
  49. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/role_cmd.py +0 -0
  50. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/update_cmd.py +0 -0
  51. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/upload_cmd.py +0 -0
  52. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/v3_registry.py +0 -0
  53. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/workflow_cmd.py +0 -0
  54. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/commands/worksheet_cmd.py +0 -0
  55. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/context.py +0 -0
  56. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/__init__.py +0 -0
  57. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/action_spec_adapter.py +0 -0
  58. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app.py +0 -0
  59. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/__init__.py +0 -0
  60. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/_hapmeta/__init__.py +0 -0
  61. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/_hapmeta/control_type_codes.py +0 -0
  62. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/_hapmeta/worksheet_templates.py +0 -0
  63. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/charts.py +0 -0
  64. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/cleanup.py +0 -0
  65. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/compiler.py +0 -0
  66. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/config.py +0 -0
  67. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/design/design.schema.json +0 -0
  68. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/errors.py +0 -0
  69. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/examples/minimal.design.json +0 -0
  70. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/executor.py +0 -0
  71. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/fields.py +0 -0
  72. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/hap.py +0 -0
  73. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/merge.py +0 -0
  74. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/recording/__init__.py +0 -0
  75. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/recording/console.py +0 -0
  76. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/recording/jsonl.py +0 -0
  77. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/recording/mirror.py +0 -0
  78. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/recording/report.py +0 -0
  79. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/schema.py +0 -0
  80. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/seed/INSTRUCTIONS.md +0 -0
  81. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/seed/__init__.py +0 -0
  82. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/seed/cli.py +0 -0
  83. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/seed/executor.py +0 -0
  84. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/seed/resources/attachments.json +0 -0
  85. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/seed/resources/sample.docx +0 -0
  86. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/seed/resources/sample.pdf +0 -0
  87. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/seed/resources/sample_images.json +0 -0
  88. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/seed/template.py +0 -0
  89. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/selftest.py +0 -0
  90. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/smoke.py +0 -0
  91. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/steps.py +0 -0
  92. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/store.py +0 -0
  93. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/validate.py +0 -0
  94. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/app_creator/workflow_dsl.py +0 -0
  95. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/attachment.py +0 -0
  96. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/auth.py +0 -0
  97. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/calendar_mod.py +0 -0
  98. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/chart.py +0 -0
  99. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/chat.py +0 -0
  100. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/chatbot.py +0 -0
  101. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/cli_access.py +0 -0
  102. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/condition_dsl.py +0 -0
  103. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/contact.py +0 -0
  104. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/control_type_codes.py +0 -0
  105. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/department.py +0 -0
  106. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/editor/__init__.py +0 -0
  107. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/editor/_hapmeta/__init__.py +0 -0
  108. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/editor/_hapmeta/control_type_codes.py +0 -0
  109. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/editor/apply.py +0 -0
  110. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/editor/componentlower.py +0 -0
  111. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/editor/editspec/component.schema.json +0 -0
  112. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/editor/editspec/custom-action.schema.json +0 -0
  113. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/editor/editspec/envelope.schema.json +0 -0
  114. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/editor/editspec/field.schema.json +0 -0
  115. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/editor/editspec.py +0 -0
  116. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/editor/errors.py +0 -0
  117. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/editor/fieldlower.py +0 -0
  118. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/editor/jsonschema_mini.py +0 -0
  119. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/editor/models.py +0 -0
  120. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/editor/ops.py +0 -0
  121. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/editor/planner.py +0 -0
  122. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/editor/reader.py +0 -0
  123. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/field_normalizer.py +0 -0
  124. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/field_spec_adapter.py +0 -0
  125. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/filter_translator.py +0 -0
  126. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/filter_v3.py +0 -0
  127. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/flow_node.py +0 -0
  128. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/global_meta.py +0 -0
  129. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/group.py +0 -0
  130. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/guide.py +0 -0
  131. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/icon_index.py +0 -0
  132. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/instance.py +0 -0
  133. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/layout_check.py +0 -0
  134. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/logger.py +0 -0
  135. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/optionset.py +0 -0
  136. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/page.py +0 -0
  137. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/post.py +0 -0
  138. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/record.py +0 -0
  139. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/record_defaults.py +0 -0
  140. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/record_form_checks.py +0 -0
  141. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/record_lookups.py +0 -0
  142. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/record_rules.py +0 -0
  143. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/relation_scope.py +0 -0
  144. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/relogin.py +0 -0
  145. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/response_crypto.py +0 -0
  146. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/role.py +0 -0
  147. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/role_perm_builder.py +0 -0
  148. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/rule_spec_adapter.py +0 -0
  149. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/session.py +0 -0
  150. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/token_crypto.py +0 -0
  151. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/update.py +0 -0
  152. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/v3/__init__.py +0 -0
  153. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/v3/dispatcher.py +0 -0
  154. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/v3/render.py +0 -0
  155. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/v3/schema.py +0 -0
  156. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/view_spec_adapter.py +0 -0
  157. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/workflow.py +0 -0
  158. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/workflow_node_dsl.py +0 -0
  159. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/worksheet.py +0 -0
  160. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/worksheet_form.py +0 -0
  161. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/worksheet_reference.py +0 -0
  162. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/core/worksheet_templates.py +0 -0
  163. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/en/approval.md +0 -0
  164. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/en/chart.md +0 -0
  165. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/en/overview.md +0 -0
  166. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/en/post.md +0 -0
  167. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/en/record.md +0 -0
  168. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/en/setup.md +0 -0
  169. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/en/skills.md +0 -0
  170. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/en/workflow.md +0 -0
  171. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/en/worksheet.md +0 -0
  172. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/index.json +0 -0
  173. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/zh-Hans/approval.md +0 -0
  174. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/zh-Hans/chart.md +0 -0
  175. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/zh-Hans/overview.md +0 -0
  176. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/zh-Hans/post.md +0 -0
  177. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/zh-Hans/record.md +0 -0
  178. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/zh-Hans/setup.md +0 -0
  179. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/zh-Hans/skills.md +0 -0
  180. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/zh-Hans/workflow.md +0 -0
  181. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/guide/zh-Hans/worksheet.md +0 -0
  182. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/i18n.py +0 -0
  183. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/locale/__init__.py +0 -0
  184. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/locale/messages.schema.json +0 -0
  185. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/__init__.py +0 -0
  186. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/conftest.py +0 -0
  187. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_action_mdpublic_parity.py +0 -0
  188. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_advanced_setting_guard.py +0 -0
  189. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_app_creator.py +0 -0
  190. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_app_editor.py +0 -0
  191. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_app_export_usage.py +0 -0
  192. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_app_light_color.py +0 -0
  193. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_app_section_name.py +0 -0
  194. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_approval_submit_fill_cli.py +0 -0
  195. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_approval_wire.py +0 -0
  196. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_atomic_write.py +0 -0
  197. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_attachment_share.py +0 -0
  198. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_auth_prerelease.py +0 -0
  199. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_batch_add_atomic.py +0 -0
  200. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_bug_036430.py +0 -0
  201. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_bug_036750.py +0 -0
  202. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_calendar_date_range.py +0 -0
  203. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_calendar_discussion_cli.py +0 -0
  204. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_chart.py +0 -0
  205. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_chart_filter_merge.py +0 -0
  206. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_chat_attachment_send.py +0 -0
  207. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_chat_messages_cli.py +0 -0
  208. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_chat_recall_cli.py +0 -0
  209. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_chat_send_socket.py +0 -0
  210. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_cli_access.py +0 -0
  211. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_coded_responses.py +0 -0
  212. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_condition_dsl.py +0 -0
  213. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_condition_dsl_entries.py +0 -0
  214. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_condition_dsl_readback.py +0 -0
  215. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_config_cmd.py +0 -0
  216. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_content_language.py +0 -0
  217. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_control_lookup_guard.py +0 -0
  218. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_core.py +0 -0
  219. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_create_worksheet_partial.py +0 -0
  220. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_destructive_confirm_cli.py +0 -0
  221. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_dsl_existing_node_refs.py +0 -0
  222. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_dsl_multi_record_guard.py +0 -0
  223. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_editor_inline_subtable.py +0 -0
  224. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_engine_core_parity.py +0 -0
  225. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_arg_consistency.py +0 -0
  226. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_bidirectional.py +0 -0
  227. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_discussion_mentions.py +0 -0
  228. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_entry_module.py +0 -0
  229. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_field_record_ref.py +0 -0
  230. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_http_error_body.py +0 -0
  231. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_json_anywhere.py +0 -0
  232. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_json_file_arg.py +0 -0
  233. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_layout_check.py +0 -0
  234. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_node_get_detail.py +0 -0
  235. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_node_summary.py +0 -0
  236. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_post_cursor.py +0 -0
  237. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_publish_reasons.py +0 -0
  238. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_replicate_workflow.py +0 -0
  239. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_save_fields_shape.py +0 -0
  240. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_subgroups.py +0 -0
  241. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_subtable_read.py +0 -0
  242. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_worksheet_references.py +0 -0
  243. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_worksheet_visibility.py +0 -0
  244. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fb_worksheet_workflows.py +0 -0
  245. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_fields_mdpublic_parity.py +0 -0
  246. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_full_e2e.py +0 -0
  247. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_g1_chart_parity.py +0 -0
  248. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_g1_record_parity.py +0 -0
  249. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_g1_upload_parity.py +0 -0
  250. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_g1_worksheet_parity.py +0 -0
  251. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_g2_coverage_parity.py +0 -0
  252. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_g3_workflow_parity.py +0 -0
  253. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_g4_approval_parity.py +0 -0
  254. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_g5_low_frequency_parity.py +0 -0
  255. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_g6_advanced_fields.py +0 -0
  256. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_g6_fields_roundtrip.py +0 -0
  257. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_g7_misc_gaps.py +0 -0
  258. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_g7b_permanent_delete.py +0 -0
  259. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_g8_filter_operator.py +0 -0
  260. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_g8b_pivot_operators.py +0 -0
  261. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_g8c_empty_filter_and_help_truth.py +0 -0
  262. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_g9_appid_resolve.py +0 -0
  263. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_global_meta.py +0 -0
  264. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_guide.py +0 -0
  265. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_guide_sections.py +0 -0
  266. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_i18n.py +0 -0
  267. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_inner_flow_batch_add.py +0 -0
  268. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_instance_envelope.py +0 -0
  269. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_instance_history_cli.py +0 -0
  270. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_integration.py +0 -0
  271. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_integration_approval.py +0 -0
  272. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_integration_approval_actions.py +0 -0
  273. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_integration_calendar.py +0 -0
  274. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_integration_destructive.py +0 -0
  275. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_integration_misc.py +0 -0
  276. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_integration_post.py +0 -0
  277. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_integration_social.py +0 -0
  278. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_integration_v3.py +0 -0
  279. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_integration_workflow.py +0 -0
  280. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_integration_worksheet_extra.py +0 -0
  281. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_jsonschema_mini_copy.py +0 -0
  282. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_member_relation_array_wrap.py +0 -0
  283. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_multi_profile.py +0 -0
  284. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_no_workflow_unsupported.py +0 -0
  285. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_noninteractive_confirm.py +0 -0
  286. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_org_approval_v3_semantic_cli.py +0 -0
  287. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_org_id_cli.py +0 -0
  288. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_org_id_docs.py +0 -0
  289. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_page_filters_group_read.py +0 -0
  290. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_page_filters_group_update.py +0 -0
  291. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_page_save_page_id.py +0 -0
  292. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_parameter_conventions.py +0 -0
  293. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_parameter_mapping_registry.py +0 -0
  294. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_post_attachments.py +0 -0
  295. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_post_group_friction.py +0 -0
  296. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_post_scope_cli.py +0 -0
  297. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_record_batch_v3_semantic_cli.py +0 -0
  298. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_record_business_rules.py +0 -0
  299. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_record_defaults.py +0 -0
  300. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_record_doc_id_hidden.py +0 -0
  301. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_record_field_alias.py +0 -0
  302. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_record_form_checks.py +0 -0
  303. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_record_run_action.py +0 -0
  304. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_record_v3_semantic_cli.py +0 -0
  305. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_record_write_fixes.py +0 -0
  306. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_relation_scope.py +0 -0
  307. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_relogin.py +0 -0
  308. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_rmw_mdpublic_parity.py +0 -0
  309. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_role_app_scope.py +0 -0
  310. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_rule_filters_and_field_warning.py +0 -0
  311. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_save_action_silent_drop.py +0 -0
  312. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_save_rule_spec.py +0 -0
  313. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_select_add_option.py +0 -0
  314. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_select_rejects_relation_value.py +0 -0
  315. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_semantic_types_registry.py +0 -0
  316. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_subtable_mdpublic_parity.py +0 -0
  317. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_update.py +0 -0
  318. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_update_mode.py +0 -0
  319. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_upload_allow_down.py +0 -0
  320. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_upload_host_resolution.py +0 -0
  321. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_v3_api_schema_loader.py +0 -0
  322. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_v3_bool_flags.py +0 -0
  323. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_v3_dispatcher.py +0 -0
  324. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_v3_registry_coverage.py +0 -0
  325. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_v3_response_format_json.py +0 -0
  326. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_v3_session.py +0 -0
  327. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_v3_yaml_translation.py +0 -0
  328. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_view_mdpublic_parity.py +0 -0
  329. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_wf_config_keys.py +0 -0
  330. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_wf_inner_scope.py +0 -0
  331. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_wf_json_file_arg.py +0 -0
  332. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_wf_node_delete_missing.py +0 -0
  333. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_wf_save_action_dsl_fields.py +0 -0
  334. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_wf_structure_listing.py +0 -0
  335. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_wf_trigger_outcome.py +0 -0
  336. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_wf_trigger_preserve.py +0 -0
  337. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_wo4_result_handling.py +0 -0
  338. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_workflow_code_node.py +0 -0
  339. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_workflow_condition_field_types.py +0 -0
  340. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_workflow_condition_slots.py +0 -0
  341. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_workflow_delete_cascade.py +0 -0
  342. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_workflow_envelope_errors.py +0 -0
  343. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_workflow_lifecycle_wire.py +0 -0
  344. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_workflow_list_cli.py +0 -0
  345. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_workflow_node_wire.py +0 -0
  346. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_workflow_publish_inner.py +0 -0
  347. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_workflow_read_write_keys.py +0 -0
  348. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_workflow_v3_semantic_cli.py +0 -0
  349. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_worksheet_create_section.py +0 -0
  350. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_worksheet_crud_cli.py +0 -0
  351. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_worksheet_filter_read.py +0 -0
  352. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_worksheet_switch.py +0 -0
  353. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/tests/test_worksheet_v3_semantic_cli.py +0 -0
  354. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/utils/__init__.py +0 -0
  355. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/utils/atomic_write.py +0 -0
  356. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/utils/confirm.py +0 -0
  357. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/utils/formatting.py +0 -0
  358. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/utils/options.py +0 -0
  359. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli/utils/parameter_mapping.py +0 -0
  360. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli.egg-info/dependency_links.txt +0 -0
  361. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli.egg-info/entry_points.txt +0 -0
  362. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli.egg-info/requires.txt +0 -0
  363. {hap_cli-0.9.8 → hap_cli-0.9.9}/hap_cli.egg-info/top_level.txt +0 -0
  364. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/__init__.py +0 -0
  365. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/__main__.py +0 -0
  366. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/_wftest.py +0 -0
  367. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/charts.py +0 -0
  368. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/cleanup.py +0 -0
  369. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/compiler.py +0 -0
  370. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/config.py +0 -0
  371. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/errors.py +0 -0
  372. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/executor.py +0 -0
  373. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/fields.py +0 -0
  374. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/hap.py +0 -0
  375. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/recording/__init__.py +0 -0
  376. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/recording/console.py +0 -0
  377. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/recording/jsonl.py +0 -0
  378. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/recording/mirror.py +0 -0
  379. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/recording/report.py +0 -0
  380. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/schema.py +0 -0
  381. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/seed/__init__.py +0 -0
  382. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/seed/cli.py +0 -0
  383. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/seed/executor.py +0 -0
  384. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/seed/template.py +0 -0
  385. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/selftest.py +0 -0
  386. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/smoke.py +0 -0
  387. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/step.py +0 -0
  388. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/steps.py +0 -0
  389. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/store.py +0 -0
  390. {hap_cli-0.9.8 → hap_cli-0.9.9}/live_tests/workflow_dsl.py +0 -0
  391. {hap_cli-0.9.8 → hap_cli-0.9.9}/setup.cfg +0 -0
  392. {hap_cli-0.9.8 → hap_cli-0.9.9}/setup.py +0 -0
  393. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/INDEX.json +0 -0
  394. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/add_member_to_role.yaml +0 -0
  395. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/batch_delete_records.yaml +0 -0
  396. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/create_optionset.yaml +0 -0
  397. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/create_role.yaml +0 -0
  398. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/delete_optionset.yaml +0 -0
  399. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/delete_record.yaml +0 -0
  400. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/delete_role.yaml +0 -0
  401. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/delete_worksheet.yaml +0 -0
  402. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/get_app_info.yaml +0 -0
  403. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/get_app_knowledge_list.yaml +0 -0
  404. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/get_app_worksheets_list.yaml +0 -0
  405. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/get_optionset_list.yaml +0 -0
  406. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/get_record_details.yaml +0 -0
  407. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/get_record_discussions.yaml +0 -0
  408. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/get_record_list.yaml +0 -0
  409. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/get_record_logs.yaml +0 -0
  410. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/get_record_pivot_data.yaml +0 -0
  411. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/get_record_relations.yaml +0 -0
  412. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/get_record_share_link.yaml +0 -0
  413. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/get_regions.yaml +0 -0
  414. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/get_role_details.yaml +0 -0
  415. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/get_role_list.yaml +0 -0
  416. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/knowledge_search.yaml +0 -0
  417. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/leave_all_roles.yaml +0 -0
  418. {hap_cli-0.9.8 → hap_cli-0.9.9}/sources/v3-api-schema/remove_member_from_role.yaml +0 -0
  419. {hap_cli-0.9.8 → hap_cli-0.9.9}/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.9.8
3
+ Version: 0.9.9
4
4
  Summary: CLI harness for Mingdao HAP - Enterprise no-code platform
5
5
  Author: hap-cli
6
6
  License: Apache-2.0
@@ -3,7 +3,7 @@
3
3
  import sys as _sys
4
4
  import types as _types
5
5
 
6
- __version__ = "0.9.8"
6
+ __version__ = "0.9.9"
7
7
 
8
8
  # The command tree used to live in hap_cli/hap_cli.py. A module named
9
9
  # after the package it sits in shadows that package: run python with the
@@ -1,6 +1,8 @@
1
1
  """CLI commands for chat and messaging management."""
2
2
 
3
+ import html
3
4
  import json
5
+ import re
4
6
 
5
7
  import click
6
8
 
@@ -73,6 +75,103 @@ def _output_chat_list_table(rows):
73
75
  )
74
76
 
75
77
 
78
+ def _one_line(text: str) -> str:
79
+ """Visible text of a message on one line: tags dropped, entities
80
+ decoded, runs of whitespace collapsed."""
81
+ text = html.unescape(re.sub(r"<[^>]*>", "", text or ""))
82
+ return " ".join(text.split())
83
+
84
+
85
+ def _conversation_preview(msg: dict) -> str:
86
+ body = msg.get("msg") or {}
87
+ text = _one_line(str(body.get("con") or ""))
88
+ files = body.get("files")
89
+ if isinstance(files, dict):
90
+ name = f"{files.get('originalFileName') or ''}{files.get('fileExt') or ''}"
91
+ label = "[image]" if msg.get("type") == 2 else "[file]"
92
+ text = " ".join(x for x in (label, name, text) if x)
93
+ return text
94
+
95
+
96
+ def _output_conversation_table(rows):
97
+ """One row per message of a 1-on-1 or group chat, in the order the
98
+ server returns them (newest first)."""
99
+ output_table(
100
+ [
101
+ {
102
+ "time": str(m.get("time") or "")[:19],
103
+ "from": (m.get("fromAccount") or {}).get("name") or m.get("from", ""),
104
+ "message": _conversation_preview(m),
105
+ "id": m.get("id", ""),
106
+ }
107
+ for m in rows or []
108
+ if isinstance(m, dict)
109
+ ],
110
+ ["time", "from", "message", "id"],
111
+ ["Time", "From", "Message", "Message ID"],
112
+ )
113
+
114
+
115
+ def _output_inbox_table(data):
116
+ rows = (data or {}).get("list") or []
117
+ output_table(
118
+ [
119
+ {
120
+ "time": r.get("createTime", ""),
121
+ "from": (r.get("sender") or {}).get("name")
122
+ or (r.get("app") or {}).get("name", ""),
123
+ "message": _one_line(str(r.get("message") or "")),
124
+ }
125
+ for r in rows
126
+ if isinstance(r, dict)
127
+ ],
128
+ ["time", "from", "message"],
129
+ ["Time", "From", "Message"],
130
+ )
131
+
132
+
133
+ def _output_messages(data):
134
+ if isinstance(data, dict) and "list" in data:
135
+ _output_inbox_table(data)
136
+ else:
137
+ _output_conversation_table(data)
138
+
139
+
140
+ def _output_chat_files(data):
141
+ rows = (data or {}).get("list") or []
142
+ output_table(
143
+ [
144
+ {
145
+ "time": r.get("time", ""),
146
+ "name": r.get("name", ""),
147
+ "size": _file_size(r.get("size")),
148
+ "from": (r.get("createAccount") or {}).get("fullname", ""),
149
+ "fileId": r.get("fileId", ""),
150
+ }
151
+ for r in rows
152
+ if isinstance(r, dict)
153
+ ],
154
+ ["time", "name", "size", "from", "fileId"],
155
+ ["Time", "Name", "Size", "From", "File ID"],
156
+ )
157
+ total = (data or {}).get("allCount")
158
+ if isinstance(total, int) and total > len(rows):
159
+ click.echo(f"Showing {len(rows)} of {total} files. Use -p for the "
160
+ f"next page.", err=True)
161
+
162
+
163
+ def _file_size(value) -> str:
164
+ try:
165
+ size = float(value)
166
+ except (TypeError, ValueError):
167
+ return ""
168
+ for unit in ("B", "KB", "MB", "GB"):
169
+ if size < 1024 or unit == "GB":
170
+ return f"{size:.0f} {unit}" if unit == "B" else f"{size:.1f} {unit}"
171
+ size /= 1024
172
+ return ""
173
+
174
+
76
175
  @click.group(help=t(
77
176
  'Chat and messaging management.\n\n'
78
177
  'To follow a notification back to the app record it belongs to, see '
@@ -97,7 +196,8 @@ def chat_list(ctx, page_size, page):
97
196
 
98
197
 
99
198
  @chat.command("files")
100
- @click.option("--with-user", "with_user", help="Peer accountId for 1-on-1 files")
199
+ @click.option("--account-id", "--with-user", "with_user",
200
+ help="Account id of the person, for the files of your 1-on-1 chat")
101
201
  @click.option("--group-id", "group_id", help="Group id for group chat files")
102
202
  @click.option("--page-size", "-n", default=20, help="Items per page")
103
203
  @click.option("--page", "-p", default=1, help="Page number")
@@ -114,11 +214,11 @@ def chat_list(ctx, page_size, page):
114
214
  def chat_files(ctx, with_user, group_id, page_size, page, keywords, file_type, start, end):
115
215
  """List files shared in a 1-on-1 or group chat.
116
216
 
117
- Provide exactly one of --with-user or --group-id.
217
+ Provide exactly one of --account-id or --group-id.
118
218
  """
119
219
  if bool(with_user) == bool(group_id):
120
220
  ctx.handle_error(click.UsageError(
121
- "Provide exactly one of --with-user or --group-id."
221
+ "Provide exactly one of --account-id or --group-id."
122
222
  ))
123
223
  return
124
224
  try:
@@ -145,13 +245,14 @@ def chat_files(ctx, with_user, group_id, page_size, page, keywords, file_type, s
145
245
  start=start,
146
246
  end=end,
147
247
  )
148
- ctx.output(data, lambda d: output_json(d))
248
+ ctx.output(data, _output_chat_files)
149
249
  except Exception as e:
150
250
  ctx.handle_error(e)
151
251
 
152
252
 
153
253
  @chat.command("messages")
154
- @click.option("--with-user", "with_user", help="Peer accountId for 1-on-1 messages")
254
+ @click.option("--account-id", "--with-user", "with_user",
255
+ help="Account id of the person, for your 1-on-1 chat with them")
155
256
  @click.option("--group-id", "group_id", help="Group id for group chat messages")
156
257
  @click.option(
157
258
  "--category",
@@ -202,7 +303,9 @@ def chat_messages(
202
303
  """Fetch chat message history.
203
304
 
204
305
  Provide exactly one of:
205
- --with-user 1-on-1 chat with a user
306
+
307
+ \b
308
+ --account-id 1-on-1 chat with a person
206
309
  --group-id a group chat
207
310
  --category inbox category (system / post / task / calendar /
208
311
  kc / hr / app / workflow)
@@ -211,7 +314,7 @@ def chat_messages(
211
314
  sources = [bool(with_user), bool(group_id), bool(category), bool(inbox_type)]
212
315
  if sum(sources) != 1:
213
316
  ctx.handle_error(click.UsageError(
214
- "Provide exactly one of --with-user / --group-id / --category / --inbox-type."
317
+ "Provide exactly one of --account-id / --group-id / --category / --inbox-type."
215
318
  ))
216
319
  return
217
320
  try:
@@ -250,13 +353,14 @@ def chat_messages(
250
353
  )
251
354
  if mark_read and category:
252
355
  chat_mod.mark_inbox_read(session, category)
253
- ctx.output(data, lambda d: output_json(d))
356
+ ctx.output(data, _output_messages)
254
357
  except Exception as e:
255
358
  ctx.handle_error(e)
256
359
 
257
360
 
258
361
  @chat.command("send-to-one")
259
- @click.option("--to", "-t", multiple=True, help="Target user account ID (can repeat)")
362
+ @click.option("--account-id", "--to", "-t", "to", multiple=True,
363
+ help="Account id of the person to message (repeatable)")
260
364
  @click.option("--message", "-m", default="", help="Message text")
261
365
  @click.option(
262
366
  "--file", "-f", "files", multiple=True,
@@ -282,7 +386,7 @@ def chat_send_to_one(ctx, to, message, files, dry_run):
282
386
  """
283
387
  if not to:
284
388
  ctx.handle_error(click.UsageError(
285
- "Provide at least one --to <accountId>."
389
+ "Provide at least one --account-id."
286
390
  ))
287
391
  return
288
392
  if not message and not files:
@@ -446,8 +550,9 @@ def chat_card_detail(ctx, task, post, calendar, kcfile, worksheet, worksheetrow)
446
550
  @chat.command("recall")
447
551
  @click.argument("message_id")
448
552
  @click.option("--group-id", "group_id", default="", help="Group id the message is in")
449
- @click.option("--with-user", "with_user", default="",
450
- help="Peer accountId for a 1-on-1 message")
553
+ @click.option("--account-id", "--with-user", "with_user", default="",
554
+ help="Account id of the person, for a message in your 1-on-1 "
555
+ "chat with them")
451
556
  @click.option("--time", "msg_time", default="",
452
557
  help="Send time of the message. Looked up from the conversation "
453
558
  "when omitted.")
@@ -465,7 +570,7 @@ def chat_recall(ctx, message_id, group_id, with_user, msg_time, as_admin, dry_ru
465
570
  cannot be undone.
466
571
  """
467
572
  if bool(group_id) == bool(with_user):
468
- raise click.UsageError("Pass exactly one of --group-id or --with-user.")
573
+ raise click.UsageError("Pass exactly one of --group-id or --account-id.")
469
574
  try:
470
575
  session = ctx.get_session()
471
576
  found = None
@@ -28,7 +28,7 @@ import re
28
28
  import time
29
29
  from datetime import datetime, timezone
30
30
  from typing import Any, Callable, Optional
31
- from urllib.parse import parse_qs, quote, urlparse
31
+ from urllib.parse import parse_qs, quote, unquote, urlparse
32
32
 
33
33
  import requests
34
34
 
@@ -267,6 +267,17 @@ def _encode_original_name(stem: str) -> str:
267
267
  return quote(stem, safe="")
268
268
 
269
269
 
270
+ def _decode_original_name(echoed: Any, fallback: str) -> str:
271
+ """The store echoes ``x:originalFileName`` exactly as posted — still
272
+ percent-encoded — and the uploader decodes it before handing the file
273
+ on (MDPublic createUploader.js:452). Passing the echo through as-is
274
+ left names like "HDP-%E5%B9%BF%E5%91%8A40s" on posts, chat files and
275
+ record attachments."""
276
+ if not echoed:
277
+ return fallback
278
+ return unquote(str(echoed))
279
+
280
+
270
281
  def _name_and_ext(source: str, *, name: str = "") -> tuple[str, str]:
271
282
  """Derive (originalName-without-ext, ext-with-dot) from a name or path/url.
272
283
 
@@ -368,7 +379,7 @@ def upload_bytes(
368
379
  "filePath": up.get("filePath"),
369
380
  "fileName": up.get("fileName"),
370
381
  "fileExt": up.get("fileExt"),
371
- "originalFileName": up.get("originalFileName"),
382
+ "originalFileName": _decode_original_name(up.get("originalFileName"), original),
372
383
  "key": up.get("key") or token.get("key"),
373
384
  "url": token.get("url"),
374
385
  # The signed URL above stops working at this instant — see
@@ -30,7 +30,7 @@ hap --json chat messages --category app # or workflow, etc.
30
30
  with `viewId`, `comment.recordName` and `comment.entityName`.
31
31
  - Workflow **cc / participant** notifications have the `appId` / `worksheetId` / `rowId`
32
32
  resolved out of the record link for you.
33
- - One-to-one and group chats do not use `--category`; use `--with-user <accountId>` or
33
+ - One-to-one and group chats do not use `--category`; use `--account-id <accountId>` or
34
34
  `--group-id <groupId>` (the id is the conversation's `value`).
35
35
 
36
36
  **3. Read the record and its discussion**
@@ -29,7 +29,7 @@ hap --json chat messages --category app # 或 workflow 等
29
29
  `comment.recordName`、`comment.entityName`。
30
30
  - 工作流**抄送 / 参与者**类通知会把记录链接里的 `appId` / `worksheetId` / `rowId`
31
31
  一并解析出来。
32
- - 单聊 / 群聊不走 `--category`,用 `--with-user <accountId>` 或 `--group-id <groupId>`
32
+ - 单聊 / 群聊不走 `--category`,用 `--account-id <accountId>` 或 `--group-id <groupId>`
33
33
  (id 取会话的 `value`)。
34
34
 
35
35
  **3. 拿三元组直接读记录和讨论**
@@ -3015,6 +3015,30 @@
3015
3015
  "en": "Output in JSON format",
3016
3016
  "zh-Hans": "以 JSON 格式输出"
3017
3017
  },
3018
+ "attachment download": {
3019
+ "en": "Download a file attached to a worksheet record.\n\nFILE_ID is listed in an attachment field or a record operation log.\nExisting local files are never overwritten.",
3020
+ "zh-Hans": "下载工作表记录里的附件。\n\nFILE_ID 可以在附件字段或记录操作日志中找到。不会覆盖本地已有的文件。"
3021
+ },
3022
+ "attachment download --control-id": {
3023
+ "en": "Attachment field containing the file.",
3024
+ "zh-Hans": "附件所在的附件字段。"
3025
+ },
3026
+ "attachment download --json": {
3027
+ "en": "Output in JSON format",
3028
+ "zh-Hans": "以 JSON 格式输出"
3029
+ },
3030
+ "attachment download --output": {
3031
+ "en": "Save as this path. By default, uses the attachment name.",
3032
+ "zh-Hans": "保存到此路径。默认使用附件原名。"
3033
+ },
3034
+ "attachment download --row-id": {
3035
+ "en": "Record containing the attachment.",
3036
+ "zh-Hans": "附件所在的记录。"
3037
+ },
3038
+ "attachment download --worksheet-id": {
3039
+ "en": "Worksheet containing the record.",
3040
+ "zh-Hans": "记录所在的工作表。"
3041
+ },
3018
3042
  "attachment share": {
3019
3043
  "en": "Create a link to a stored file that you can pass on.\n\n\b\n hap attachment share https://doc.example.com/doc/20260830/abc.html\n hap attachment share doc/20260830/abc.html --hours 168\n hap attachment share --file-id <id>\n\nADDRESS is the file's link — a link that has already stopped working\nis fine, paste it as-is — or just the path part of it.",
3020
3044
  "zh-Hans": "为已存储的文件创建可转发的链接。\n\n\b\n hap attachment share https://doc.example.com/doc/20260830/abc.html\n hap attachment share doc/20260830/abc.html --hours 168\n hap attachment share --file-id <id>\n\nADDRESS 是文件的链接——已经失效的链接也可以,原样粘贴即可——或者只传链接中的路径部分。"
@@ -3432,8 +3456,12 @@
3432
3456
  "zh-Hans": "工作表记录,格式 'wsId>rowId',以 '|' 分隔"
3433
3457
  },
3434
3458
  "chat files": {
3435
- "en": "List files shared in a 1-on-1 or group chat.\n\nProvide exactly one of --with-user or --group-id.",
3436
- "zh-Hans": "列出单聊或群聊中共享的文件。\n\n--with-user 与 --group-id 必须且只能提供一个"
3459
+ "en": "List files shared in a 1-on-1 or group chat.\n\nProvide exactly one of --account-id or --group-id.",
3460
+ "zh-Hans": "列出单聊或群聊中共享的文件。\n\n--account-id 与 --group-id 必须且只能提供一个。"
3461
+ },
3462
+ "chat files --account-id": {
3463
+ "en": "Account id of the person, for the files of your 1-on-1 chat",
3464
+ "zh-Hans": "对方的账号 ID,列出你和此人单聊中的文件"
3437
3465
  },
3438
3466
  "chat files --end": {
3439
3467
  "en": "End timestamp (inclusive)",
@@ -3467,10 +3495,6 @@
3467
3495
  "en": "Start timestamp (inclusive)",
3468
3496
  "zh-Hans": "开始时间戳(含)"
3469
3497
  },
3470
- "chat files --with-user": {
3471
- "en": "Peer accountId for 1-on-1 files",
3472
- "zh-Hans": "单聊文件的对方 accountId"
3473
- },
3474
3498
  "chat list": {
3475
3499
  "en": "List recent chat sessions.",
3476
3500
  "zh-Hans": "列出最近的聊天会话"
@@ -3488,8 +3512,12 @@
3488
3512
  "zh-Hans": "每页条数"
3489
3513
  },
3490
3514
  "chat messages": {
3491
- "en": "Fetch chat message history.\n\nProvide exactly one of:\n --with-user 1-on-1 chat with a user\n --group-id a group chat\n --category inbox category (system / post / task / calendar /\n kc / hr / app / workflow)\n --inbox-type raw inbox type code for advanced filters",
3492
- "zh-Hans": "获取聊天消息历史。\n\n以下选项必须且只能提供一个:\n --with-user 与某用户的单聊\n --group-id 群聊\n --category 收件箱分类(system / post / task / calendar /\n kc / hr / app / workflow)\n --inbox-type 原始收件箱类型代码,用于高级筛选"
3515
+ "en": "Fetch chat message history.\n\nProvide exactly one of:\n\n\b\n --account-id 1-on-1 chat with a person\n --group-id a group chat\n --category inbox category (system / post / task / calendar /\n kc / hr / app / workflow)\n --inbox-type raw inbox type code for advanced filters",
3516
+ "zh-Hans": "获取聊天消息历史。\n\n以下选项必须且只能提供一个:\n\n\b\n --account-id 与某人的单聊\n --group-id 群聊\n --category 收件箱分类(system / post / task / calendar /\n kc / hr / app / workflow)\n --inbox-type 原始收件箱类型代码,用于高级筛选"
3517
+ },
3518
+ "chat messages --account-id": {
3519
+ "en": "Account id of the person, for your 1-on-1 chat with them",
3520
+ "zh-Hans": "对方的账号 ID,查看你和此人的单聊"
3493
3521
  },
3494
3522
  "chat messages --category": {
3495
3523
  "en": "Inbox category: system, post, task, calendar, kc, hr, app, workflow",
@@ -3531,14 +3559,14 @@
3531
3559
  "en": "Anchor timestamp, e.g. '2026-04-07 19:06:53.038' (paginate around this)",
3532
3560
  "zh-Hans": "锚点时间戳,例如 '2026-04-07 19:06:53.038'(以此为基准分页)"
3533
3561
  },
3534
- "chat messages --with-user": {
3535
- "en": "Peer accountId for 1-on-1 messages",
3536
- "zh-Hans": "单聊消息的对方 accountId"
3537
- },
3538
3562
  "chat recall": {
3539
3563
  "en": "Recall a message you sent.\n\nYou can recall your own message within 5 minutes of sending it; a group\nadmin can recall another member's message with no time limit. A recall\ncannot be undone.",
3540
3564
  "zh-Hans": "撤回自己发送的消息。自己的消息限发送后 5 分钟内撤回;群管理员撤回其他成员的消息不限时间。撤回后无法恢复。"
3541
3565
  },
3566
+ "chat recall --account-id": {
3567
+ "en": "Account id of the person, for a message in your 1-on-1 chat with them",
3568
+ "zh-Hans": "对方的账号 ID,撤回你和此人单聊中的消息"
3569
+ },
3542
3570
  "chat recall --as-admin": {
3543
3571
  "en": "Recall as a group admin. Admins may recall another member's message; ordinary recall only covers your own.",
3544
3572
  "zh-Hans": "以群管理员身份撤回。管理员可撤回其他成员的消息;普通撤回只能撤回自己的。"
@@ -3559,10 +3587,6 @@
3559
3587
  "en": "Send time of the message. Looked up from the conversation when omitted.",
3560
3588
  "zh-Hans": "消息的发送时间。省略时自动从会话记录中查找。"
3561
3589
  },
3562
- "chat recall --with-user": {
3563
- "en": "Peer accountId for a 1-on-1 message",
3564
- "zh-Hans": "单聊消息的对方 accountId"
3565
- },
3566
3590
  "chat send-to-group": {
3567
3591
  "en": "Send a message, optionally with files, to a group chat.\n\n\b\n hap chat send-to-group -g <groupId> -m \"spec attached\" -f ./spec.pdf\n\nText and each file arrive as separate messages, in that order. An\n@-mention applies to the text line, so it needs --message.",
3568
3592
  "zh-Hans": "向群聊发送消息,可附带文件。\n\n\b\n hap chat send-to-group -g <groupId> -m \"spec attached\" -f ./spec.pdf\n\n文本和每个文件会依次作为独立消息送达。@提及作用于文本行,因此需要 --message"
@@ -3599,6 +3623,10 @@
3599
3623
  "en": "Send a message, optionally with files, to one or more users (1-on-1).\n\n\b\n hap chat send-to-one -t <accountId> -m \"spec attached\" -f ./spec.pdf\n\nText and each file arrive as separate messages, in that order.\n\nTo message yourself, send to the file-transfer assistant with\n-t file-transfer. Your own account id is not a valid target.",
3600
3624
  "zh-Hans": "向一个或多个用户发送消息(单聊),可附带文件。\n\n hap chat send-to-one -t <accountId> -m \"spec attached\" -f ./spec.pdf\n\n文本和每个文件会依次作为独立消息送达。\n\n给自己发消息请发到文件传输助手:-t file-transfer。自己的账号 ID 不是有效目标。"
3601
3625
  },
3626
+ "chat send-to-one --account-id": {
3627
+ "en": "Account id of the person to message (repeatable)",
3628
+ "zh-Hans": "接收消息的人的账号 ID(可重复)"
3629
+ },
3602
3630
  "chat send-to-one --dry-run": {
3603
3631
  "en": "Show what would be sent, without uploading or sending anything.",
3604
3632
  "zh-Hans": "仅显示将要发送的内容,不上传也不发送"
@@ -3615,10 +3643,6 @@
3615
3643
  "en": "Message text",
3616
3644
  "zh-Hans": "消息文本"
3617
3645
  },
3618
- "chat send-to-one --to": {
3619
- "en": "Target user account ID (can repeat)",
3620
- "zh-Hans": "目标用户账号 ID(可重复)"
3621
- },
3622
3646
  "completion": {
3623
3647
  "en": "Alias of `hap config completion`.",
3624
3648
  "zh-Hans": "`hap config completion` 的别名"
@@ -0,0 +1,106 @@
1
+ """Chat commands name the other person the same way, and print tables
2
+ without --json like every other list command."""
3
+
4
+ import json
5
+ from unittest.mock import patch
6
+
7
+ import pytest
8
+ from click.testing import CliRunner
9
+
10
+ from hap_cli._entry import cli
11
+ from hap_cli.core.session import Session
12
+
13
+ PEER = "8cd1a334-e6c4-432c-90b6-85245b356c9e"
14
+
15
+ CONVERSATION = [
16
+ {"id": "m2", "type": 1, "time": "2026-10-15 18:05:05.123",
17
+ "fromAccount": {"name": "顿唯"}, "msg": {"con": "第一行\n<b>第二行</b>"}},
18
+ {"id": "m1", "type": 4, "time": "2026-10-15 18:00:00.000",
19
+ "fromAccount": {"name": "田然"},
20
+ "msg": {"con": "", "files": {"originalFileName": "方案", "fileExt": ".pdf"}}},
21
+ ]
22
+ INBOX = {"category": "app", "list": [
23
+ {"createTime": "2026-10-15 10:56:05", "sender": {"name": "工作流"},
24
+ "message": '您已被添加为<a href="/x">需求</a>的参与者'},
25
+ {"createTime": "2026-10-15 10:00:00", "app": {"name": "产品管理"},
26
+ "message": "流程出错"},
27
+ ]}
28
+ FILES = {"allCount": 5, "list": [
29
+ {"time": "2026-09-23 20:10:59", "name": "image.png", "size": 370896,
30
+ "createAccount": {"fullname": "金可伟"}, "fileId": "f1"},
31
+ ]}
32
+
33
+
34
+ def _authed():
35
+ s = Session(server_url="https://test.mingdao.com", auth_token="tok123")
36
+ s.account_id = "me"
37
+ return s
38
+
39
+
40
+ def _run(args):
41
+ with patch("hap_cli.context.Session.load", return_value=_authed()):
42
+ return CliRunner().invoke(cli, args)
43
+
44
+
45
+ class TestAccountIdEverywhere:
46
+ @pytest.mark.parametrize("flag", ["--account-id", "--with-user"])
47
+ def test_messages(self, flag):
48
+ with patch("hap_cli.core.chat.get_user_messages", return_value=[]) as get:
49
+ result = _run(["--json", "chat", "messages", flag, PEER])
50
+ assert result.exit_code == 0, result.output
51
+ assert get.call_args.kwargs["account_id"] == PEER
52
+
53
+ @pytest.mark.parametrize("flag", ["--account-id", "--with-user"])
54
+ def test_files(self, flag):
55
+ with patch("hap_cli.core.chat.get_user_chat_files",
56
+ return_value={"list": []}) as get:
57
+ result = _run(["--json", "chat", "files", flag, PEER])
58
+ assert result.exit_code == 0, result.output
59
+ assert get.call_args.kwargs["with_user"] == PEER
60
+
61
+ @pytest.mark.parametrize("flag", ["--account-id", "--to", "-t"])
62
+ def test_send_to_one(self, flag):
63
+ result = _run(["--json", "chat", "send-to-one", flag, PEER, "-m", "x",
64
+ "--dry-run"])
65
+ assert result.exit_code == 0, result.output
66
+ assert json.loads(result.output)["to"] == [PEER]
67
+
68
+ def test_recall_accepts_account_id(self):
69
+ result = _run(["chat", "recall", "m1", "--account-id", PEER,
70
+ "--group-id", "g"])
71
+ assert "exactly one of --group-id or --account-id" in result.output
72
+
73
+ def test_missing_source_names_account_id(self):
74
+ result = _run(["chat", "messages"])
75
+ assert "--account-id" in result.output
76
+
77
+
78
+ class TestTables:
79
+ def test_conversation(self):
80
+ with patch("hap_cli.core.chat.get_user_messages", return_value=CONVERSATION):
81
+ result = _run(["chat", "messages", "--account-id", PEER])
82
+ assert result.exit_code == 0, result.output
83
+ assert not result.output.lstrip().startswith(("[", "{"))
84
+ assert "Message ID" in result.output
85
+ assert "第一行 第二行" in result.output and "<b>" not in result.output
86
+ assert "[file] 方案.pdf" in result.output
87
+ assert "2026-10-15 18:05:05 " in result.output
88
+
89
+ def test_inbox(self):
90
+ with patch("hap_cli.core.chat.get_inbox_messages", return_value=INBOX):
91
+ result = _run(["chat", "messages", "--category", "app"])
92
+ assert result.exit_code == 0, result.output
93
+ assert "您已被添加为需求的参与者" in result.output
94
+ assert "工作流" in result.output and "产品管理" in result.output
95
+
96
+ def test_files(self):
97
+ with patch("hap_cli.core.chat.get_group_chat_files", return_value=FILES):
98
+ result = _run(["chat", "files", "--group-id", "g"])
99
+ assert result.exit_code == 0, result.output
100
+ assert "image.png" in result.output and "362.2 KB" in result.output
101
+ assert "Showing 1 of 5 files" in result.output
102
+
103
+ def test_json_mode_unchanged(self):
104
+ with patch("hap_cli.core.chat.get_user_messages", return_value=CONVERSATION):
105
+ result = _run(["--json", "chat", "messages", "--account-id", PEER])
106
+ assert json.loads(result.output)[0]["id"] == "m2"
@@ -0,0 +1,40 @@
1
+ """Every visible command and option has a current catalog entry with a
2
+ Chinese translation.
3
+
4
+ The catalog overrides in-source help at runtime, so a command that ships
5
+ without running ``scripts/sync_command_catalog.py --apply`` shows English
6
+ help to Chinese users. ``attachment download`` went out that way in 0.9.1
7
+ and every later sync re-added its entries, which kept being mistaken for
8
+ unrelated drift and stripped."""
9
+
10
+ import json
11
+ import subprocess
12
+ import sys
13
+ from pathlib import Path
14
+
15
+ ROOT = Path(__file__).resolve().parents[2]
16
+
17
+
18
+ def test_catalog_matches_source_help():
19
+ out = subprocess.run(
20
+ [sys.executable, str(ROOT / "scripts" / "sync_command_catalog.py")],
21
+ capture_output=True, text=True, cwd=ROOT, timeout=120,
22
+ )
23
+ assert out.returncode == 0, out.stderr
24
+ summary = out.stdout.splitlines()[0]
25
+ counts = dict(
26
+ part.strip().rsplit(" ", 1) for part in summary.split("|")
27
+ )
28
+ drift = {k: v for k, v in counts.items()
29
+ if k in ("changed", "added", "pruned") and v != "0"}
30
+ assert not drift, (
31
+ f"{summary}\nRun: python3 scripts/sync_command_catalog.py --apply, "
32
+ "then add zh-Hans for the keys it lists.")
33
+
34
+
35
+ def test_every_entry_has_zh_hans():
36
+ cat = json.loads((ROOT / "hap_cli" / "locale" / "messages.json")
37
+ .read_text(encoding="utf-8"))
38
+ missing = [k for k, v in cat["commands"].items()
39
+ if isinstance(v, dict) and v.get("en") and not v.get("zh-Hans")]
40
+ assert not missing, f"no zh-Hans for: {missing}"
@@ -86,6 +86,38 @@ def test_original_file_name_is_percent_encoded():
86
86
  assert up_mod._encode_original_name("中文") == "%E4%B8%AD%E6%96%87"
87
87
 
88
88
 
89
+ @pytest.mark.parametrize("stem", [
90
+ "HDP-广告40s-1080p", "季度 汇报 (终版)", "50% report", "a+b&c#1",
91
+ ])
92
+ def test_echoed_original_file_name_is_decoded(stem):
93
+ """The store echoes x:originalFileName still encoded; the uploader
94
+ decodes it before handing the file on (MDPublic createUploader.js:452,
95
+ ``decodeURIComponent``). Keeping the echo made a post show
96
+ "HDP-%E5%B9%BF%E5%91%8A40s-1080p.mp4" instead of the real name."""
97
+ from unittest.mock import MagicMock, patch
98
+
99
+ token = {"uptoken": "t", "key": "doc/20261013/k.mp4",
100
+ "serverName": "https://doc.mingdao.com/", "fileName": "k.mp4",
101
+ "url": "https://doc.mingdao.com/doc/20261013/k.mp4"}
102
+ sent = {}
103
+
104
+ def store(host, tok, content, *, original_name, ext, server_name=""):
105
+ sent["form"] = up_mod._encode_original_name(original_name)
106
+ return {"key": tok["key"], "etag": "e", "bucket": "mdoc",
107
+ "filePath": "doc/20261013/", "fileName": "k",
108
+ "fileExt": ext, "originalFileName": sent["form"]}
109
+
110
+ session = MagicMock(default_project_id="")
111
+ with patch.object(up_mod, "get_upload_token", return_value=token), \
112
+ patch.object(up_mod, "upload_host", return_value="https://up/"), \
113
+ patch.object(up_mod, "_post_to_store", side_effect=store):
114
+ d = up_mod.upload_bytes(session, content=b"x", name=stem + ".mp4")
115
+ assert sent["form"] != stem or stem.isascii()
116
+ assert d["originalFileName"] == stem
117
+ item = up_mod.attachment_items([d])[0]
118
+ assert item["originalFileName"] == item["oldOriginalFileName"] == stem
119
+
120
+
89
121
  # ── bootstrap routing ────────────────────────────────────────────────────
90
122
 
91
123
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hap-cli
3
- Version: 0.9.8
3
+ Version: 0.9.9
4
4
  Summary: CLI harness for Mingdao HAP - Enterprise no-code platform
5
5
  Author: hap-cli
6
6
  License: Apache-2.0
@@ -204,12 +204,14 @@ hap_cli/tests/test_calendar_date_range.py
204
204
  hap_cli/tests/test_calendar_discussion_cli.py
205
205
  hap_cli/tests/test_chart.py
206
206
  hap_cli/tests/test_chart_filter_merge.py
207
+ hap_cli/tests/test_chat_args_and_tables.py
207
208
  hap_cli/tests/test_chat_attachment_send.py
208
209
  hap_cli/tests/test_chat_messages_cli.py
209
210
  hap_cli/tests/test_chat_recall_cli.py
210
211
  hap_cli/tests/test_chat_send_socket.py
211
212
  hap_cli/tests/test_cli_access.py
212
213
  hap_cli/tests/test_coded_responses.py
214
+ hap_cli/tests/test_command_catalog_in_sync.py
213
215
  hap_cli/tests/test_condition_dsl.py
214
216
  hap_cli/tests/test_condition_dsl_entries.py
215
217
  hap_cli/tests/test_condition_dsl_readback.py
File without changes
File without changes
File without changes
File without changes