hap-cli 0.8.20__tar.gz → 0.8.22__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.20 → hap_cli-0.8.22}/PKG-INFO +13 -4
- {hap_cli-0.8.20/hap_cli → hap_cli-0.8.22}/README.md +12 -3
- {hap_cli-0.8.20 → hap_cli-0.8.22/hap_cli}/README.md +12 -3
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/README_CN.md +12 -3
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/__init__.py +1 -1
- hap_cli-0.8.22/hap_cli/commands/attachment_cmd.py +44 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/chat_cmd.py +51 -5
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/config_cmd.py +44 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/upload_cmd.py +13 -7
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/action_spec_adapter.py +9 -3
- hap_cli-0.8.22/hap_cli/core/attachment.py +107 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/chat.py +208 -15
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/flow_node.py +41 -18
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/record.py +31 -2
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/session.py +9 -1
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/update.py +39 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/upload.py +98 -20
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/worksheet.py +38 -3
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/hap_cli.py +2 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/i18n.py +64 -0
- hap_cli-0.8.22/hap_cli/tests/test_attachment_share.py +148 -0
- hap_cli-0.8.22/hap_cli/tests/test_chat_attachment_send.py +358 -0
- hap_cli-0.8.22/hap_cli/tests/test_content_language.py +120 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_core.py +22 -6
- hap_cli-0.8.22/hap_cli/tests/test_no_workflow_unsupported.py +92 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_record_batch_v3_semantic_cli.py +20 -10
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_record_v3_semantic_cli.py +3 -1
- hap_cli-0.8.22/hap_cli/tests/test_update_mode.py +90 -0
- hap_cli-0.8.22/hap_cli/tests/test_upload_host_resolution.py +93 -0
- hap_cli-0.8.22/hap_cli/tests/test_workflow_read_write_keys.py +71 -0
- hap_cli-0.8.22/hap_cli/tests/test_worksheet_create_section.py +91 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_worksheet_v3_semantic_cli.py +4 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli.egg-info/PKG-INFO +13 -4
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli.egg-info/SOURCES.txt +10 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/MANIFEST.in +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/app_live_tests/__init__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/app_live_tests/__main__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/app_live_tests/config.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/app_live_tests/harness.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/app_live_tests/smoke.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/app_live_tests/state.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/__main__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/__init__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/app_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/app_creator_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/app_editor_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/auth_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/calendar_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/chart_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/chatbot_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/contact_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/department_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/group_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/icon_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/instance_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/node_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/optionset_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/page_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/post_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/record_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/region_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/role_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/update_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/v3_registry.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/workflow_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/commands/worksheet_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/context.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/__init__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/__init__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/_hapmeta/__init__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/_hapmeta/worksheet_templates.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/charts.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/cleanup.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/compiler.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/config.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/design/design.schema.json +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/errors.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/examples/minimal.design.json +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/executor.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/fields.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/hap.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/merge.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/recording/__init__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/recording/console.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/recording/jsonl.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/recording/mirror.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/recording/report.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/schema.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/seed/INSTRUCTIONS.md +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/seed/__init__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/seed/cli.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/seed/executor.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/seed/resources/attachments.json +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/seed/resources/sample.docx +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/seed/resources/sample.pdf +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/seed/resources/sample_images.json +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/seed/template.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/selftest.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/smoke.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/steps.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/store.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/validate.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/app_creator/workflow_dsl.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/auth.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/calendar_mod.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/chart.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/chatbot.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/cli_access.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/contact.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/control_type_codes.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/department.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/editor/__init__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/editor/_hapmeta/__init__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/editor/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/editor/apply.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/editor/componentlower.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/editor/editspec.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/editor/errors.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/editor/fieldlower.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/editor/jsonschema_mini.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/editor/models.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/editor/ops.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/editor/planner.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/editor/reader.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/field_normalizer.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/field_spec_adapter.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/filter_translator.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/global_meta.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/group.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/icon_index.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/instance.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/logger.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/optionset.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/page.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/post.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/response_crypto.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/role.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/role_perm_builder.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/token_crypto.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/v3/__init__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/v3/dispatcher.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/v3/render.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/v3/schema.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/view_spec_adapter.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/workflow.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/workflow_node_dsl.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/core/worksheet_templates.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/locale/__init__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/locale/messages.json +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/locale/messages.schema.json +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/__init__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/conftest.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_app_creator.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_app_editor.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_app_export_usage.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_auth_prerelease.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_bug_036430.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_bug_036750.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_chart.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_cli_access.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_config_cmd.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_control_lookup_guard.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_destructive_confirm_cli.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_full_e2e.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_global_meta.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_i18n.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_instance_history_cli.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_integration.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_integration_approval.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_integration_approval_actions.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_integration_calendar.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_integration_destructive.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_integration_misc.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_integration_post.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_integration_social.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_integration_v3.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_integration_workflow.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_integration_worksheet_extra.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_member_relation_array_wrap.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_multi_profile.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_org_approval_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_org_id_cli.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_org_id_docs.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_parameter_conventions.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_parameter_mapping_registry.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_record_field_alias.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_select_rejects_relation_value.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_semantic_types_registry.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_update.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_v3_api_schema_loader.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_v3_dispatcher.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_v3_registry_coverage.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_v3_session.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_v3_yaml_translation.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_workflow_envelope_errors.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_workflow_list_cli.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_workflow_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/tests/test_worksheet_crud_cli.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/utils/__init__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/utils/formatting.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/utils/options.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli/utils/parameter_mapping.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli.egg-info/dependency_links.txt +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli.egg-info/entry_points.txt +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli.egg-info/requires.txt +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/hap_cli.egg-info/top_level.txt +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/__init__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/__main__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/_wftest.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/charts.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/cleanup.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/compiler.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/config.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/errors.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/executor.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/fields.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/hap.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/recording/__init__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/recording/console.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/recording/jsonl.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/recording/mirror.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/recording/report.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/schema.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/seed/__init__.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/seed/cli.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/seed/executor.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/seed/template.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/selftest.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/smoke.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/step.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/steps.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/store.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/live_tests/workflow_dsl.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/setup.cfg +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/setup.py +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/skills/cli/hap-cli-app-editor/scripts/editspec/component.schema.json +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/skills/cli/hap-cli-app-editor/scripts/editspec/custom-action.schema.json +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/skills/cli/hap-cli-app-editor/scripts/editspec/envelope.schema.json +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/skills/cli/hap-cli-app-editor/scripts/editspec/field.schema.json +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/INDEX.json +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/add_member_to_role.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/batch_delete_records.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/create_optionset.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/create_role.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/delete_optionset.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/delete_record.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/delete_role.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/delete_worksheet.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/get_app_info.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/get_app_knowledge_list.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/get_app_worksheets_list.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/get_optionset_list.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/get_record_details.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/get_record_discussions.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/get_record_list.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/get_record_logs.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/get_record_pivot_data.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/get_record_relations.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/get_record_share_link.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/get_regions.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/get_role_details.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/get_role_list.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/knowledge_search.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/leave_all_roles.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/sources/v3-api-schema/remove_member_from_role.yaml +0 -0
- {hap_cli-0.8.20 → hap_cli-0.8.22}/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.22
|
|
4
4
|
Summary: CLI harness for Mingdao HAP - Enterprise no-code platform
|
|
5
5
|
Author: hap-cli
|
|
6
6
|
License: Apache-2.0
|
|
@@ -272,7 +272,7 @@ discover every subcommand.
|
|
|
272
272
|
| `chat list` | Recent sessions |
|
|
273
273
|
| `chat messages` | 1-on-1 / group / inbox messages |
|
|
274
274
|
| `chat files` | Files shared in a chat |
|
|
275
|
-
| `chat send-to-one` | Send a
|
|
275
|
+
| `chat send-to-one` | Send a message, optionally with files (`--file`), to one or more users (1-on-1) |
|
|
276
276
|
| `chat send-to-group` | Send a plain-text message to a group chat |
|
|
277
277
|
| `chat card-detail` | Resolve embedded card references |
|
|
278
278
|
|
|
@@ -298,13 +298,21 @@ discover every subcommand.
|
|
|
298
298
|
| `icon search` | Search icons by Chinese/English keyword (OR across terms, more matches rank higher); fewer than 10 matches get random suggestions appended; no keyword lists all |
|
|
299
299
|
| `icon list [-n SIZE] [-p PAGE]` | List icons page by page with keywords (50 per page by default) |
|
|
300
300
|
|
|
301
|
+
### attachment — stored files
|
|
302
|
+
|
|
303
|
+
| Command | Description |
|
|
304
|
+
|---|---|
|
|
305
|
+
| `attachment share ADDRESS` | Create a link to a stored file that you can pass on (`--hours`, default 48) |
|
|
306
|
+
|
|
307
|
+
> ADDRESS is the file's link — one that has already stopped working is fine, paste it as-is — or just the path part of it. The file itself does not expire, only the link does, so a dead link can always be revived.
|
|
308
|
+
|
|
301
309
|
### upload — file upload
|
|
302
310
|
|
|
303
311
|
| Command | Description |
|
|
304
312
|
|---|---|
|
|
305
|
-
| `upload [SOURCES...]` | Upload local paths or http(s) URLs to the file store; prints neutral uploaded-file descriptors (fileID/key/url/serverName/filePath/fileName/fileExt/originalFileName/fileSize) |
|
|
313
|
+
| `upload [SOURCES...]` | Upload local paths or http(s) URLs to the file store; prints neutral uploaded-file descriptors (fileID/key/url/urlExpiresAt/serverName/filePath/fileName/fileExt/originalFileName/fileSize) |
|
|
306
314
|
|
|
307
|
-
> A cross-feature capability — the same descriptors can be attached to a worksheet Attachment field, a
|
|
315
|
+
> A cross-feature capability — the same descriptors can be attached to a worksheet Attachment field, a post, a calendar event, or a comment. The returned `url` is a temporary address for your own immediate use and stops working at `urlExpiresAt`; never send it to anyone. To share a file, attach it where it belongs — e.g. `hap chat send-to-one --file <path>`. Use `--files '[{"name":"cover.png","url":"https://..."}]'` to set display names; `--worksheet-id` / `--app-id` refine upload-token routing.
|
|
308
316
|
|
|
309
317
|
### config — local CLI settings
|
|
310
318
|
|
|
@@ -313,6 +321,7 @@ discover every subcommand.
|
|
|
313
321
|
| `config show` | Display the current configuration summary |
|
|
314
322
|
| `config completion [bash\|zsh\|fish] [--install]` | Enable `<Tab>` completion |
|
|
315
323
|
| `config language [LANG]` | Switch UI language (`en` / `zh-Hans` / `zh-Hant` / `ja`) |
|
|
324
|
+
| `config update [auto\|notify\|off]` | Self-upgrade mode; `notify` only reports, `off` never checks |
|
|
316
325
|
| `config log on / off / status` | Toggle and inspect API logging |
|
|
317
326
|
| `config log level LEVEL` | `DEBUG / INFO / WARNING / ERROR / CRITICAL` |
|
|
318
327
|
| `config log view [--lines N] [--no-follow]` | Tail the log file |
|
|
@@ -243,7 +243,7 @@ discover every subcommand.
|
|
|
243
243
|
| `chat list` | Recent sessions |
|
|
244
244
|
| `chat messages` | 1-on-1 / group / inbox messages |
|
|
245
245
|
| `chat files` | Files shared in a chat |
|
|
246
|
-
| `chat send-to-one` | Send a
|
|
246
|
+
| `chat send-to-one` | Send a message, optionally with files (`--file`), to one or more users (1-on-1) |
|
|
247
247
|
| `chat send-to-group` | Send a plain-text message to a group chat |
|
|
248
248
|
| `chat card-detail` | Resolve embedded card references |
|
|
249
249
|
|
|
@@ -269,13 +269,21 @@ discover every subcommand.
|
|
|
269
269
|
| `icon search` | Search icons by Chinese/English keyword (OR across terms, more matches rank higher); fewer than 10 matches get random suggestions appended; no keyword lists all |
|
|
270
270
|
| `icon list [-n SIZE] [-p PAGE]` | List icons page by page with keywords (50 per page by default) |
|
|
271
271
|
|
|
272
|
+
### attachment — stored files
|
|
273
|
+
|
|
274
|
+
| Command | Description |
|
|
275
|
+
|---|---|
|
|
276
|
+
| `attachment share ADDRESS` | Create a link to a stored file that you can pass on (`--hours`, default 48) |
|
|
277
|
+
|
|
278
|
+
> ADDRESS is the file's link — one that has already stopped working is fine, paste it as-is — or just the path part of it. The file itself does not expire, only the link does, so a dead link can always be revived.
|
|
279
|
+
|
|
272
280
|
### upload — file upload
|
|
273
281
|
|
|
274
282
|
| Command | Description |
|
|
275
283
|
|---|---|
|
|
276
|
-
| `upload [SOURCES...]` | Upload local paths or http(s) URLs to the file store; prints neutral uploaded-file descriptors (fileID/key/url/serverName/filePath/fileName/fileExt/originalFileName/fileSize) |
|
|
284
|
+
| `upload [SOURCES...]` | Upload local paths or http(s) URLs to the file store; prints neutral uploaded-file descriptors (fileID/key/url/urlExpiresAt/serverName/filePath/fileName/fileExt/originalFileName/fileSize) |
|
|
277
285
|
|
|
278
|
-
> A cross-feature capability — the same descriptors can be attached to a worksheet Attachment field, a
|
|
286
|
+
> A cross-feature capability — the same descriptors can be attached to a worksheet Attachment field, a post, a calendar event, or a comment. The returned `url` is a temporary address for your own immediate use and stops working at `urlExpiresAt`; never send it to anyone. To share a file, attach it where it belongs — e.g. `hap chat send-to-one --file <path>`. Use `--files '[{"name":"cover.png","url":"https://..."}]'` to set display names; `--worksheet-id` / `--app-id` refine upload-token routing.
|
|
279
287
|
|
|
280
288
|
### config — local CLI settings
|
|
281
289
|
|
|
@@ -284,6 +292,7 @@ discover every subcommand.
|
|
|
284
292
|
| `config show` | Display the current configuration summary |
|
|
285
293
|
| `config completion [bash\|zsh\|fish] [--install]` | Enable `<Tab>` completion |
|
|
286
294
|
| `config language [LANG]` | Switch UI language (`en` / `zh-Hans` / `zh-Hant` / `ja`) |
|
|
295
|
+
| `config update [auto\|notify\|off]` | Self-upgrade mode; `notify` only reports, `off` never checks |
|
|
287
296
|
| `config log on / off / status` | Toggle and inspect API logging |
|
|
288
297
|
| `config log level LEVEL` | `DEBUG / INFO / WARNING / ERROR / CRITICAL` |
|
|
289
298
|
| `config log view [--lines N] [--no-follow]` | Tail the log file |
|
|
@@ -243,7 +243,7 @@ discover every subcommand.
|
|
|
243
243
|
| `chat list` | Recent sessions |
|
|
244
244
|
| `chat messages` | 1-on-1 / group / inbox messages |
|
|
245
245
|
| `chat files` | Files shared in a chat |
|
|
246
|
-
| `chat send-to-one` | Send a
|
|
246
|
+
| `chat send-to-one` | Send a message, optionally with files (`--file`), to one or more users (1-on-1) |
|
|
247
247
|
| `chat send-to-group` | Send a plain-text message to a group chat |
|
|
248
248
|
| `chat card-detail` | Resolve embedded card references |
|
|
249
249
|
|
|
@@ -269,13 +269,21 @@ discover every subcommand.
|
|
|
269
269
|
| `icon search` | Search icons by Chinese/English keyword (OR across terms, more matches rank higher); fewer than 10 matches get random suggestions appended; no keyword lists all |
|
|
270
270
|
| `icon list [-n SIZE] [-p PAGE]` | List icons page by page with keywords (50 per page by default) |
|
|
271
271
|
|
|
272
|
+
### attachment — stored files
|
|
273
|
+
|
|
274
|
+
| Command | Description |
|
|
275
|
+
|---|---|
|
|
276
|
+
| `attachment share ADDRESS` | Create a link to a stored file that you can pass on (`--hours`, default 48) |
|
|
277
|
+
|
|
278
|
+
> ADDRESS is the file's link — one that has already stopped working is fine, paste it as-is — or just the path part of it. The file itself does not expire, only the link does, so a dead link can always be revived.
|
|
279
|
+
|
|
272
280
|
### upload — file upload
|
|
273
281
|
|
|
274
282
|
| Command | Description |
|
|
275
283
|
|---|---|
|
|
276
|
-
| `upload [SOURCES...]` | Upload local paths or http(s) URLs to the file store; prints neutral uploaded-file descriptors (fileID/key/url/serverName/filePath/fileName/fileExt/originalFileName/fileSize) |
|
|
284
|
+
| `upload [SOURCES...]` | Upload local paths or http(s) URLs to the file store; prints neutral uploaded-file descriptors (fileID/key/url/urlExpiresAt/serverName/filePath/fileName/fileExt/originalFileName/fileSize) |
|
|
277
285
|
|
|
278
|
-
> A cross-feature capability — the same descriptors can be attached to a worksheet Attachment field, a
|
|
286
|
+
> A cross-feature capability — the same descriptors can be attached to a worksheet Attachment field, a post, a calendar event, or a comment. The returned `url` is a temporary address for your own immediate use and stops working at `urlExpiresAt`; never send it to anyone. To share a file, attach it where it belongs — e.g. `hap chat send-to-one --file <path>`. Use `--files '[{"name":"cover.png","url":"https://..."}]'` to set display names; `--worksheet-id` / `--app-id` refine upload-token routing.
|
|
279
287
|
|
|
280
288
|
### config — local CLI settings
|
|
281
289
|
|
|
@@ -284,6 +292,7 @@ discover every subcommand.
|
|
|
284
292
|
| `config show` | Display the current configuration summary |
|
|
285
293
|
| `config completion [bash\|zsh\|fish] [--install]` | Enable `<Tab>` completion |
|
|
286
294
|
| `config language [LANG]` | Switch UI language (`en` / `zh-Hans` / `zh-Hant` / `ja`) |
|
|
295
|
+
| `config update [auto\|notify\|off]` | Self-upgrade mode; `notify` only reports, `off` never checks |
|
|
287
296
|
| `config log on / off / status` | Toggle and inspect API logging |
|
|
288
297
|
| `config log level LEVEL` | `DEBUG / INFO / WARNING / ERROR / CRITICAL` |
|
|
289
298
|
| `config log view [--lines N] [--no-follow]` | Tail the log file |
|
|
@@ -226,7 +226,7 @@ hap --json worksheet record list WORKSHEET_ID
|
|
|
226
226
|
| `chat list` | 最近会话 |
|
|
227
227
|
| `chat messages` | 单聊 / 群聊 / 收件箱(系统、应用、工作流等) |
|
|
228
228
|
| `chat files` | 聊天中分享的文件 |
|
|
229
|
-
| `chat send` |
|
|
229
|
+
| `chat send-to-one` | 向一个或多个用户发消息(单聊),可带附件 `--file`(文件作为聊天附件送达,不是链接) |
|
|
230
230
|
| `chat group-info` | 群组信息 |
|
|
231
231
|
| `chat card-detail` | 解析消息中嵌入的卡片引用 |
|
|
232
232
|
|
|
@@ -243,13 +243,21 @@ hap --json worksheet record list WORKSHEET_ID
|
|
|
243
243
|
| `icon search` | 按中英文关键词搜索图标(多关键词取并集,命中越多排越前);命中不足 10 个时随机补足推荐;无关键词列出全部 |
|
|
244
244
|
| `icon list [-n SIZE] [-p PAGE]` | 分页列出图标及其关键词(默认每页 50 个) |
|
|
245
245
|
|
|
246
|
+
### attachment — 已存储文件
|
|
247
|
+
|
|
248
|
+
| 命令 | 说明 |
|
|
249
|
+
|---|---|
|
|
250
|
+
| `attachment share ADDRESS` | 为已存储的文件生成一条可以转给别人的链接(`--hours`,默认 48 小时) |
|
|
251
|
+
|
|
252
|
+
> ADDRESS 传文件的链接即可——**已经失效的链接照样能传,原样粘贴**——也可以只传路径部分。文件本身不会过期,过期的只是链接,所以失效链接随时可以重新生成。
|
|
253
|
+
|
|
246
254
|
### upload — 文件上传
|
|
247
255
|
|
|
248
256
|
| 命令 | 说明 |
|
|
249
257
|
|---|---|
|
|
250
|
-
| `upload [SOURCES...]` | 上传本地路径或 http(s) 直链到文件存储,返回中性的「已上传文件描述符」(fileID/key/url/serverName/filePath/fileName/fileExt/originalFileName/fileSize) |
|
|
258
|
+
| `upload [SOURCES...]` | 上传本地路径或 http(s) 直链到文件存储,返回中性的「已上传文件描述符」(fileID/key/url/urlExpiresAt/serverName/filePath/fileName/fileExt/originalFileName/fileSize) |
|
|
251
259
|
|
|
252
|
-
>
|
|
260
|
+
> 跨功能的通用能力——同一份描述符可用于工作表附件字段、动态、日程、评论等。返回的 `url` 只是给你自己临时取用的地址,到 `urlExpiresAt` 就失效,不要发给别人;要把文件给别人,请用对应的附件入口,例如 `hap chat send-to-one --file <路径>`。用 `--files '[{"name":"封面.png","url":"https://..."}]'` 指定显示名;`--worksheet-id` / `--app-id` 优化上传 token 路由。
|
|
253
261
|
|
|
254
262
|
### config — 本地 CLI 配置
|
|
255
263
|
|
|
@@ -258,6 +266,7 @@ hap --json worksheet record list WORKSHEET_ID
|
|
|
258
266
|
| `config show` | 显示 CLI 配置摘要 |
|
|
259
267
|
| `config completion [bash\|zsh\|fish] [--install]` | 启用 `<Tab>` 补全 |
|
|
260
268
|
| `config language [LANG]` | 切换显示语言(`en` / `zh-Hans` / `zh-Hant` / `ja`) |
|
|
269
|
+
| `config update [auto\|notify\|off]` | 自动升级开关;`notify` 只提示不安装,`off` 不检查 |
|
|
261
270
|
| `config log on / off / status` | 日志开关与状态 |
|
|
262
271
|
| `config log level LEVEL` | 设置日志级别(`DEBUG/INFO/WARNING/ERROR/CRITICAL`) |
|
|
263
272
|
| `config log view [--lines N] [--no-follow]` | 跟踪日志文件 |
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""CLI commands for files stored as attachments."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from hap_cli.context import pass_context
|
|
6
|
+
from hap_cli.core import attachment as attachment_mod
|
|
7
|
+
from hap_cli.utils.formatting import output_json
|
|
8
|
+
from hap_cli.i18n import t
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@click.group("attachment", help=t("Files stored as attachments."))
|
|
12
|
+
def attachment():
|
|
13
|
+
"""Attachment group."""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@attachment.command("share")
|
|
17
|
+
@click.argument("address")
|
|
18
|
+
@click.option(
|
|
19
|
+
"--hours", type=int, default=attachment_mod.DEFAULT_SHARE_HOURS,
|
|
20
|
+
show_default=True, help="How long the link stays usable.",
|
|
21
|
+
)
|
|
22
|
+
@pass_context
|
|
23
|
+
def attachment_share(ctx, address, hours):
|
|
24
|
+
"""Create a link to a stored file that you can pass on.
|
|
25
|
+
|
|
26
|
+
\b
|
|
27
|
+
hap attachment share https://doc.example.com/doc/20260830/abc.html
|
|
28
|
+
hap attachment share doc/20260830/abc.html --hours 168
|
|
29
|
+
|
|
30
|
+
ADDRESS is the file's link — a link that has already stopped working
|
|
31
|
+
is fine, paste it as-is — or just the path part of it.
|
|
32
|
+
"""
|
|
33
|
+
try:
|
|
34
|
+
session = ctx.get_session()
|
|
35
|
+
data = attachment_mod.share_url(session, address, hours=hours)
|
|
36
|
+
ctx.output(data, _human)
|
|
37
|
+
except Exception as e:
|
|
38
|
+
ctx.handle_error(e)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _human(d):
|
|
42
|
+
click.echo(d["url"])
|
|
43
|
+
if d.get("expiresAt"):
|
|
44
|
+
click.echo(f"Usable until {d['expiresAt']}")
|
|
@@ -6,6 +6,7 @@ import click
|
|
|
6
6
|
|
|
7
7
|
from hap_cli.context import pass_context
|
|
8
8
|
from hap_cli.core import chat as chat_mod
|
|
9
|
+
from hap_cli.core import upload as upload_mod
|
|
9
10
|
from hap_cli.utils.formatting import output_json, output_table
|
|
10
11
|
from hap_cli.i18n import t
|
|
11
12
|
|
|
@@ -251,19 +252,64 @@ def chat_messages(
|
|
|
251
252
|
|
|
252
253
|
@chat.command("send-to-one")
|
|
253
254
|
@click.option("--to", "-t", multiple=True, help="Target user account ID (can repeat)")
|
|
254
|
-
@click.option("--message", "-m",
|
|
255
|
+
@click.option("--message", "-m", default="", help="Message text")
|
|
256
|
+
@click.option(
|
|
257
|
+
"--file", "-f", "files", multiple=True,
|
|
258
|
+
help="Attach a file: a local path or an http(s) address. Repeat for "
|
|
259
|
+
"several. The file arrives as an attachment the recipient can "
|
|
260
|
+
"open at any time, not as a link that stops working.",
|
|
261
|
+
)
|
|
262
|
+
@click.option(
|
|
263
|
+
"--dry-run", is_flag=True, default=False,
|
|
264
|
+
help="Show what would be sent, without uploading or sending anything.",
|
|
265
|
+
)
|
|
255
266
|
@pass_context
|
|
256
|
-
def chat_send_to_one(ctx, to, message):
|
|
257
|
-
"""Send a
|
|
267
|
+
def chat_send_to_one(ctx, to, message, files, dry_run):
|
|
268
|
+
"""Send a message, optionally with files, to one or more users (1-on-1).
|
|
269
|
+
|
|
270
|
+
\b
|
|
271
|
+
hap chat send-to-one -t <accountId> -m "spec attached" -f ./spec.pdf
|
|
272
|
+
|
|
273
|
+
Text and each file arrive as separate messages, in that order. You
|
|
274
|
+
cannot message yourself — your own account is skipped.
|
|
275
|
+
"""
|
|
258
276
|
if not to:
|
|
259
277
|
ctx.handle_error(click.UsageError(
|
|
260
278
|
"Provide at least one --to <accountId>."
|
|
261
279
|
))
|
|
262
280
|
return
|
|
281
|
+
if not message and not files:
|
|
282
|
+
ctx.handle_error(click.UsageError(
|
|
283
|
+
"Provide --message, --file, or both."
|
|
284
|
+
))
|
|
285
|
+
return
|
|
286
|
+
sources = upload_mod.source_descriptors(list(files))
|
|
287
|
+
if dry_run:
|
|
288
|
+
ctx.output(
|
|
289
|
+
{"to": list(to), "message": message, "files": list(files),
|
|
290
|
+
"sent": False},
|
|
291
|
+
lambda d: click.echo(
|
|
292
|
+
"Dry run — nothing sent."
|
|
293
|
+
+ f"\n To: {', '.join(to)}"
|
|
294
|
+
+ (f"\n Message: {message}" if message else "")
|
|
295
|
+
+ "".join(f"\n File: {f}" for f in files)
|
|
296
|
+
),
|
|
297
|
+
)
|
|
298
|
+
return
|
|
263
299
|
try:
|
|
264
300
|
session = ctx.get_session()
|
|
265
|
-
|
|
266
|
-
|
|
301
|
+
if not sources:
|
|
302
|
+
data = chat_mod.send_message(session, list(to), message)
|
|
303
|
+
ctx.output(data, lambda d: click.echo("Message sent."))
|
|
304
|
+
return
|
|
305
|
+
descriptors = chat_mod.upload_chat_files(session, sources)
|
|
306
|
+
acks = chat_mod.send_files(session, list(to), descriptors, message)
|
|
307
|
+
ctx.output(
|
|
308
|
+
{"sent": len(acks), "files": len(descriptors), "acks": acks},
|
|
309
|
+
lambda d: click.echo(
|
|
310
|
+
f"Sent {len(descriptors)} file(s) to {len(to)} recipient(s)."
|
|
311
|
+
),
|
|
312
|
+
)
|
|
267
313
|
except Exception as e:
|
|
268
314
|
ctx.handle_error(e)
|
|
269
315
|
|
|
@@ -122,6 +122,8 @@ def config_completion(shell, install):
|
|
|
122
122
|
@pass_context
|
|
123
123
|
def config_show(ctx):
|
|
124
124
|
"""Display current harness configuration."""
|
|
125
|
+
from hap_cli.core.update import get_update_mode
|
|
126
|
+
|
|
125
127
|
log_cfg = load_logging_config()
|
|
126
128
|
data = {
|
|
127
129
|
"logging": {
|
|
@@ -129,6 +131,7 @@ def config_show(ctx):
|
|
|
129
131
|
"level": log_cfg["level"],
|
|
130
132
|
"file": str(resolve_log_path(log_cfg)),
|
|
131
133
|
},
|
|
134
|
+
"update": get_update_mode(),
|
|
132
135
|
}
|
|
133
136
|
|
|
134
137
|
def _human(d):
|
|
@@ -136,6 +139,7 @@ def config_show(ctx):
|
|
|
136
139
|
click.echo(f" enabled : {d['logging']['enabled']}")
|
|
137
140
|
click.echo(f" level : {d['logging']['level']}")
|
|
138
141
|
click.echo(f" file : {d['logging']['file']}")
|
|
142
|
+
click.echo(f"update : {d['update']}")
|
|
139
143
|
|
|
140
144
|
ctx.output(data, _human)
|
|
141
145
|
|
|
@@ -205,6 +209,46 @@ def log_status(ctx):
|
|
|
205
209
|
_echo_log_status(ctx, cfg)
|
|
206
210
|
|
|
207
211
|
|
|
212
|
+
# ── `hap config update` ───────────────────────────────────────────────────
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
@config.command("update")
|
|
216
|
+
@click.argument(
|
|
217
|
+
"mode", required=False, type=click.Choice(["auto", "notify", "off"]),
|
|
218
|
+
)
|
|
219
|
+
@pass_context
|
|
220
|
+
def config_update(ctx, mode):
|
|
221
|
+
"""Control whether hap-cli upgrades itself.
|
|
222
|
+
|
|
223
|
+
\b
|
|
224
|
+
auto check hourly and install new versions (default)
|
|
225
|
+
notify check hourly and tell you, but never install
|
|
226
|
+
off never check
|
|
227
|
+
|
|
228
|
+
Use ``notify`` or ``off`` to pin the version in scripted or
|
|
229
|
+
production environments. Without an argument, shows the current
|
|
230
|
+
setting. ``hap update`` still upgrades on demand in every mode.
|
|
231
|
+
"""
|
|
232
|
+
from hap_cli.core.session import load_config, save_config
|
|
233
|
+
from hap_cli.core.update import get_update_mode
|
|
234
|
+
|
|
235
|
+
if mode is None:
|
|
236
|
+
current = get_update_mode()
|
|
237
|
+
if ctx.json_mode:
|
|
238
|
+
from hap_cli.utils.formatting import output_json
|
|
239
|
+
output_json({"update": current})
|
|
240
|
+
else:
|
|
241
|
+
click.echo(f"Self-update: {current}")
|
|
242
|
+
return
|
|
243
|
+
|
|
244
|
+
save_config({"update": mode})
|
|
245
|
+
if ctx.json_mode:
|
|
246
|
+
from hap_cli.utils.formatting import output_json
|
|
247
|
+
output_json({"status": "ok", "update": mode})
|
|
248
|
+
else:
|
|
249
|
+
click.echo(f"Self-update set to: {mode}")
|
|
250
|
+
|
|
251
|
+
|
|
208
252
|
# ── `hap config language` ─────────────────────────────────────────────────
|
|
209
253
|
|
|
210
254
|
|
|
@@ -10,7 +10,13 @@ from hap_cli.utils.formatting import output_json
|
|
|
10
10
|
from hap_cli.i18n import t
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
@click.command("upload", help=t(
|
|
13
|
+
@click.command("upload", help=t(
|
|
14
|
+
"Upload file(s) to the file store.\n\n"
|
|
15
|
+
"The returned \"url\" is a temporary address for your own immediate "
|
|
16
|
+
"use and stops working at the moment shown in \"urlExpiresAt\". Do not "
|
|
17
|
+
"send it to anyone — to share a file, attach it where it belongs, "
|
|
18
|
+
"e.g. 'hap chat send-to-one --file <path>'."
|
|
19
|
+
))
|
|
14
20
|
@click.argument("sources", nargs=-1)
|
|
15
21
|
@click.option("--files", "files_json", default="",
|
|
16
22
|
help="JSON array of {name,url} or {name,path} descriptors "
|
|
@@ -33,18 +39,18 @@ def upload(ctx, sources, files_json, worksheet_id, app_id):
|
|
|
33
39
|
originalFileName/fileSize) is returned. Consumers wrap these for their
|
|
34
40
|
own attachment shape — e.g. a worksheet Attachment field, a chat
|
|
35
41
|
message, a post, a comment, or a calendar event.
|
|
42
|
+
|
|
43
|
+
The returned "url" is a temporary address for your own immediate use
|
|
44
|
+
and stops working at the moment shown in "urlExpiresAt". Do not send
|
|
45
|
+
it to anyone — to share a file, attach it where it belongs, e.g.
|
|
46
|
+
'hap chat send-to-one --file <path>'.
|
|
36
47
|
"""
|
|
37
48
|
try:
|
|
38
49
|
session = ctx.get_session()
|
|
39
50
|
if files_json:
|
|
40
51
|
files = json.loads(files_json)
|
|
41
52
|
else:
|
|
42
|
-
files =
|
|
43
|
-
for s in sources:
|
|
44
|
-
if s.startswith("http://") or s.startswith("https://"):
|
|
45
|
-
files.append({"url": s})
|
|
46
|
-
else:
|
|
47
|
-
files.append({"path": s})
|
|
53
|
+
files = upload_mod.source_descriptors(sources)
|
|
48
54
|
if not files:
|
|
49
55
|
raise click.UsageError("provide SOURCES or --files")
|
|
50
56
|
descriptors = upload_mod.upload_files(
|
|
@@ -110,9 +110,15 @@ def build_button_payload(spec: dict[str, Any]) -> dict[str, Any]:
|
|
|
110
110
|
# in the UI; for the dedicated 二次确认 button use clickType 2.
|
|
111
111
|
if out["clickType"] == 1 and confirm:
|
|
112
112
|
out["clickType"] = 2
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
# Dialog text is stored on the button itself, so it must be
|
|
114
|
+
# written in the application's language, not ours. Follows the
|
|
115
|
+
# active CLI language; an explicit value always wins.
|
|
116
|
+
from hap_cli.i18n import content_default
|
|
117
|
+
|
|
118
|
+
out["confirmMsg"] = confirm_msg or content_default("button.confirmMsg")
|
|
119
|
+
out["sureName"] = spec.get("sureName") or content_default("button.sure")
|
|
120
|
+
out["cancelName"] = (
|
|
121
|
+
spec.get("cancelName") or content_default("button.cancel"))
|
|
116
122
|
|
|
117
123
|
# enableWhen → filters (reuse the shared filter translator).
|
|
118
124
|
enable_when = spec.get("enableWhen")
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""Attachments in the file store: shareable links for stored files.
|
|
2
|
+
|
|
3
|
+
The address handed out at upload time is a private-bucket signature that
|
|
4
|
+
expires within the hour (``upload.url_expires_at``). The file behind it
|
|
5
|
+
does not expire — the object path *is* the URL path — so a dead link is
|
|
6
|
+
re-signable at any time.
|
|
7
|
+
|
|
8
|
+
``Attachment/GetShareLocalAttachmentUrl`` is what the web UI's
|
|
9
|
+
"分享附件" action calls: pd-openweb
|
|
10
|
+
src/components/shareAttachment/toMobile.js:121 passes
|
|
11
|
+
``{filePath: file.qiniuPath, hours: 48}``, where ``qiniuPath`` is built
|
|
12
|
+
as ``window.config.FilePath + file.key``
|
|
13
|
+
(src/pages/chat/components/Message/MessageToolbar/index.js:222).
|
|
14
|
+
|
|
15
|
+
That prefix is not decorative. Verified live on 2026-08-31, the server
|
|
16
|
+
accepts the ``config.FilePath`` form and nothing else — a bare key, a
|
|
17
|
+
``documentHost``-prefixed URL, or the original signed URL with its query
|
|
18
|
+
intact each come back as an empty string with no error state. So this
|
|
19
|
+
module normalizes any address the user has to hand down to a key and
|
|
20
|
+
rebuilds the one prefix that works.
|
|
21
|
+
"""
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import logging
|
|
25
|
+
from typing import Any, Optional
|
|
26
|
+
from urllib.parse import urlparse
|
|
27
|
+
|
|
28
|
+
from hap_cli.core.session import APIError, Session, SessionError
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger("hap_cli.attachment")
|
|
31
|
+
|
|
32
|
+
# What the web UI uses when it shares an attachment (toMobile.js:123).
|
|
33
|
+
DEFAULT_SHARE_HOURS = 48
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def store_key(address: str) -> str:
|
|
37
|
+
"""Reduce any form of a stored file's address to its store key.
|
|
38
|
+
|
|
39
|
+
Accepts a full URL on any of the store's hosts (with or without the
|
|
40
|
+
``?e=…&token=…`` signature still attached — a dead link pasted out of
|
|
41
|
+
a chat message is the common case), a leading-slash path, or a bare
|
|
42
|
+
key.
|
|
43
|
+
"""
|
|
44
|
+
if not address or not address.strip():
|
|
45
|
+
raise ValueError("a file address or key is required")
|
|
46
|
+
address = address.strip()
|
|
47
|
+
if "://" in address:
|
|
48
|
+
address = urlparse(address).path
|
|
49
|
+
else:
|
|
50
|
+
# A bare key may still carry a query if it came from a copied link.
|
|
51
|
+
address = address.split("?", 1)[0]
|
|
52
|
+
return address.lstrip("/")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _file_path_prefix(session: Session) -> str:
|
|
56
|
+
"""The store prefix this endpoint requires in ``filePath``.
|
|
57
|
+
|
|
58
|
+
Bootstrap publishes it as ``config.FilePath`` — the same value chat
|
|
59
|
+
file addresses are built from (``chat.chat_file_host``).
|
|
60
|
+
"""
|
|
61
|
+
meta = session.get_global_meta()
|
|
62
|
+
for scope in (meta.get("config"), meta):
|
|
63
|
+
if isinstance(scope, dict) and scope.get("FilePath"):
|
|
64
|
+
return scope["FilePath"]
|
|
65
|
+
raise SessionError(
|
|
66
|
+
"This server did not publish a file address, so a link cannot be "
|
|
67
|
+
"created. Check that you are signed in to the right server, then "
|
|
68
|
+
"try again."
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def share_url(
|
|
73
|
+
session: Session,
|
|
74
|
+
address: str,
|
|
75
|
+
*,
|
|
76
|
+
hours: int = DEFAULT_SHARE_HOURS,
|
|
77
|
+
) -> dict[str, Any]:
|
|
78
|
+
"""Create a fresh, time-limited link to a file already in the store.
|
|
79
|
+
|
|
80
|
+
``address`` is anything that identifies the file: its current or
|
|
81
|
+
expired link, or its bare key. Returns
|
|
82
|
+
``{url, expiresAt, hours, key}``.
|
|
83
|
+
"""
|
|
84
|
+
from hap_cli.core.upload import _iso, url_expires_at
|
|
85
|
+
|
|
86
|
+
if hours <= 0:
|
|
87
|
+
raise ValueError("hours must be a positive number")
|
|
88
|
+
key = store_key(address)
|
|
89
|
+
prefix = _file_path_prefix(session)
|
|
90
|
+
url = session.api_call(
|
|
91
|
+
"Attachment", "GetShareLocalAttachmentUrl",
|
|
92
|
+
{"filePath": prefix + key, "hours": hours},
|
|
93
|
+
)
|
|
94
|
+
if not url or not isinstance(url, str):
|
|
95
|
+
# An unknown or unreachable file is answered with an empty string
|
|
96
|
+
# and a success state, so there is nothing to detect but this.
|
|
97
|
+
logger.warning("GetShareLocalAttachmentUrl returned %r for key=%s", url, key)
|
|
98
|
+
raise APIError(
|
|
99
|
+
"Could not create a link for that file. Check the address is "
|
|
100
|
+
"complete and that the file still exists."
|
|
101
|
+
)
|
|
102
|
+
return {
|
|
103
|
+
"url": url,
|
|
104
|
+
"expiresAt": _iso(url_expires_at(url)),
|
|
105
|
+
"hours": hours,
|
|
106
|
+
"key": key,
|
|
107
|
+
}
|