hap-cli 0.9.4__tar.gz → 0.9.6__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 (416) hide show
  1. {hap_cli-0.9.4 → hap_cli-0.9.6}/PKG-INFO +2 -1
  2. {hap_cli-0.9.4/hap_cli → hap_cli-0.9.6}/README.md +1 -0
  3. {hap_cli-0.9.4 → hap_cli-0.9.6/hap_cli}/README.md +1 -0
  4. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/README_CN.md +1 -0
  5. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/__init__.py +1 -1
  6. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/config_cmd.py +42 -0
  7. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/post_cmd.py +57 -7
  8. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/context.py +26 -1
  9. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/chat.py +36 -19
  10. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/post.py +58 -10
  11. hap_cli-0.9.6/hap_cli/core/relogin.py +255 -0
  12. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/session.py +50 -1
  13. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/upload.py +21 -10
  14. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/en/post.md +2 -0
  15. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/zh-Hans/post.md +2 -0
  16. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/locale/messages.json +30 -6
  17. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/conftest.py +12 -0
  18. hap_cli-0.9.6/hap_cli/tests/test_post_attachments.py +182 -0
  19. hap_cli-0.9.6/hap_cli/tests/test_relogin.py +234 -0
  20. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli.egg-info/PKG-INFO +2 -1
  21. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli.egg-info/SOURCES.txt +3 -0
  22. {hap_cli-0.9.4 → hap_cli-0.9.6}/MANIFEST.in +0 -0
  23. {hap_cli-0.9.4 → hap_cli-0.9.6}/app_live_tests/__init__.py +0 -0
  24. {hap_cli-0.9.4 → hap_cli-0.9.6}/app_live_tests/__main__.py +0 -0
  25. {hap_cli-0.9.4 → hap_cli-0.9.6}/app_live_tests/config.py +0 -0
  26. {hap_cli-0.9.4 → hap_cli-0.9.6}/app_live_tests/fixtures/__init__.py +0 -0
  27. {hap_cli-0.9.4 → hap_cli-0.9.6}/app_live_tests/fixtures/feedback_scenario.py +0 -0
  28. {hap_cli-0.9.4 → hap_cli-0.9.6}/app_live_tests/harness.py +0 -0
  29. {hap_cli-0.9.4 → hap_cli-0.9.6}/app_live_tests/smoke.py +0 -0
  30. {hap_cli-0.9.4 → hap_cli-0.9.6}/app_live_tests/state.py +0 -0
  31. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/__main__.py +0 -0
  32. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/_entry.py +0 -0
  33. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/__init__.py +0 -0
  34. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/app_cmd.py +0 -0
  35. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/app_creator_cmd.py +0 -0
  36. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/app_editor_cmd.py +0 -0
  37. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/attachment_cmd.py +0 -0
  38. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/auth_cmd.py +0 -0
  39. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/calendar_cmd.py +0 -0
  40. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/chart_cmd.py +0 -0
  41. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/chat_cmd.py +0 -0
  42. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/chatbot_cmd.py +0 -0
  43. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/contact_cmd.py +0 -0
  44. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/department_cmd.py +0 -0
  45. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/group_cmd.py +0 -0
  46. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/guide_cmd.py +0 -0
  47. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/icon_cmd.py +0 -0
  48. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/instance_cmd.py +0 -0
  49. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/node_cmd.py +0 -0
  50. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/optionset_cmd.py +0 -0
  51. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/page_cmd.py +0 -0
  52. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/record_cmd.py +0 -0
  53. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/region_cmd.py +0 -0
  54. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/role_cmd.py +0 -0
  55. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/update_cmd.py +0 -0
  56. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/upload_cmd.py +0 -0
  57. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/v3_registry.py +0 -0
  58. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/workflow_cmd.py +0 -0
  59. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/commands/worksheet_cmd.py +0 -0
  60. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/__init__.py +0 -0
  61. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/action_spec_adapter.py +0 -0
  62. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app.py +0 -0
  63. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/__init__.py +0 -0
  64. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/_hapmeta/__init__.py +0 -0
  65. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/_hapmeta/control_type_codes.py +0 -0
  66. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/_hapmeta/worksheet_templates.py +0 -0
  67. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/charts.py +0 -0
  68. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/cleanup.py +0 -0
  69. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/compiler.py +0 -0
  70. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/config.py +0 -0
  71. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/design/design.schema.json +0 -0
  72. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/errors.py +0 -0
  73. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/examples/minimal.design.json +0 -0
  74. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/executor.py +0 -0
  75. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/fields.py +0 -0
  76. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/hap.py +0 -0
  77. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/merge.py +0 -0
  78. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/recording/__init__.py +0 -0
  79. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/recording/console.py +0 -0
  80. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/recording/jsonl.py +0 -0
  81. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/recording/mirror.py +0 -0
  82. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/recording/report.py +0 -0
  83. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/schema.py +0 -0
  84. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/seed/INSTRUCTIONS.md +0 -0
  85. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/seed/__init__.py +0 -0
  86. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/seed/cli.py +0 -0
  87. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/seed/executor.py +0 -0
  88. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/seed/resources/attachments.json +0 -0
  89. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/seed/resources/sample.docx +0 -0
  90. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/seed/resources/sample.pdf +0 -0
  91. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/seed/resources/sample_images.json +0 -0
  92. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/seed/template.py +0 -0
  93. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/selftest.py +0 -0
  94. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/smoke.py +0 -0
  95. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/steps.py +0 -0
  96. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/store.py +0 -0
  97. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/validate.py +0 -0
  98. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/app_creator/workflow_dsl.py +0 -0
  99. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/attachment.py +0 -0
  100. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/auth.py +0 -0
  101. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/calendar_mod.py +0 -0
  102. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/chart.py +0 -0
  103. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/chatbot.py +0 -0
  104. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/cli_access.py +0 -0
  105. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/condition_dsl.py +0 -0
  106. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/contact.py +0 -0
  107. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/control_type_codes.py +0 -0
  108. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/department.py +0 -0
  109. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/editor/__init__.py +0 -0
  110. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/editor/_hapmeta/__init__.py +0 -0
  111. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/editor/_hapmeta/control_type_codes.py +0 -0
  112. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/editor/apply.py +0 -0
  113. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/editor/componentlower.py +0 -0
  114. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/editor/editspec/component.schema.json +0 -0
  115. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/editor/editspec/custom-action.schema.json +0 -0
  116. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/editor/editspec/envelope.schema.json +0 -0
  117. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/editor/editspec/field.schema.json +0 -0
  118. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/editor/editspec.py +0 -0
  119. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/editor/errors.py +0 -0
  120. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/editor/fieldlower.py +0 -0
  121. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/editor/jsonschema_mini.py +0 -0
  122. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/editor/models.py +0 -0
  123. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/editor/ops.py +0 -0
  124. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/editor/planner.py +0 -0
  125. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/editor/reader.py +0 -0
  126. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/field_normalizer.py +0 -0
  127. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/field_spec_adapter.py +0 -0
  128. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/filter_translator.py +0 -0
  129. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/filter_v3.py +0 -0
  130. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/flow_node.py +0 -0
  131. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/global_meta.py +0 -0
  132. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/group.py +0 -0
  133. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/guide.py +0 -0
  134. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/icon_index.py +0 -0
  135. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/instance.py +0 -0
  136. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/layout_check.py +0 -0
  137. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/logger.py +0 -0
  138. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/optionset.py +0 -0
  139. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/page.py +0 -0
  140. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/record.py +0 -0
  141. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/record_defaults.py +0 -0
  142. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/record_form_checks.py +0 -0
  143. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/record_lookups.py +0 -0
  144. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/record_rules.py +0 -0
  145. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/relation_scope.py +0 -0
  146. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/response_crypto.py +0 -0
  147. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/role.py +0 -0
  148. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/role_perm_builder.py +0 -0
  149. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/rule_spec_adapter.py +0 -0
  150. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/token_crypto.py +0 -0
  151. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/update.py +0 -0
  152. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/v3/__init__.py +0 -0
  153. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/v3/dispatcher.py +0 -0
  154. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/v3/render.py +0 -0
  155. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/v3/schema.py +0 -0
  156. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/view_spec_adapter.py +0 -0
  157. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/workflow.py +0 -0
  158. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/workflow_node_dsl.py +0 -0
  159. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/worksheet.py +0 -0
  160. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/worksheet_form.py +0 -0
  161. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/worksheet_reference.py +0 -0
  162. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/core/worksheet_templates.py +0 -0
  163. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/en/approval.md +0 -0
  164. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/en/chart.md +0 -0
  165. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/en/messages.md +0 -0
  166. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/en/overview.md +0 -0
  167. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/en/record.md +0 -0
  168. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/en/setup.md +0 -0
  169. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/en/skills.md +0 -0
  170. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/en/workflow.md +0 -0
  171. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/en/worksheet.md +0 -0
  172. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/index.json +0 -0
  173. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/zh-Hans/approval.md +0 -0
  174. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/zh-Hans/chart.md +0 -0
  175. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/zh-Hans/messages.md +0 -0
  176. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/zh-Hans/overview.md +0 -0
  177. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/zh-Hans/record.md +0 -0
  178. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/zh-Hans/setup.md +0 -0
  179. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/zh-Hans/skills.md +0 -0
  180. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/zh-Hans/workflow.md +0 -0
  181. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/guide/zh-Hans/worksheet.md +0 -0
  182. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/i18n.py +0 -0
  183. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/locale/__init__.py +0 -0
  184. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/locale/messages.schema.json +0 -0
  185. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/__init__.py +0 -0
  186. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_action_mdpublic_parity.py +0 -0
  187. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_advanced_setting_guard.py +0 -0
  188. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_app_creator.py +0 -0
  189. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_app_editor.py +0 -0
  190. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_app_export_usage.py +0 -0
  191. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_app_light_color.py +0 -0
  192. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_app_section_name.py +0 -0
  193. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_approval_submit_fill_cli.py +0 -0
  194. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_approval_wire.py +0 -0
  195. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_atomic_write.py +0 -0
  196. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_attachment_share.py +0 -0
  197. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_auth_prerelease.py +0 -0
  198. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_batch_add_atomic.py +0 -0
  199. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_bug_036430.py +0 -0
  200. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_bug_036750.py +0 -0
  201. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_calendar_date_range.py +0 -0
  202. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_calendar_discussion_cli.py +0 -0
  203. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_chart.py +0 -0
  204. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_chart_filter_merge.py +0 -0
  205. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_chat_attachment_send.py +0 -0
  206. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_chat_messages_cli.py +0 -0
  207. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_chat_recall_cli.py +0 -0
  208. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_chat_send_socket.py +0 -0
  209. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_cli_access.py +0 -0
  210. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_coded_responses.py +0 -0
  211. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_condition_dsl.py +0 -0
  212. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_condition_dsl_entries.py +0 -0
  213. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_condition_dsl_readback.py +0 -0
  214. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_config_cmd.py +0 -0
  215. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_content_language.py +0 -0
  216. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_control_lookup_guard.py +0 -0
  217. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_core.py +0 -0
  218. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_create_worksheet_partial.py +0 -0
  219. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_destructive_confirm_cli.py +0 -0
  220. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_dsl_existing_node_refs.py +0 -0
  221. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_dsl_multi_record_guard.py +0 -0
  222. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_editor_inline_subtable.py +0 -0
  223. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_engine_core_parity.py +0 -0
  224. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_arg_consistency.py +0 -0
  225. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_bidirectional.py +0 -0
  226. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_discussion_mentions.py +0 -0
  227. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_entry_module.py +0 -0
  228. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_field_record_ref.py +0 -0
  229. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_http_error_body.py +0 -0
  230. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_json_anywhere.py +0 -0
  231. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_json_file_arg.py +0 -0
  232. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_layout_check.py +0 -0
  233. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_node_get_detail.py +0 -0
  234. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_node_summary.py +0 -0
  235. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_post_cursor.py +0 -0
  236. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_publish_reasons.py +0 -0
  237. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_replicate_workflow.py +0 -0
  238. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_save_fields_shape.py +0 -0
  239. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_subgroups.py +0 -0
  240. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_subtable_read.py +0 -0
  241. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_worksheet_references.py +0 -0
  242. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_worksheet_visibility.py +0 -0
  243. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fb_worksheet_workflows.py +0 -0
  244. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_fields_mdpublic_parity.py +0 -0
  245. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_full_e2e.py +0 -0
  246. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_g1_chart_parity.py +0 -0
  247. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_g1_record_parity.py +0 -0
  248. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_g1_upload_parity.py +0 -0
  249. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_g1_worksheet_parity.py +0 -0
  250. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_g2_coverage_parity.py +0 -0
  251. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_g3_workflow_parity.py +0 -0
  252. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_g4_approval_parity.py +0 -0
  253. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_g5_low_frequency_parity.py +0 -0
  254. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_g6_advanced_fields.py +0 -0
  255. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_g6_fields_roundtrip.py +0 -0
  256. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_g7_misc_gaps.py +0 -0
  257. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_g7b_permanent_delete.py +0 -0
  258. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_g8_filter_operator.py +0 -0
  259. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_g8b_pivot_operators.py +0 -0
  260. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_g8c_empty_filter_and_help_truth.py +0 -0
  261. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_g9_appid_resolve.py +0 -0
  262. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_global_meta.py +0 -0
  263. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_guide.py +0 -0
  264. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_guide_sections.py +0 -0
  265. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_i18n.py +0 -0
  266. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_inner_flow_batch_add.py +0 -0
  267. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_instance_envelope.py +0 -0
  268. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_instance_history_cli.py +0 -0
  269. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_integration.py +0 -0
  270. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_integration_approval.py +0 -0
  271. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_integration_approval_actions.py +0 -0
  272. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_integration_calendar.py +0 -0
  273. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_integration_destructive.py +0 -0
  274. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_integration_misc.py +0 -0
  275. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_integration_post.py +0 -0
  276. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_integration_social.py +0 -0
  277. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_integration_v3.py +0 -0
  278. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_integration_workflow.py +0 -0
  279. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_integration_worksheet_extra.py +0 -0
  280. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_jsonschema_mini_copy.py +0 -0
  281. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_member_relation_array_wrap.py +0 -0
  282. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_multi_profile.py +0 -0
  283. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_no_workflow_unsupported.py +0 -0
  284. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_noninteractive_confirm.py +0 -0
  285. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_org_approval_v3_semantic_cli.py +0 -0
  286. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_org_id_cli.py +0 -0
  287. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_org_id_docs.py +0 -0
  288. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_page_filters_group_read.py +0 -0
  289. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_page_filters_group_update.py +0 -0
  290. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_page_save_page_id.py +0 -0
  291. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_parameter_conventions.py +0 -0
  292. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_parameter_mapping_registry.py +0 -0
  293. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_post_scope_cli.py +0 -0
  294. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_record_batch_v3_semantic_cli.py +0 -0
  295. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_record_business_rules.py +0 -0
  296. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_record_defaults.py +0 -0
  297. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_record_doc_id_hidden.py +0 -0
  298. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_record_field_alias.py +0 -0
  299. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_record_form_checks.py +0 -0
  300. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_record_run_action.py +0 -0
  301. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_record_v3_semantic_cli.py +0 -0
  302. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_record_write_fixes.py +0 -0
  303. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_relation_scope.py +0 -0
  304. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_rmw_mdpublic_parity.py +0 -0
  305. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_role_app_scope.py +0 -0
  306. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_rule_filters_and_field_warning.py +0 -0
  307. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_save_action_silent_drop.py +0 -0
  308. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_save_rule_spec.py +0 -0
  309. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_select_add_option.py +0 -0
  310. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_select_rejects_relation_value.py +0 -0
  311. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_semantic_types_registry.py +0 -0
  312. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_subtable_mdpublic_parity.py +0 -0
  313. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_update.py +0 -0
  314. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_update_mode.py +0 -0
  315. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_upload_allow_down.py +0 -0
  316. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_upload_host_resolution.py +0 -0
  317. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_upload_mdpublic_parity.py +0 -0
  318. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_v3_api_schema_loader.py +0 -0
  319. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_v3_bool_flags.py +0 -0
  320. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_v3_dispatcher.py +0 -0
  321. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_v3_registry_coverage.py +0 -0
  322. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_v3_response_format_json.py +0 -0
  323. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_v3_session.py +0 -0
  324. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_v3_yaml_translation.py +0 -0
  325. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_view_mdpublic_parity.py +0 -0
  326. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_wf_config_keys.py +0 -0
  327. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_wf_inner_scope.py +0 -0
  328. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_wf_json_file_arg.py +0 -0
  329. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_wf_node_delete_missing.py +0 -0
  330. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_wf_save_action_dsl_fields.py +0 -0
  331. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_wf_structure_listing.py +0 -0
  332. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_wf_trigger_outcome.py +0 -0
  333. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_wf_trigger_preserve.py +0 -0
  334. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_wo4_result_handling.py +0 -0
  335. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_workflow_code_node.py +0 -0
  336. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_workflow_condition_field_types.py +0 -0
  337. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_workflow_condition_slots.py +0 -0
  338. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_workflow_delete_cascade.py +0 -0
  339. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_workflow_envelope_errors.py +0 -0
  340. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_workflow_lifecycle_wire.py +0 -0
  341. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_workflow_list_cli.py +0 -0
  342. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_workflow_node_wire.py +0 -0
  343. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_workflow_publish_inner.py +0 -0
  344. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_workflow_read_write_keys.py +0 -0
  345. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_workflow_v3_semantic_cli.py +0 -0
  346. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_worksheet_create_section.py +0 -0
  347. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_worksheet_crud_cli.py +0 -0
  348. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_worksheet_filter_read.py +0 -0
  349. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_worksheet_switch.py +0 -0
  350. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/tests/test_worksheet_v3_semantic_cli.py +0 -0
  351. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/utils/__init__.py +0 -0
  352. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/utils/atomic_write.py +0 -0
  353. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/utils/confirm.py +0 -0
  354. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/utils/formatting.py +0 -0
  355. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/utils/options.py +0 -0
  356. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli/utils/parameter_mapping.py +0 -0
  357. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli.egg-info/dependency_links.txt +0 -0
  358. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli.egg-info/entry_points.txt +0 -0
  359. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli.egg-info/requires.txt +0 -0
  360. {hap_cli-0.9.4 → hap_cli-0.9.6}/hap_cli.egg-info/top_level.txt +0 -0
  361. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/__init__.py +0 -0
  362. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/__main__.py +0 -0
  363. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/_wftest.py +0 -0
  364. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/charts.py +0 -0
  365. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/cleanup.py +0 -0
  366. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/compiler.py +0 -0
  367. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/config.py +0 -0
  368. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/errors.py +0 -0
  369. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/executor.py +0 -0
  370. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/fields.py +0 -0
  371. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/hap.py +0 -0
  372. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/recording/__init__.py +0 -0
  373. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/recording/console.py +0 -0
  374. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/recording/jsonl.py +0 -0
  375. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/recording/mirror.py +0 -0
  376. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/recording/report.py +0 -0
  377. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/schema.py +0 -0
  378. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/seed/__init__.py +0 -0
  379. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/seed/cli.py +0 -0
  380. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/seed/executor.py +0 -0
  381. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/seed/template.py +0 -0
  382. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/selftest.py +0 -0
  383. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/smoke.py +0 -0
  384. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/step.py +0 -0
  385. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/steps.py +0 -0
  386. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/store.py +0 -0
  387. {hap_cli-0.9.4 → hap_cli-0.9.6}/live_tests/workflow_dsl.py +0 -0
  388. {hap_cli-0.9.4 → hap_cli-0.9.6}/setup.cfg +0 -0
  389. {hap_cli-0.9.4 → hap_cli-0.9.6}/setup.py +0 -0
  390. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/INDEX.json +0 -0
  391. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/add_member_to_role.yaml +0 -0
  392. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/batch_delete_records.yaml +0 -0
  393. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/create_optionset.yaml +0 -0
  394. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/create_role.yaml +0 -0
  395. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/delete_optionset.yaml +0 -0
  396. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/delete_record.yaml +0 -0
  397. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/delete_role.yaml +0 -0
  398. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/delete_worksheet.yaml +0 -0
  399. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/get_app_info.yaml +0 -0
  400. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/get_app_knowledge_list.yaml +0 -0
  401. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/get_app_worksheets_list.yaml +0 -0
  402. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/get_optionset_list.yaml +0 -0
  403. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/get_record_details.yaml +0 -0
  404. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/get_record_discussions.yaml +0 -0
  405. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/get_record_list.yaml +0 -0
  406. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/get_record_logs.yaml +0 -0
  407. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/get_record_pivot_data.yaml +0 -0
  408. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/get_record_relations.yaml +0 -0
  409. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/get_record_share_link.yaml +0 -0
  410. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/get_regions.yaml +0 -0
  411. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/get_role_details.yaml +0 -0
  412. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/get_role_list.yaml +0 -0
  413. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/knowledge_search.yaml +0 -0
  414. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/leave_all_roles.yaml +0 -0
  415. {hap_cli-0.9.4 → hap_cli-0.9.6}/sources/v3-api-schema/remove_member_from_role.yaml +0 -0
  416. {hap_cli-0.9.4 → hap_cli-0.9.6}/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.4
