hap-cli 0.8.24__tar.gz → 0.8.26__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.
- {hap_cli-0.8.24 → hap_cli-0.8.26}/PKG-INFO +3 -3
- {hap_cli-0.8.24/hap_cli → hap_cli-0.8.26}/README.md +2 -2
- {hap_cli-0.8.24 → hap_cli-0.8.26/hap_cli}/README.md +2 -2
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/README_CN.md +2 -1
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/__init__.py +1 -1
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/chart_cmd.py +5 -2
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/chat_cmd.py +58 -10
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/config_cmd.py +93 -16
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/instance_cmd.py +15 -4
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/record_cmd.py +14 -2
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/chart.py +30 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/chat.py +73 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/instance.py +147 -13
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/record.py +7 -0
- hap_cli-0.8.26/hap_cli/guide/en/chart.md +150 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/guide/index.json +8 -0
- hap_cli-0.8.26/hap_cli/guide/zh-Hans/chart.md +133 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/hap_cli.py +4 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/i18n.py +24 -7
- hap_cli-0.8.26/hap_cli/locale/messages.json +4821 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_chart.py +33 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_chat_attachment_send.py +137 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_core.py +197 -1
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_i18n.py +115 -16
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_integration_approval_actions.py +34 -10
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_org_approval_v3_semantic_cli.py +6 -1
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli.egg-info/PKG-INFO +3 -3
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli.egg-info/SOURCES.txt +2 -0
- hap_cli-0.8.24/hap_cli/locale/messages.json +0 -3271
- {hap_cli-0.8.24 → hap_cli-0.8.26}/MANIFEST.in +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/app_live_tests/__init__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/app_live_tests/__main__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/app_live_tests/config.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/app_live_tests/harness.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/app_live_tests/smoke.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/app_live_tests/state.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/__main__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/__init__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/app_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/app_creator_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/app_editor_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/attachment_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/auth_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/calendar_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/chatbot_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/contact_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/department_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/group_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/guide_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/icon_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/node_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/optionset_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/page_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/post_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/region_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/role_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/update_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/upload_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/v3_registry.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/workflow_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/commands/worksheet_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/context.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/__init__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/action_spec_adapter.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/__init__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/_hapmeta/__init__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/_hapmeta/worksheet_templates.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/charts.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/cleanup.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/compiler.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/config.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/design/design.schema.json +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/errors.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/examples/minimal.design.json +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/executor.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/fields.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/hap.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/merge.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/recording/__init__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/recording/console.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/recording/jsonl.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/recording/mirror.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/recording/report.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/schema.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/seed/INSTRUCTIONS.md +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/seed/__init__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/seed/cli.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/seed/executor.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/seed/resources/attachments.json +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/seed/resources/sample.docx +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/seed/resources/sample.pdf +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/seed/resources/sample_images.json +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/seed/template.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/selftest.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/smoke.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/steps.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/store.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/validate.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/app_creator/workflow_dsl.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/attachment.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/auth.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/calendar_mod.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/chatbot.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/cli_access.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/contact.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/control_type_codes.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/department.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/editor/__init__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/editor/_hapmeta/__init__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/editor/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/editor/apply.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/editor/componentlower.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/editor/editspec/component.schema.json +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/editor/editspec/custom-action.schema.json +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/editor/editspec/envelope.schema.json +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/editor/editspec/field.schema.json +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/editor/editspec.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/editor/errors.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/editor/fieldlower.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/editor/jsonschema_mini.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/editor/models.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/editor/ops.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/editor/planner.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/editor/reader.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/field_normalizer.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/field_spec_adapter.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/filter_translator.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/flow_node.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/global_meta.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/group.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/guide.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/icon_index.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/logger.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/optionset.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/page.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/post.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/response_crypto.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/role.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/role_perm_builder.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/session.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/token_crypto.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/update.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/upload.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/v3/__init__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/v3/dispatcher.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/v3/render.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/v3/schema.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/view_spec_adapter.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/workflow.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/workflow_node_dsl.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/worksheet.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/core/worksheet_templates.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/guide/en/messages.md +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/guide/en/overview.md +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/guide/en/record.md +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/guide/en/setup.md +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/guide/en/skills.md +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/guide/zh-Hans/messages.md +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/guide/zh-Hans/overview.md +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/guide/zh-Hans/record.md +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/guide/zh-Hans/setup.md +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/guide/zh-Hans/skills.md +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/locale/__init__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/locale/messages.schema.json +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/__init__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/conftest.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_app_creator.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_app_editor.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_app_export_usage.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_attachment_share.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_auth_prerelease.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_bug_036430.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_bug_036750.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_cli_access.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_config_cmd.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_content_language.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_control_lookup_guard.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_destructive_confirm_cli.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_full_e2e.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_global_meta.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_guide.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_instance_history_cli.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_integration.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_integration_approval.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_integration_calendar.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_integration_destructive.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_integration_misc.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_integration_post.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_integration_social.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_integration_v3.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_integration_workflow.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_integration_worksheet_extra.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_member_relation_array_wrap.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_multi_profile.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_no_workflow_unsupported.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_org_id_cli.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_org_id_docs.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_parameter_conventions.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_parameter_mapping_registry.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_record_batch_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_record_field_alias.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_record_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_record_write_fixes.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_select_add_option.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_select_rejects_relation_value.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_semantic_types_registry.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_update.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_update_mode.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_upload_host_resolution.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_v3_api_schema_loader.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_v3_dispatcher.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_v3_registry_coverage.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_v3_session.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_v3_yaml_translation.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_workflow_envelope_errors.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_workflow_list_cli.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_workflow_read_write_keys.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_workflow_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_worksheet_create_section.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_worksheet_crud_cli.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/tests/test_worksheet_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/utils/__init__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/utils/formatting.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/utils/options.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli/utils/parameter_mapping.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli.egg-info/dependency_links.txt +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli.egg-info/entry_points.txt +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli.egg-info/requires.txt +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/hap_cli.egg-info/top_level.txt +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/__init__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/__main__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/_wftest.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/charts.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/cleanup.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/compiler.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/config.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/errors.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/executor.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/fields.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/hap.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/recording/__init__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/recording/console.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/recording/jsonl.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/recording/mirror.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/recording/report.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/schema.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/seed/__init__.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/seed/cli.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/seed/executor.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/seed/template.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/selftest.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/smoke.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/step.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/steps.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/store.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/live_tests/workflow_dsl.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/setup.cfg +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/setup.py +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/INDEX.json +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/add_member_to_role.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/batch_delete_records.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/create_optionset.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/create_role.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/delete_optionset.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/delete_record.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/delete_role.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/delete_worksheet.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/get_app_info.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/get_app_knowledge_list.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/get_app_worksheets_list.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/get_optionset_list.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/get_record_details.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/get_record_discussions.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/get_record_list.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/get_record_logs.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/get_record_pivot_data.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/get_record_relations.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/get_record_share_link.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/get_regions.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/get_role_details.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/get_role_list.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/knowledge_search.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/leave_all_roles.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/remove_member_from_role.yaml +0 -0
- {hap_cli-0.8.24 → hap_cli-0.8.26}/sources/v3-api-schema/update_optionset.yaml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hap-cli
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.26
|
|
4
4
|
Summary: CLI harness for Mingdao HAP - Enterprise no-code platform
|
|
5
5
|
Author: hap-cli
|
|
6
6
|
License: Apache-2.0
|
|
@@ -273,7 +273,7 @@ discover every subcommand.
|
|
|
273
273
|
| `chat messages` | 1-on-1 / group / inbox messages |
|
|
274
274
|
| `chat files` | Files shared in a chat |
|
|
275
275
|
| `chat send-to-one` | Send a message, optionally with files (`--file`), to one or more users (1-on-1) |
|
|
276
|
-
| `chat send-to-group` | Send a
|
|
276
|
+
| `chat send-to-group` | Send a message, optionally with files, to a group chat |
|
|
277
277
|
| `chat card-detail` | Resolve embedded card references |
|
|
278
278
|
|
|
279
279
|
### group — chat group lifecycle
|
|
@@ -326,7 +326,7 @@ discover every subcommand.
|
|
|
326
326
|
|---|---|
|
|
327
327
|
| `config show` | Display the current configuration summary |
|
|
328
328
|
| `config completion [bash\|zsh\|fish] [--install]` | Enable `<Tab>` completion |
|
|
329
|
-
| `config language [LANG]` | Switch UI language (`en` / `zh-Hans
|
|
329
|
+
| `config language [LANG]` | Switch UI language (`en` / `zh-Hans`, or `auto` to follow the account language) |
|
|
330
330
|
| `config update [auto\|notify\|off]` | Self-upgrade mode; `notify` only reports, `off` never checks |
|
|
331
331
|
| `config log on / off / status` | Toggle and inspect API logging |
|
|
332
332
|
| `config log level LEVEL` | `DEBUG / INFO / WARNING / ERROR / CRITICAL` |
|
|
@@ -244,7 +244,7 @@ discover every subcommand.
|
|
|
244
244
|
| `chat messages` | 1-on-1 / group / inbox messages |
|
|
245
245
|
| `chat files` | Files shared in a chat |
|
|
246
246
|
| `chat send-to-one` | Send a message, optionally with files (`--file`), to one or more users (1-on-1) |
|
|
247
|
-
| `chat send-to-group` | Send a
|
|
247
|
+
| `chat send-to-group` | Send a message, optionally with files, to a group chat |
|
|
248
248
|
| `chat card-detail` | Resolve embedded card references |
|
|
249
249
|
|
|
250
250
|
### group — chat group lifecycle
|
|
@@ -297,7 +297,7 @@ discover every subcommand.
|
|
|
297
297
|
|---|---|
|
|
298
298
|
| `config show` | Display the current configuration summary |
|
|
299
299
|
| `config completion [bash\|zsh\|fish] [--install]` | Enable `<Tab>` completion |
|
|
300
|
-
| `config language [LANG]` | Switch UI language (`en` / `zh-Hans
|
|
300
|
+
| `config language [LANG]` | Switch UI language (`en` / `zh-Hans`, or `auto` to follow the account language) |
|
|
301
301
|
| `config update [auto\|notify\|off]` | Self-upgrade mode; `notify` only reports, `off` never checks |
|
|
302
302
|
| `config log on / off / status` | Toggle and inspect API logging |
|
|
303
303
|
| `config log level LEVEL` | `DEBUG / INFO / WARNING / ERROR / CRITICAL` |
|
|
@@ -244,7 +244,7 @@ discover every subcommand.
|
|
|
244
244
|
| `chat messages` | 1-on-1 / group / inbox messages |
|
|
245
245
|
| `chat files` | Files shared in a chat |
|
|
246
246
|
| `chat send-to-one` | Send a message, optionally with files (`--file`), to one or more users (1-on-1) |
|
|
247
|
-
| `chat send-to-group` | Send a
|
|
247
|
+
| `chat send-to-group` | Send a message, optionally with files, to a group chat |
|
|
248
248
|
| `chat card-detail` | Resolve embedded card references |
|
|
249
249
|
|
|
250
250
|
### group — chat group lifecycle
|
|
@@ -297,7 +297,7 @@ discover every subcommand.
|
|
|
297
297
|
|---|---|
|
|
298
298
|
| `config show` | Display the current configuration summary |
|
|
299
299
|
| `config completion [bash\|zsh\|fish] [--install]` | Enable `<Tab>` completion |
|
|
300
|
-
| `config language [LANG]` | Switch UI language (`en` / `zh-Hans
|
|
300
|
+
| `config language [LANG]` | Switch UI language (`en` / `zh-Hans`, or `auto` to follow the account language) |
|
|
301
301
|
| `config update [auto\|notify\|off]` | Self-upgrade mode; `notify` only reports, `off` never checks |
|
|
302
302
|
| `config log on / off / status` | Toggle and inspect API logging |
|
|
303
303
|
| `config log level LEVEL` | `DEBUG / INFO / WARNING / ERROR / CRITICAL` |
|
|
@@ -227,6 +227,7 @@ hap --json worksheet record list WORKSHEET_ID
|
|
|
227
227
|
| `chat messages` | 单聊 / 群聊 / 收件箱(系统、应用、工作流等) |
|
|
228
228
|
| `chat files` | 聊天中分享的文件 |
|
|
229
229
|
| `chat send-to-one` | 向一个或多个用户发消息(单聊),可带附件 `--file`(文件作为聊天附件送达,不是链接) |
|
|
230
|
+
| `chat send-to-group` | 向群聊发消息,可带附件 `--file`,支持 `--at` / `--at-all` 提醒 |
|
|
230
231
|
| `chat group-info` | 群组信息 |
|
|
231
232
|
| `chat card-detail` | 解析消息中嵌入的卡片引用 |
|
|
232
233
|
|
|
@@ -271,7 +272,7 @@ hap --json worksheet record list WORKSHEET_ID
|
|
|
271
272
|
|---|---|
|
|
272
273
|
| `config show` | 显示 CLI 配置摘要 |
|
|
273
274
|
| `config completion [bash\|zsh\|fish] [--install]` | 启用 `<Tab>` 补全 |
|
|
274
|
-
| `config language [LANG]` | 切换显示语言(`en` / `zh-Hans`
|
|
275
|
+
| `config language [LANG]` | 切换显示语言(`en` / `zh-Hans`;`auto` 跟随登录账号的语言) |
|
|
275
276
|
| `config update [auto\|notify\|off]` | 自动升级开关;`notify` 只提示不安装,`off` 不检查 |
|
|
276
277
|
| `config log on / off / status` | 日志开关与状态 |
|
|
277
278
|
| `config log level LEVEL` | 设置日志级别(`DEBUG/INFO/WARNING/ERROR/CRITICAL`) |
|
|
@@ -123,7 +123,8 @@ def _resolve_app_id_for_filter(session, worksheet_id: str, extra: dict) -> str:
|
|
|
123
123
|
return (data or {}).get("appId", "") if isinstance(data, dict) else ""
|
|
124
124
|
|
|
125
125
|
|
|
126
|
-
@chart.command("create"
|
|
126
|
+
@chart.command("create", help="Create a new chart on a worksheet. "
|
|
127
|
+
"Chart spec shapes are in `hap guide chart`.")
|
|
127
128
|
@click.argument("worksheet_id")
|
|
128
129
|
@click.option("--name", required=True, help="Chart display name.")
|
|
129
130
|
@click.option("--report-type", "report_type", type=int, required=True,
|
|
@@ -163,7 +164,9 @@ def chart_create(ctx, worksheet_id, name, report_type, app_type, app_id,
|
|
|
163
164
|
ctx.handle_error(e)
|
|
164
165
|
|
|
165
166
|
|
|
166
|
-
@chart.command("update"
|
|
167
|
+
@chart.command("update", help="Update an existing chart's configuration. "
|
|
168
|
+
"Read the config with `chart get`, edit it, submit "
|
|
169
|
+
"it back — see `hap guide chart`.")
|
|
167
170
|
@click.argument("report_id")
|
|
168
171
|
@click.option("--app-id", "-a", required=True, help="Worksheet ID the chart attaches to.")
|
|
169
172
|
@click.option("--name", required=True, help="Chart display name.")
|
|
@@ -320,7 +320,13 @@ def chat_send_to_one(ctx, to, message, files, dry_run):
|
|
|
320
320
|
|
|
321
321
|
@chat.command("send-to-group")
|
|
322
322
|
@click.option("--group-id", "-g", required=True, help="Target group ID")
|
|
323
|
-
@click.option("--message", "-m",
|
|
323
|
+
@click.option("--message", "-m", default="", help="Message text")
|
|
324
|
+
@click.option(
|
|
325
|
+
"--file", "-f", "files", multiple=True,
|
|
326
|
+
help="Attach a file: a local path or an http(s) address. Repeat for "
|
|
327
|
+
"several. The file arrives as an attachment members can open at "
|
|
328
|
+
"any time, not as a link that stops working.",
|
|
329
|
+
)
|
|
324
330
|
@click.option(
|
|
325
331
|
"--at", "at_account_ids", multiple=True,
|
|
326
332
|
help="Account ID to @-mention (can repeat). Sends a separate "
|
|
@@ -331,19 +337,61 @@ def chat_send_to_one(ctx, to, message, files, dry_run):
|
|
|
331
337
|
"--at-all", is_flag=True, default=False,
|
|
332
338
|
help="@-mention everyone in the group.",
|
|
333
339
|
)
|
|
340
|
+
@click.option(
|
|
341
|
+
"--dry-run", is_flag=True, default=False,
|
|
342
|
+
help="Show what would be sent, without uploading or sending anything.",
|
|
343
|
+
)
|
|
334
344
|
@pass_context
|
|
335
|
-
def chat_send_to_group(ctx, group_id, message, at_account_ids, at_all):
|
|
336
|
-
"""Send a
|
|
345
|
+
def chat_send_to_group(ctx, group_id, message, files, at_account_ids, at_all, dry_run):
|
|
346
|
+
"""Send a message, optionally with files, to a group chat.
|
|
347
|
+
|
|
348
|
+
\b
|
|
349
|
+
hap chat send-to-group -g <groupId> -m "spec attached" -f ./spec.pdf
|
|
350
|
+
|
|
351
|
+
Text and each file arrive as separate messages, in that order. An
|
|
352
|
+
@-mention applies to the text line, so it needs --message.
|
|
353
|
+
"""
|
|
354
|
+
if not message and not files:
|
|
355
|
+
ctx.handle_error(click.UsageError(
|
|
356
|
+
"Provide --message, --file, or both."
|
|
357
|
+
))
|
|
358
|
+
return
|
|
359
|
+
sources = upload_mod.source_descriptors(list(files))
|
|
360
|
+
at_ids = list(at_account_ids) if at_account_ids else None
|
|
361
|
+
if dry_run:
|
|
362
|
+
ctx.output(
|
|
363
|
+
{"group_id": group_id, "message": message, "files": list(files),
|
|
364
|
+
"at": at_ids or [], "at_all": at_all, "sent": False},
|
|
365
|
+
lambda d: click.echo(
|
|
366
|
+
"Dry run — nothing sent."
|
|
367
|
+
+ f"\n Group: {group_id}"
|
|
368
|
+
+ (f"\n Message: {message}" if message else "")
|
|
369
|
+
+ "".join(f"\n File: {f}" for f in files)
|
|
370
|
+
+ (f"\n @: {', '.join(at_ids)}" if at_ids else "")
|
|
371
|
+
+ ("\n @: everyone" if at_all else "")
|
|
372
|
+
),
|
|
373
|
+
)
|
|
374
|
+
return
|
|
337
375
|
try:
|
|
338
376
|
session = ctx.get_session()
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
377
|
+
if not sources:
|
|
378
|
+
data = chat_mod.send_group_message(
|
|
379
|
+
session, group_id, message,
|
|
380
|
+
at_account_ids=at_ids, at_all=at_all,
|
|
381
|
+
)
|
|
382
|
+
ctx.output(data, lambda d: click.echo("Message sent."))
|
|
383
|
+
return
|
|
384
|
+
descriptors = chat_mod.upload_chat_files(session, sources)
|
|
385
|
+
acks = chat_mod.send_group_files(
|
|
386
|
+
session, group_id, descriptors, message,
|
|
387
|
+
at_account_ids=at_ids, at_all=at_all,
|
|
388
|
+
)
|
|
389
|
+
ctx.output(
|
|
390
|
+
{"sent": len(acks), "files": len(descriptors), "acks": acks},
|
|
391
|
+
lambda d: click.echo(
|
|
392
|
+
f"Sent {len(descriptors)} file(s) to the group."
|
|
393
|
+
),
|
|
345
394
|
)
|
|
346
|
-
ctx.output(data, lambda d: click.echo("Message sent."))
|
|
347
395
|
except Exception as e:
|
|
348
396
|
ctx.handle_error(e)
|
|
349
397
|
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import logging
|
|
5
6
|
import os
|
|
6
7
|
import re
|
|
7
8
|
import time
|
|
8
9
|
from pathlib import Path
|
|
9
10
|
|
|
10
11
|
import click
|
|
12
|
+
from typing import Optional
|
|
11
13
|
|
|
12
14
|
from hap_cli.context import pass_context
|
|
13
15
|
from hap_cli.core.logger import (
|
|
@@ -20,6 +22,8 @@ from hap_cli.core.logger import (
|
|
|
20
22
|
)
|
|
21
23
|
from hap_cli.i18n import t
|
|
22
24
|
|
|
25
|
+
logger = logging.getLogger("hap_cli.config")
|
|
26
|
+
|
|
23
27
|
|
|
24
28
|
# ── Shell completion helpers (moved from hap_cli.hap_cli) ────────────────
|
|
25
29
|
|
|
@@ -252,46 +256,119 @@ def config_update(ctx, mode):
|
|
|
252
256
|
# ── `hap config language` ─────────────────────────────────────────────────
|
|
253
257
|
|
|
254
258
|
|
|
259
|
+
# Languages a user can pin here. The catalog and the resolution logic
|
|
260
|
+
# (HAP_LANG, config.json, login auto-detect) still understand every code in
|
|
261
|
+
# ``i18n.LANG_OPTIONS`` — zh-Hant / ja keep working and keep falling back
|
|
262
|
+
# to English where untranslated — they are only hidden from this picker.
|
|
263
|
+
_SELECTABLE_LANGS = ("en", "zh-Hans")
|
|
264
|
+
# Picker entry 0 / argument value "auto": drop the manual pin and follow
|
|
265
|
+
# the language of the HAP account (re-read now, and again at every login).
|
|
266
|
+
_AUTO = "auto"
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def _detect_account_language(ctx) -> Optional[str]:
|
|
270
|
+
"""Read the HAP account language of the active profile, or ``None``.
|
|
271
|
+
|
|
272
|
+
Uses the same lookup as ``hap auth whoami`` (``Global/GetGlobalMeta`` →
|
|
273
|
+
``Account.lang``). Any failure — not logged in, expired token, network —
|
|
274
|
+
yields ``None`` so the caller can still switch to auto mode and let the
|
|
275
|
+
next login fill the language in.
|
|
276
|
+
"""
|
|
277
|
+
from hap_cli.core import auth as auth_mod
|
|
278
|
+
from hap_cli.core.session import (
|
|
279
|
+
_normalize_login_url, load_profile, resolve_profile_name,
|
|
280
|
+
)
|
|
281
|
+
from hap_cli.i18n import lang_from_hap_account
|
|
282
|
+
|
|
283
|
+
try:
|
|
284
|
+
session = ctx.get_session(require_auth=False)
|
|
285
|
+
if not session.auth_token:
|
|
286
|
+
return None
|
|
287
|
+
prof = load_profile(resolve_profile_name(ctx.profile))
|
|
288
|
+
login_url = _normalize_login_url(
|
|
289
|
+
prof.get("login_url") or prof.get("server_url", "")
|
|
290
|
+
) or "https://www.mingdao.com"
|
|
291
|
+
info = auth_mod.get_user_info(login_url, session.auth_token)
|
|
292
|
+
return lang_from_hap_account(str(info.get("lang") or ""))
|
|
293
|
+
except Exception as exc: # noqa: BLE001 — auto mode must not fail on lookup
|
|
294
|
+
logger.warning("Could not read the account language: %s", exc)
|
|
295
|
+
return None
|
|
296
|
+
|
|
297
|
+
|
|
255
298
|
@config.command("language")
|
|
256
299
|
@click.argument(
|
|
257
300
|
"lang",
|
|
258
301
|
required=False,
|
|
259
|
-
type=click.Choice([
|
|
302
|
+
type=click.Choice([_AUTO, *_SELECTABLE_LANGS]),
|
|
260
303
|
)
|
|
261
304
|
@pass_context
|
|
262
305
|
def config_language(ctx, lang):
|
|
263
306
|
"""Switch the CLI display language.
|
|
264
307
|
|
|
265
|
-
Without an argument, shows an interactive picker. Pass
|
|
266
|
-
``
|
|
308
|
+
Without an argument, shows an interactive picker. Pass ``en`` or
|
|
309
|
+
``zh-Hans`` to pin a language, or ``auto`` (``0`` in the picker) to
|
|
310
|
+
follow the language of the HAP account you log in with.
|
|
267
311
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
312
|
+
A pinned language is saved as a manual preference — subsequent
|
|
313
|
+
``hap auth login`` calls won't overwrite it. ``auto`` removes the pin
|
|
314
|
+
and re-reads the language from your current account right away.
|
|
271
315
|
"""
|
|
272
316
|
from hap_cli.core.session import load_config, save_config
|
|
273
|
-
from hap_cli.i18n import
|
|
317
|
+
from hap_cli.i18n import DEFAULT_LANGUAGE, LANG_LABELS, reset_language_cache
|
|
274
318
|
|
|
275
319
|
if lang is None:
|
|
276
320
|
cfg = load_config() or {}
|
|
277
|
-
current = cfg.get("language") or
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
321
|
+
current = cfg.get("language") or DEFAULT_LANGUAGE
|
|
322
|
+
is_auto = cfg.get("language_source") != "manual"
|
|
323
|
+
click.echo("Choose a language / 选择语言:")
|
|
324
|
+
mark = " (current)" if is_auto else ""
|
|
325
|
+
click.echo(f" 0. Auto — follow your HAP account language [auto]{mark}")
|
|
326
|
+
for i, code in enumerate(_SELECTABLE_LANGS, start=1):
|
|
327
|
+
mark = " (current)" if (not is_auto and code == current) else ""
|
|
281
328
|
click.echo(f" {i}. {LANG_LABELS[code]} [{code}]{mark}")
|
|
329
|
+
if is_auto or current not in _SELECTABLE_LANGS:
|
|
330
|
+
default_index = 0
|
|
331
|
+
else:
|
|
332
|
+
default_index = _SELECTABLE_LANGS.index(current) + 1
|
|
282
333
|
choice = click.prompt(
|
|
283
|
-
"Enter
|
|
284
|
-
type=click.IntRange(
|
|
285
|
-
default=
|
|
334
|
+
f"Enter 0-{len(_SELECTABLE_LANGS)}",
|
|
335
|
+
type=click.IntRange(0, len(_SELECTABLE_LANGS)),
|
|
336
|
+
default=default_index,
|
|
286
337
|
)
|
|
287
|
-
lang =
|
|
338
|
+
lang = _AUTO if choice == 0 else _SELECTABLE_LANGS[choice - 1]
|
|
339
|
+
|
|
340
|
+
if lang == _AUTO:
|
|
341
|
+
detected = _detect_account_language(ctx)
|
|
342
|
+
save_config({
|
|
343
|
+
"language": detected or DEFAULT_LANGUAGE,
|
|
344
|
+
"language_source": "auto",
|
|
345
|
+
})
|
|
346
|
+
reset_language_cache()
|
|
347
|
+
if ctx.json_mode:
|
|
348
|
+
from hap_cli.utils.formatting import output_json
|
|
349
|
+
output_json({
|
|
350
|
+
"status": "ok", "mode": "auto",
|
|
351
|
+
"language": detected or DEFAULT_LANGUAGE,
|
|
352
|
+
"detected": bool(detected),
|
|
353
|
+
})
|
|
354
|
+
elif detected:
|
|
355
|
+
click.echo(
|
|
356
|
+
"Language set to: Auto — following your HAP account language "
|
|
357
|
+
f"({LANG_LABELS[detected]} [{detected}])"
|
|
358
|
+
)
|
|
359
|
+
else:
|
|
360
|
+
click.echo(
|
|
361
|
+
"Language set to: Auto — it will follow your HAP account "
|
|
362
|
+
"language after the next login."
|
|
363
|
+
)
|
|
364
|
+
return
|
|
288
365
|
|
|
289
366
|
save_config({"language": lang, "language_source": "manual"})
|
|
290
367
|
reset_language_cache()
|
|
291
368
|
label = LANG_LABELS[lang]
|
|
292
369
|
if ctx.json_mode:
|
|
293
370
|
from hap_cli.utils.formatting import output_json
|
|
294
|
-
output_json({"status": "ok", "language": lang, "label": label})
|
|
371
|
+
output_json({"status": "ok", "mode": "manual", "language": lang, "label": label})
|
|
295
372
|
else:
|
|
296
373
|
click.echo(f"Language set to: {label} [{lang}]")
|
|
297
374
|
|
|
@@ -182,11 +182,17 @@ def instance_submit(ctx, instance_id, work_id, opinion):
|
|
|
182
182
|
|
|
183
183
|
@instance.command("revoke")
|
|
184
184
|
@click.argument("instance_id")
|
|
185
|
-
@click.option("--work-id", "-w", default="",
|
|
185
|
+
@click.option("--work-id", "-w", default="",
|
|
186
|
+
help="Work item ID of the initiating step. Looked up from the "
|
|
187
|
+
"flow automatically when omitted.")
|
|
186
188
|
@click.option("--opinion", "-o", default="", help="Revocation reason")
|
|
187
189
|
@pass_context
|
|
188
190
|
def instance_revoke(ctx, instance_id, work_id, opinion):
|
|
189
|
-
"""Revoke/withdraw a submitted instance.
|
|
191
|
+
"""Revoke/withdraw a submitted instance.
|
|
192
|
+
|
|
193
|
+
Only the initiator can withdraw a flow, and only while it is still
|
|
194
|
+
running.
|
|
195
|
+
"""
|
|
190
196
|
try:
|
|
191
197
|
session = ctx.get_session()
|
|
192
198
|
data = inst_mod.revoke(session, instance_id, work_id, opinion)
|
|
@@ -240,13 +246,18 @@ def instance_retry(ctx, instance_id):
|
|
|
240
246
|
|
|
241
247
|
@instance.command("restart")
|
|
242
248
|
@click.argument("instance_id")
|
|
243
|
-
@click.option("--work-id", "-w", default="",
|
|
249
|
+
@click.option("--work-id", "-w", default="",
|
|
250
|
+
help="Work item ID of the pending initiating step created by "
|
|
251
|
+
"the revoke. Looked up from the flow automatically when "
|
|
252
|
+
"omitted.")
|
|
244
253
|
@pass_context
|
|
245
254
|
def instance_restart(ctx, instance_id, work_id):
|
|
246
255
|
"""Re-initiate a flow the initiator has revoked.
|
|
247
256
|
|
|
248
257
|
Use this after the initiator revoked (withdrew) a still-running flow to
|
|
249
|
-
start it again. It
|
|
258
|
+
start it again. It requires the approval flow to allow re-initiating
|
|
259
|
+
after a revoke; the initiator then gets a new fill task to submit. It
|
|
260
|
+
does not apply to flows that already finished.
|
|
250
261
|
"""
|
|
251
262
|
try:
|
|
252
263
|
session = ctx.get_session()
|
|
@@ -374,16 +374,28 @@ def record_discussions(ctx, worksheet_id, row_id, page_size, page):
|
|
|
374
374
|
@click.option("--app-id", default="", help="Application ID (auto-detected from the worksheet if omitted)")
|
|
375
375
|
@click.option("--view-id", default="", help="View ID the discussion originates from")
|
|
376
376
|
@click.option("--reply-id", default="", help="ID of the discussion being replied to")
|
|
377
|
+
@click.option("--file", "-f", "files", multiple=True,
|
|
378
|
+
help="Attach a file to the comment (repeatable). Accepts a local "
|
|
379
|
+
"path or an http(s) URL.")
|
|
377
380
|
@pass_context
|
|
378
|
-
def record_add_discussion(ctx, worksheet_id, row_id, message, app_id, view_id, reply_id):
|
|
381
|
+
def record_add_discussion(ctx, worksheet_id, row_id, message, app_id, view_id, reply_id, files):
|
|
379
382
|
"""Add a discussion/comment to a record."""
|
|
380
383
|
try:
|
|
381
384
|
session = ctx.get_session()
|
|
385
|
+
attachments = None
|
|
386
|
+
if files:
|
|
387
|
+
from hap_cli.core import upload as up_mod
|
|
388
|
+
descriptors = up_mod.source_descriptors(list(files))
|
|
389
|
+
attachments = up_mod.upload_files(
|
|
390
|
+
session, descriptors,
|
|
391
|
+
worksheet_id=worksheet_id, app_id=app_id,
|
|
392
|
+
)
|
|
382
393
|
data = rec_mod.add_discussion(
|
|
383
394
|
session, worksheet_id, row_id, message,
|
|
384
395
|
app_id=app_id, view_id=view_id, reply_id=reply_id,
|
|
396
|
+
attachments=attachments,
|
|
385
397
|
)
|
|
386
|
-
ctx.output(data, lambda d: click.echo(
|
|
398
|
+
ctx.output(data, lambda d: click.echo("Discussion added."))
|
|
387
399
|
except Exception as e:
|
|
388
400
|
ctx.handle_error(e)
|
|
389
401
|
|
|
@@ -44,6 +44,30 @@ from hap_cli.core.session import Session
|
|
|
44
44
|
|
|
45
45
|
logger = logging.getLogger("hap_cli.chart")
|
|
46
46
|
|
|
47
|
+
# A chart that is saved without a ``filter`` block saves successfully but
|
|
48
|
+
# never renders: the statistics backend cannot scope the query and
|
|
49
|
+
# ``report/getData`` answers status -1/0, which the UI paints as
|
|
50
|
+
# "无法形成图表 / 构成要素不存在或已删除". The chart looks fine in the editor
|
|
51
|
+
# (which supplies its own default scope) and only breaks after save — the
|
|
52
|
+
# single most common way a hand-written ``chart create`` spec silently
|
|
53
|
+
# produces a blank chart. The frontend's ``getNewReport`` always injects a
|
|
54
|
+
# default time filter for a new worksheet chart; we mirror that here, but
|
|
55
|
+
# default to ``rangeType: 0`` (全部时间 / all-time) instead of the UI's
|
|
56
|
+
# "last 365 days" so the chart is never blank merely because the default
|
|
57
|
+
# window excluded older data. Callers that supply their own ``filter``
|
|
58
|
+
# (any non-empty dict) keep it untouched.
|
|
59
|
+
_DEFAULT_CHART_FILTER: dict[str, Any] = {
|
|
60
|
+
"filterRangeId": "ctime",
|
|
61
|
+
"filterRangeName": "创建时间",
|
|
62
|
+
"rangeType": 0,
|
|
63
|
+
"rangeValue": None,
|
|
64
|
+
"today": False,
|
|
65
|
+
"dynamicFilter": {
|
|
66
|
+
"startType": 1, "startCount": 1, "startUnit": 1,
|
|
67
|
+
"endType": 1, "endCount": 1, "endUnit": 1,
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
|
|
47
71
|
|
|
48
72
|
def list_charts(
|
|
49
73
|
session: Session,
|
|
@@ -218,6 +242,12 @@ def save_chart(
|
|
|
218
242
|
split_control_id = body["split"].get("controlId")
|
|
219
243
|
if split_control_id:
|
|
220
244
|
body["splitId"] = split_control_id
|
|
245
|
+
# A chart with no filter block saves but never renders (blank after
|
|
246
|
+
# save — see _DEFAULT_CHART_FILTER). Inject an all-time default when the
|
|
247
|
+
# caller omitted it; a caller-supplied filter (any non-empty value) is
|
|
248
|
+
# left untouched so an explicit scope always wins.
|
|
249
|
+
if not body.get("filter"):
|
|
250
|
+
body["filter"] = dict(_DEFAULT_CHART_FILTER)
|
|
221
251
|
# Resolve the chart's filter block before sending saveReportConfig.
|
|
222
252
|
if isinstance(body.get("filter"), dict):
|
|
223
253
|
body["filter"] = _ensure_filter_id(
|
|
@@ -438,6 +438,79 @@ def send_group_message(
|
|
|
438
438
|
return ack_data
|
|
439
439
|
|
|
440
440
|
|
|
441
|
+
def send_group_files(
|
|
442
|
+
session: Session,
|
|
443
|
+
group_id: str,
|
|
444
|
+
descriptors: list[dict[str, Any]],
|
|
445
|
+
message: str = "",
|
|
446
|
+
at_account_ids: Optional[list[str]] = None,
|
|
447
|
+
at_all: bool = False,
|
|
448
|
+
) -> list[Any]:
|
|
449
|
+
"""Send already-uploaded files (and an optional line of text) to a group.
|
|
450
|
+
|
|
451
|
+
Group file messages ride the same socket.io event as group text —
|
|
452
|
+
``'send group message'`` (``src/pages/chat/utils/socket.js``
|
|
453
|
+
``Message.send`` GROUP branch) — with the same per-message shape the
|
|
454
|
+
1-on-1 path uses (SendToolbar ``FileUploaded`` → ``onSendFileMsg({file,
|
|
455
|
+
type}, msg)`` → ``ChatPanelSession.sendMessage``), the only difference
|
|
456
|
+
being ``togroup`` instead of ``touser`` (ChatPanelSession/index.js:355).
|
|
457
|
+
Order mirrors the chat panel: the typed text first, then one message
|
|
458
|
+
per file, all over one connection.
|
|
459
|
+
|
|
460
|
+
An @-mention (``at_account_ids`` / ``at_all``) only makes sense on the
|
|
461
|
+
text line, so the ``'group shake'`` follow-up carries the text
|
|
462
|
+
message's ack id and is skipped when there is no text — same
|
|
463
|
+
best-effort contract as :func:`send_group_message`.
|
|
464
|
+
|
|
465
|
+
Returns the acks in send order (unwrapped from the ``(err, data)``
|
|
466
|
+
tuple python-socketio surfaces). Emitting is strict — a failure to
|
|
467
|
+
deliver raises rather than reporting a phantom success.
|
|
468
|
+
"""
|
|
469
|
+
import uuid
|
|
470
|
+
|
|
471
|
+
if not group_id:
|
|
472
|
+
raise ValueError("group_id is required")
|
|
473
|
+
if not descriptors and not message:
|
|
474
|
+
raise ValueError("nothing to send: provide files, a message, or both")
|
|
475
|
+
|
|
476
|
+
emits: list[tuple[str, dict[str, Any]]] = []
|
|
477
|
+
if message:
|
|
478
|
+
emits.append(("send group message", {
|
|
479
|
+
"type": MSGTYPE_TEXT,
|
|
480
|
+
"msg": message,
|
|
481
|
+
"togroup": group_id,
|
|
482
|
+
"waitingid": str(uuid.uuid4()),
|
|
483
|
+
}))
|
|
484
|
+
for descriptor in descriptors:
|
|
485
|
+
msg_type, file_obj = _chat_file_message(descriptor)
|
|
486
|
+
emits.append(("send group message", {
|
|
487
|
+
"type": msg_type,
|
|
488
|
+
"msg": _chat_file_label(msg_type, file_obj["name"]),
|
|
489
|
+
"file": file_obj,
|
|
490
|
+
"togroup": group_id,
|
|
491
|
+
"waitingid": str(uuid.uuid4()),
|
|
492
|
+
}))
|
|
493
|
+
raw_acks = _socket_emit_batch(session, emits, strict=True)
|
|
494
|
+
acks = [
|
|
495
|
+
ack[1] if isinstance(ack, tuple) and len(ack) >= 2 else ack
|
|
496
|
+
for ack in raw_acks
|
|
497
|
+
]
|
|
498
|
+
|
|
499
|
+
to_user: Any = None
|
|
500
|
+
if at_all:
|
|
501
|
+
to_user = "all"
|
|
502
|
+
elif at_account_ids:
|
|
503
|
+
to_user = list(at_account_ids)
|
|
504
|
+
if to_user and message:
|
|
505
|
+
text_ack = acks[0]
|
|
506
|
+
message_id = text_ack.get("id") if isinstance(text_ack, dict) else None
|
|
507
|
+
shake_payload: dict[str, Any] = {"gid": group_id, "toUser": to_user}
|
|
508
|
+
if message_id:
|
|
509
|
+
shake_payload["messageId"] = message_id
|
|
510
|
+
_socket_emit(session, "group shake", shake_payload, strict=False)
|
|
511
|
+
return acks
|
|
512
|
+
|
|
513
|
+
|
|
441
514
|
def get_group_info(
|
|
442
515
|
session: Session,
|
|
443
516
|
group_id: str,
|