3
+ Version: 0.9.6
4
4
  Summary: CLI harness for Mingdao HAP - Enterprise no-code platform
5
5
  Author: hap-cli
6
6
  License: Apache-2.0
@@ -339,6 +339,7 @@ discover every subcommand.
339
339
  | `config completion [bash\|zsh\|fish] [--install]` | Enable `<Tab>` completion |
340
340
  | `config language [LANG]` | Switch UI language (`en` / `zh-Hans`, or `auto` to follow the account language) |
341
341
  | `config update [auto\|notify\|off]` | Self-upgrade mode; `notify` only reports, `off` never checks |
342
+ | `config auto-login [on\|off]` | Renew an expired login in the browser (one click on Authorize) and carry on; `off` stops with "not logged in" |
342
343
  | `config log on / off / status` | Toggle and inspect API logging |
343
344
  | `config log level LEVEL` | `DEBUG / INFO / WARNING / ERROR / CRITICAL` |
344
345
  | `config log view [--lines N] [--no-follow]` | Tail the log file |
@@ -310,6 +310,7 @@ discover every subcommand.
310
310
  | `config completion [bash\|zsh\|fish] [--install]` | Enable `<Tab>` completion |
311
311
  | `config language [LANG]` | Switch UI language (`en` / `zh-Hans`, or `auto` to follow the account language) |
312
312
  | `config update [auto\|notify\|off]` | Self-upgrade mode; `notify` only reports, `off` never checks |
313
+ | `config auto-login [on\|off]` | Renew an expired login in the browser (one click on Authorize) and carry on; `off` stops with "not logged in" |
313
314
  | `config log on / off / status` | Toggle and inspect API logging |
314
315
  | `config log level LEVEL` | `DEBUG / INFO / WARNING / ERROR / CRITICAL` |
315
316
  | `config log view [--lines N] [--no-follow]` | Tail the log file |
@@ -310,6 +310,7 @@ discover every subcommand.
310
310
  | `config completion [bash\|zsh\|fish] [--install]` | Enable `<Tab>` completion |
311
311
  | `config language [LANG]` | Switch UI language (`en` / `zh-Hans`, or `auto` to follow the account language) |
312
312
  | `config update [auto\|notify\|off]` | Self-upgrade mode; `notify` only reports, `off` never checks |
313
+ | `config auto-login [on\|off]` | Renew an expired login in the browser (one click on Authorize) and carry on; `off` stops with "not logged in" |
313
314
  | `config log on / off / status` | Toggle and inspect API logging |
314
315
  | `config log level LEVEL` | `DEBUG / INFO / WARNING / ERROR / CRITICAL` |
315
316
  | `config log view [--lines N] [--no-follow]` | Tail the log file |
@@ -289,6 +289,7 @@ hap --json worksheet record list WORKSHEET_ID
289
289
  | `config completion [bash\|zsh\|fish] [--install]` | 启用 `<Tab>` 补全 |
290
290
  | `config language [LANG]` | 切换显示语言(`en` / `zh-Hans`;`auto` 跟随登录账号的语言) |
291
291
  | `config update [auto\|notify\|off]` | 自动升级开关;`notify` 只提示不安装,`off` 不检查 |
292
+ | `config auto-login [on\|off]` | 登录过期时自动打开浏览器授权页,点一下「授权」命令继续执行;`off` 则直接报未登录 |
292
293
  | `config log on / off / status` | 日志开关与状态 |
293
294
  | `config log level LEVEL` | 设置日志级别(`DEBUG/INFO/WARNING/ERROR/CRITICAL`) |
294
295
  | `config log view [--lines N] [--no-follow]` | 跟踪日志文件 |
@@ -3,7 +3,7 @@
3
3
  import sys as _sys
4
4
  import types as _types
5
5
 
6
- __version__ = "0.9.4"
6
+ __version__ = "0.9.6"
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
@@ -126,6 +126,7 @@ def config_completion(shell, install):
126
126
  @pass_context
127
127
  def config_show(ctx):
128
128
  """Display current harness configuration."""
129
+ from hap_cli.core.relogin import get_mode as get_auto_login_mode
129
130
  from hap_cli.core.update import get_update_mode
130
131
 
131
132
  log_cfg = load_logging_config()
@@ -136,6 +137,7 @@ def config_show(ctx):
136
137
  "file": str(resolve_log_path(log_cfg)),
137
138
  },
138
139
  "update": get_update_mode(),
140
+ "auto_login": get_auto_login_mode(),
139
141
  }
140
142
 
141
143
  def _human(d):
@@ -144,6 +146,7 @@ def config_show(ctx):
144
146
  click.echo(f" level : {d['logging']['level']}")
145
147
  click.echo(f" file : {d['logging']['file']}")
146
148
  click.echo(f"update : {d['update']}")
149
+ click.echo(f"auto-login: {d['auto_login']}")
147
150
 
148
151
  ctx.output(data, _human)
149
152
 
@@ -253,6 +256,45 @@ def config_update(ctx, mode):
253
256
  click.echo(f"Self-update set to: {mode}")
254
257
 
255
258
 
259
+ # ── `hap config auto-login` ───────────────────────────────────────────────
260
+
261
+
262
+ @config.command("auto-login")
263
+ @click.argument("mode", required=False, type=click.Choice(["on", "off"]))
264
+ @pass_context
265
+ def config_auto_login(ctx, mode):
266
+ """Control whether an expired login is renewed in the browser.
267
+
268
+ \b
269
+ on when a command finds your login expired, open the browser
270
+ authorization page, wait for you to click Authorize, then
271
+ carry on (default)
272
+ off stop with a "not logged in" error instead
273
+
274
+ Without an argument, shows the current setting. It never applies over
275
+ SSH, in CI, or where no browser can be shown. Setting the environment
276
+ variable HAP_AUTO_LOGIN=0 turns it off for one shell.
277
+ """
278
+ from hap_cli.core.relogin import CONFIG_KEY, get_mode
279
+ from hap_cli.core.session import save_config
280
+
281
+ if mode is None:
282
+ current = get_mode()
283
+ if ctx.json_mode:
284
+ from hap_cli.utils.formatting import output_json
285
+ output_json({"auto_login": current})
286
+ else:
287
+ click.echo(f"Auto-login: {current}")
288
+ return
289
+
290
+ save_config({CONFIG_KEY: mode})
291
+ if ctx.json_mode:
292
+ from hap_cli.utils.formatting import output_json
293
+ output_json({"status": "ok", "auto_login": mode})
294
+ else:
295
+ click.echo(f"Auto-login set to: {mode}")
296
+
297
+
256
298
  # ── `hap config language` ─────────────────────────────────────────────────
257
299
 
258
300
 
@@ -131,6 +131,19 @@ def _resolve_markers(
131
131
  return out
132
132
 
133
133
 
134
+ def _simplify_attachments(items: Any) -> list[dict[str, Any]]:
135
+ out = []
136
+ for a in items or []:
137
+ if not isinstance(a, dict):
138
+ continue
139
+ out.append({
140
+ "id": a.get("fileID"),
141
+ "name": f"{a.get('originalFilename') or ''}{a.get('ext') or ''}",
142
+ "size": a.get("filesize"),
143
+ })
144
+ return out
145
+
146
+
134
147
  def _simplify_comment(c: dict[str, Any]) -> dict[str, Any]:
135
148
  text = _resolve_markers(
136
149
  c.get("message") or "",
@@ -152,6 +165,9 @@ def _simplify_comment(c: dict[str, Any]) -> dict[str, Any]:
152
165
  }
153
166
  if c.get("withAttachment") and str(c["withAttachment"]) != "0":
154
167
  out["has_attachment"] = True
168
+ files = _simplify_attachments(c.get("attachments"))
169
+ if files:
170
+ out["attachments"] = files
155
171
  return out
156
172
 
157
173
 
@@ -203,6 +219,9 @@ def _simplify_post(p: dict[str, Any]) -> dict[str, Any]:
203
219
  m_groups = [_simplify_group_ref(g) for g in (p.get("rGroupList") or [])]
204
220
  if m_groups:
205
221
  out["mentioned_groups"] = m_groups
222
+ files = _simplify_attachments(p.get("attachments"))
223
+ if files:
224
+ out["attachments"] = files
206
225
  return out
207
226
 
208
227
 
@@ -377,6 +396,8 @@ def _render_post_detail(detail: dict[str, Any]) -> None:
377
396
  click.echo("")
378
397
  for line in (detail.get("text") or "").splitlines() or [""]:
379
398
  click.echo(f" {line}")
399
+ for f in detail.get("attachments") or []:
400
+ click.echo(f" 📎 {f.get('name')}")
380
401
  click.echo("")
381
402
 
382
403
  stats = (
@@ -414,6 +435,8 @@ def _render_post_detail(detail: dict[str, Any]) -> None:
414
435
  click.echo(header)
415
436
  for line in (c.get("text") or "").splitlines() or [""]:
416
437
  click.echo(f" {line}")
438
+ for f in c.get("attachments") or []:
439
+ click.echo(f" 📎 {f.get('name')}")
417
440
  click.echo("")
418
441
 
419
442
 
@@ -669,7 +692,13 @@ def post_get(ctx, post_id):
669
692
  default=0,
670
693
  type=int,
671
694
  show_default=True,
672
- help="Post type: 0=text, 3=link, 5=vote, 7=file",
695
+ help="Post type. Leave at 0 (text); adding --file makes it an "
696
+ "attachment post on its own.",
697
+ )
698
+ @click.option(
699
+ "--file", "-f", "files", multiple=True,
700
+ help="Attach a file: a local path or an http(s) address. Repeat for "
701
+ "several. Videos, pictures and documents all work.",
673
702
  )
674
703
  @click.option(
675
704
  "--to-group",
@@ -694,15 +723,20 @@ def post_get(ctx, post_id):
694
723
  @click.option("--dry-run", is_flag=True,
695
724
  help="Show the audience and what would be sent, without publishing.")
696
725
  @pass_context
697
- def post_create(ctx, org_id, message, post_type, share_group_ids, share_org_ids,
698
- legacy_group_ids, legacy_org_ids, card_group_ids, dry_run):
726
+ def post_create(ctx, org_id, message, post_type, files, share_group_ids,
727
+ share_org_ids, legacy_group_ids, legacy_org_ids,
728
+ card_group_ids, dry_run):
699
729
  """Create a new post in the given organization.
700
730
 
701
731
  Audience is set with --to-group / --to-org and defaults to everyone in
702
732
  --org-id when neither is given. Who can see a post is covered in
703
733
  `hap guide post audience`; the group-chat card is `hap guide post card`.
734
+ Files given with --file are uploaded and attached to the post.
704
735
  """
705
736
  try:
737
+ if post_type == post_mod.POST_TYPE_ATTACHMENT and not files:
738
+ raise click.UsageError(
739
+ "An attachment post needs at least one --file.")
706
740
  share_group_ids = tuple(share_group_ids) + tuple(legacy_group_ids)
707
741
  share_org_ids = tuple(share_org_ids) + tuple(legacy_org_ids)
708
742
  if dry_run:
@@ -712,11 +746,14 @@ def post_create(ctx, org_id, message, post_type, share_group_ids, share_org_ids,
712
746
  ) or [f"org:{org_id or '<current>'} (everyone, default)"]
713
747
  ctx.output(
714
748
  {"audience": audience, "cardToGroups": list(card_group_ids),
715
- "message": message, "published": False},
749
+ "message": message, "files": list(files),
750
+ "published": False},
716
751
  lambda d: click.echo(
717
752
  "Would publish to: " + ", ".join(d["audience"])
718
753
  + (f"; card to groups: {', '.join(d['cardToGroups'])}"
719
- if d["cardToGroups"] else "")),
754
+ if d["cardToGroups"] else "")
755
+ + (f"; files: {', '.join(d['files'])}"
756
+ if d["files"] else "")),
720
757
  )
721
758
  return
722
759
  session = ctx.get_session()
@@ -741,6 +778,8 @@ def post_create(ctx, org_id, message, post_type, share_group_ids, share_org_ids,
741
778
  + ". Pick a group whose feed is on, or send a card to the "
742
779
  "chat instead with --card-to-group.")
743
780
  pid = require_api_project_id(session, org_id)
781
+ attachments = (post_mod.upload_post_files(session, list(files))
782
+ if files else None)
744
783
  raw = post_mod.add_post(
745
784
  session,
746
785
  project_id=pid,
@@ -748,6 +787,7 @@ def post_create(ctx, org_id, message, post_type, share_group_ids, share_org_ids,
748
787
  post_type=post_type,
749
788
  share_group_ids=list(share_group_ids) or None,
750
789
  share_project_ids=list(share_org_ids) or None,
790
+ attachments=attachments,
751
791
  )
752
792
  post_obj = raw.get("post") if isinstance(raw, dict) else None
753
793
  summary = _simplify_post(post_obj) if post_obj else {"raw": raw}
@@ -821,14 +861,22 @@ def post_delete(ctx, post_id, yes):
821
861
  default="",
822
862
  help="Member id being replied to (optional; pairs with --reply-id)",
823
863
  )
864
+ @click.option(
865
+ "--file", "-f", "files", multiple=True,
866
+ help="Attach a file: a local path or an http(s) address. Repeat for "
867
+ "several. Videos, pictures and documents all work.",
868
+ )
824
869
  @pass_context
825
- def post_comment(ctx, post_id, message, reply_id, reply_account_id):
826
- """Add a comment to a post."""
870
+ def post_comment(ctx, post_id, message, reply_id, reply_account_id, files):
871
+ """Add a comment to a post, optionally with files attached."""
827
872
  try:
828
873
  session = ctx.get_session()
874
+ attachments = (post_mod.upload_post_files(session, list(files))
875
+ if files else None)
829
876
  raw = post_mod.add_comment(
830
877
  session, post_id, message,
831
878
  reply_id=reply_id, reply_account_id=reply_account_id,
879
+ attachments=attachments,
832
880
  )
833
881
  comment_obj = raw.get("comment") if isinstance(raw, dict) else None
834
882
  summary = _simplify_comment(comment_obj) if comment_obj else {"raw": raw}
@@ -864,6 +912,8 @@ def post_comments(ctx, post_id):
864
912
  click.echo(header)
865
913
  for line in (c.get("text") or "").splitlines() or [""]:
866
914
  click.echo(f" {line}")
915
+ for f in c.get("attachments") or []:
916
+ click.echo(f" 📎 {f.get('name')}")
867
917
  click.echo(f" id: {c.get('id')}")
868
918
  click.echo("")
869
919
  ctx.output(comments, _render)
@@ -20,6 +20,27 @@ NOT_LOGGED_IN_HINT = (
20
20
  )
21
21
 
22
22
 
23
+ def _relogin_notice(login_url: str, timeout: int) -> None:
24
+ """Tell the user an authorization page is waiting for one click.
25
+
26
+ Written to stderr so ``--json`` output on stdout stays parseable; the
27
+ desktop notification is for callers (AI agents) whose terminal output
28
+ the user only sees after the command ends.
29
+ """
30
+ from hap_cli.core.relogin import desktop_notify
31
+ from hap_cli.i18n import t
32
+
33
+ click.echo(
34
+ t("Your HAP login has expired. A browser page is open — click "
35
+ "Authorize (授权) to continue (waiting up to {seconds}s).").format(
36
+ seconds=timeout),
37
+ err=True,
38
+ )
39
+ click.echo(f" {login_url}", err=True)
40
+ desktop_notify(t("Login expired — click Authorize (授权) in the browser "
41
+ "to let the command continue."))
42
+
43
+
23
44
  class Context:
24
45
  """Shared CLI context."""
25
46
 
@@ -43,6 +64,7 @@ class Context:
43
64
  """
44
65
  if self.session is None:
45
66
  self.session = Session.load(self.profile)
67
+ self.session.relogin_notice = _relogin_notice
46
68
  # One-time migration for sessions logged in before account_id
47
69
  # was persisted. Some HAP controllers (notably
48
70
  # Invitation/InviteUser) silently degrade when the AccountId
@@ -55,7 +77,10 @@ class Context:
55
77
  ):
56
78
  self.session._lazy_resolve_account_id()
57
79
  if require_auth and not self.session.auth_token:
58
- raise SessionError("Not logged in. Run 'hap auth login' first.")
80
+ # A saved environment without a token: authorize it again in
81
+ # the browser rather than stopping the command.
82
+ if not (self.session.login_url and self.session.recover_auth()):
83
+ raise SessionError("Not logged in. Run 'hap auth login' first.")
59
84
  return self.session
60
85
 
61
86
  def output(self, data, table_fn=None):
@@ -48,26 +48,43 @@ def _chatmq_get(
48
48
  # mirror the other transport hooks.
49
49
  from hap_cli.core import cli_access
50
50
 
51
+ from hap_cli.core.session import AuthenticationError
52
+
51
53
  cli_access.ensure_before_request(session, url)
52
- headers = {
53
- "Authorization": f"md_pss_id {session.auth_token}",
54
- "X-Requested-With": "XMLHttpRequest",
55
- "User-Agent": hap_user_agent(),
56
- }
57
- auth_for_log = redact_authorization(headers["Authorization"])
58
- logger.info(
59
- "HAP GET %s params=%s Authorization=%s",
60
- url,
61
- format_body_for_log(params) or "{}",
62
- auth_for_log,
63
- )
64
- response = requests.get(url, params=params, headers=headers, timeout=timeout)
65
- logger.info(
66
- "HAP GET %s -> %d %s",
67
- url,
68
- response.status_code,
69
- format_response_for_log(getattr(response, "text", "") or ""),
70
- )
54
+
55
+ def _send():
56
+ headers = {
57
+ "Authorization": f"md_pss_id {session.auth_token}",
58
+ "X-Requested-With": "XMLHttpRequest",
59
+ "User-Agent": hap_user_agent(),
60
+ }
61
+ auth_for_log = redact_authorization(headers["Authorization"])
62
+ logger.info(
63
+ "HAP GET %s params=%s Authorization=%s",
64
+ url,
65
+ format_body_for_log(params) or "{}",
66
+ auth_for_log,
67
+ )
68
+ response = requests.get(url, params=params, headers=headers, timeout=timeout)
69
+ logger.info(
70
+ "HAP GET %s -> %d %s",
71
+ url,
72
+ response.status_code,
73
+ format_response_for_log(getattr(response, "text", "") or ""),
74
+ )
75
+ return response
76
+
77
+ response = _send()
78
+ # An expired login gets the same one-shot browser re-authorization as
79
+ # the main transport (Session._post); the read is then resent once.
80
+ if response.status_code == 401:
81
+ if not session.recover_auth():
82
+ raise AuthenticationError(
83
+ "Authentication failed (HTTP 401). "
84
+ "Your session token is missing, invalid, or expired.",
85
+ status_code=401,
86
+ )
87
+ response = _send()
71
88
  response.raise_for_status()
72
89
  return response.json()
73
90
 
@@ -24,6 +24,7 @@ Response envelopes (from a live probe on SaaS):
24
24
  * ``GetPostDetail`` → bare post object (with ``success: "1"``)
25
25
  """
26
26
 
27
+ import json
27
28
  import logging
28
29
  from typing import Any, Optional
29
30
 
@@ -219,6 +220,40 @@ def get_post_detail(session: Session, post_id: str) -> dict[str, Any]:
219
220
  return session.api_call("Post", "GetPostDetail", {"postId": post_id})
220
221
 
221
222
 
223
+ # postType of a post carrying uploaded files ("pic and doc"). The feed's
224
+ # own types: 0 text, 1 link, 2 picture, 3 document, 7 vote, 9 attachments
225
+ # (MDPublic src/pages/feed/components/post/postComponent/factory.jsx:18-41,
226
+ # createFeed/index.js:18-22).
227
+ POST_TYPE_ATTACHMENT = 9
228
+
229
+
230
+ def _attachment_fields(attachments: list[dict[str, Any]]) -> dict[str, str]:
231
+ """The two attachment keys, as JSON strings — the server takes strings
232
+ here, not arrays. Knowledge-center references are not supported, so
233
+ that list is always empty, as the composer sends it when none are
234
+ picked."""
235
+ return {
236
+ "attachments": json.dumps(attachments, ensure_ascii=False),
237
+ "knowledgeAttach": "[]",
238
+ }
239
+
240
+
241
+ def upload_post_files(session: Session, sources: list[str]) -> list[dict[str, Any]]:
242
+ """Upload local paths / http(s) addresses and return attachment items
243
+ for :func:`add_post` / :func:`add_comment`.
244
+
245
+ No organization is named for the upload credential: the feed mounts
246
+ its uploader without a projectId (MDPublic createFeed/
247
+ CreateFeedContent.jsx:124-136), same as chat does here.
248
+ """
249
+ from hap_cli.core import upload as upload_mod
250
+
251
+ descriptors = upload_mod.upload_files(
252
+ session, upload_mod.source_descriptors(list(sources)))
253
+ logger.info("post: uploaded %d attachment(s)", len(descriptors))
254
+ return upload_mod.attachment_items(descriptors)
255
+
256
+
222
257
  def add_post(
223
258
  session: Session,
224
259
  project_id: str,
@@ -228,9 +263,16 @@ def add_post(
228
263
  share_group_ids: Optional[list[str]] = None,
229
264
  share_project_ids: Optional[list[str]] = None,
230
265
  radio_project_ids: str = "",
266
+ attachments: Optional[list[dict[str, Any]]] = None,
231
267
  ) -> dict[str, Any]:
232
268
  """Create a post via ``Post.AddPost``.
233
269
 
270
+ ``attachments`` are uploaded-file items (see :func:`upload_post_files`).
271
+ Files make it an attachment post — ``postType`` 9 — and travel as JSON
272
+ strings next to an empty knowledge-center list, exactly as the feed's
273
+ composer sends them (MDPublic src/pages/feed/components/createFeed/
274
+ index.js:18-22 and :163-180; pd-openweb identical).
275
+
234
276
  ``scope`` is a ``PostShareScopeReq`` object — not an int — and it is
235
277
  what decides **who can see the post**. The frontend
236
278
  (``pd-openweb/src/pages/feed/components/createFeed/index.js``) posts
@@ -261,15 +303,16 @@ def add_post(
261
303
  "shareGroupIds": groups,
262
304
  "shareProjectIds": orgs,
263
305
  }
264
- return session.api_call(
265
- "Post", "AddPost",
266
- {
267
- "projectId": project_id,
268
- "postType": post_type,
269
- "postMsg": message,
270
- "scope": scope,
271
- },
272
- )
306
+ data: dict[str, Any] = {
307
+ "projectId": project_id,
308
+ "postType": post_type,
309
+ "postMsg": message,
310
+ "scope": scope,
311
+ }
312
+ if attachments:
313
+ data["postType"] = POST_TYPE_ATTACHMENT
314
+ data.update(_attachment_fields(attachments))
315
+ return session.api_call("Post", "AddPost", data)
273
316
 
274
317
 
275
318
  def edit_post(
@@ -304,17 +347,22 @@ def add_comment(
304
347
  message: str,
305
348
  reply_id: str = "",
306
349
  reply_account_id: str = "",
350
+ attachments: Optional[list[dict[str, Any]]] = None,
307
351
  ) -> dict[str, Any]:
308
352
  """Add a comment via ``Post.AddPostComment``.
309
353
 
310
354
  Uses ``postID`` / ``replyID`` (capital ID) to match the documented
311
- spelling in ``src/api/post.js``.
355
+ spelling in ``src/api/post.js``. ``attachments`` go in the same JSON
356
+ string form as on a post (MDPublic src/pages/feed/components/post/
357
+ comment/postCommentInput.jsx:181-192; pd-openweb identical).
312
358
  """
313
359
  data: dict[str, Any] = {"postID": post_id, "message": message}
314
360
  if reply_id:
315
361
  data["replyID"] = reply_id
316
362
  if reply_account_id:
317
363
  data["replyAccountId"] = reply_account_id
364
+ if attachments:
365
+ data.update(_attachment_fields(attachments))
318
366
  return _require_post_success(
319
367
  session.api_call("Post", "AddPostComment", data), action="comment")
320
368