hap-cli 0.8.21__tar.gz → 0.8.23__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.21 → hap_cli-0.8.23}/MANIFEST.in +2 -5
- {hap_cli-0.8.21 → hap_cli-0.8.23}/PKG-INFO +18 -4
- {hap_cli-0.8.21/hap_cli → hap_cli-0.8.23}/README.md +17 -3
- {hap_cli-0.8.21 → hap_cli-0.8.23/hap_cli}/README.md +17 -3
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/README_CN.md +17 -3
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/__init__.py +1 -1
- hap_cli-0.8.23/hap_cli/commands/attachment_cmd.py +44 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/auth_cmd.py +5 -1
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/chat_cmd.py +56 -6
- hap_cli-0.8.23/hap_cli/commands/guide_cmd.py +36 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/record_cmd.py +8 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/upload_cmd.py +13 -7
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/worksheet_cmd.py +6 -1
- hap_cli-0.8.23/hap_cli/core/attachment.py +107 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/chat.py +208 -15
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/editor/editspec.py +15 -20
- hap_cli-0.8.23/hap_cli/core/guide.py +176 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/upload.py +67 -7
- hap_cli-0.8.23/hap_cli/guide/en/messages.md +54 -0
- hap_cli-0.8.23/hap_cli/guide/en/overview.md +45 -0
- hap_cli-0.8.23/hap_cli/guide/en/record.md +289 -0
- hap_cli-0.8.23/hap_cli/guide/en/setup.md +99 -0
- hap_cli-0.8.23/hap_cli/guide/en/skills.md +48 -0
- hap_cli-0.8.23/hap_cli/guide/index.json +36 -0
- hap_cli-0.8.23/hap_cli/guide/zh-Hans/messages.md +52 -0
- hap_cli-0.8.23/hap_cli/guide/zh-Hans/overview.md +39 -0
- hap_cli-0.8.23/hap_cli/guide/zh-Hans/record.md +276 -0
- hap_cli-0.8.23/hap_cli/guide/zh-Hans/setup.md +91 -0
- hap_cli-0.8.23/hap_cli/guide/zh-Hans/skills.md +45 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/hap_cli.py +10 -1
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/i18n.py +15 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_app_editor.py +35 -0
- hap_cli-0.8.23/hap_cli/tests/test_attachment_share.py +148 -0
- hap_cli-0.8.23/hap_cli/tests/test_chat_attachment_send.py +358 -0
- hap_cli-0.8.23/hap_cli/tests/test_guide.py +162 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli.egg-info/PKG-INFO +18 -4
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli.egg-info/SOURCES.txt +22 -4
- {hap_cli-0.8.21 → hap_cli-0.8.23}/setup.py +7 -15
- {hap_cli-0.8.21 → hap_cli-0.8.23}/app_live_tests/__init__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/app_live_tests/__main__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/app_live_tests/config.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/app_live_tests/harness.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/app_live_tests/smoke.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/app_live_tests/state.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/__main__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/__init__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/app_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/app_creator_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/app_editor_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/calendar_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/chart_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/chatbot_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/config_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/contact_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/department_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/group_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/icon_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/instance_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/node_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/optionset_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/page_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/post_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/region_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/role_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/update_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/v3_registry.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/commands/workflow_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/context.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/__init__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/action_spec_adapter.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/__init__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/_hapmeta/__init__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/_hapmeta/worksheet_templates.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/charts.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/cleanup.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/compiler.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/config.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/design/design.schema.json +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/errors.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/examples/minimal.design.json +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/executor.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/fields.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/hap.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/merge.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/recording/__init__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/recording/console.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/recording/jsonl.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/recording/mirror.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/recording/report.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/schema.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/seed/INSTRUCTIONS.md +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/seed/__init__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/seed/cli.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/seed/executor.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/seed/resources/attachments.json +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/seed/resources/sample.docx +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/seed/resources/sample.pdf +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/seed/resources/sample_images.json +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/seed/template.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/selftest.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/smoke.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/steps.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/store.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/validate.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/app_creator/workflow_dsl.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/auth.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/calendar_mod.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/chart.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/chatbot.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/cli_access.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/contact.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/control_type_codes.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/department.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/editor/__init__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/editor/_hapmeta/__init__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/editor/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/editor/apply.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/editor/componentlower.py +0 -0
- {hap_cli-0.8.21/skills/cli/hap-cli-app-editor/scripts → hap_cli-0.8.23/hap_cli/core/editor}/editspec/component.schema.json +0 -0
- {hap_cli-0.8.21/skills/cli/hap-cli-app-editor/scripts → hap_cli-0.8.23/hap_cli/core/editor}/editspec/custom-action.schema.json +0 -0
- {hap_cli-0.8.21/skills/cli/hap-cli-app-editor/scripts → hap_cli-0.8.23/hap_cli/core/editor}/editspec/envelope.schema.json +0 -0
- {hap_cli-0.8.21/skills/cli/hap-cli-app-editor/scripts → hap_cli-0.8.23/hap_cli/core/editor}/editspec/field.schema.json +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/editor/errors.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/editor/fieldlower.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/editor/jsonschema_mini.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/editor/models.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/editor/ops.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/editor/planner.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/editor/reader.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/field_normalizer.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/field_spec_adapter.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/filter_translator.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/flow_node.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/global_meta.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/group.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/icon_index.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/instance.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/logger.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/optionset.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/page.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/post.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/record.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/response_crypto.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/role.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/role_perm_builder.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/session.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/token_crypto.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/update.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/v3/__init__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/v3/dispatcher.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/v3/render.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/v3/schema.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/view_spec_adapter.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/workflow.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/workflow_node_dsl.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/worksheet.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/core/worksheet_templates.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/locale/__init__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/locale/messages.json +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/locale/messages.schema.json +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/__init__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/conftest.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_app_creator.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_app_export_usage.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_auth_prerelease.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_bug_036430.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_bug_036750.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_chart.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_cli_access.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_config_cmd.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_content_language.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_control_lookup_guard.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_core.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_destructive_confirm_cli.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_full_e2e.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_global_meta.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_i18n.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_instance_history_cli.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_integration.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_integration_approval.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_integration_approval_actions.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_integration_calendar.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_integration_destructive.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_integration_misc.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_integration_post.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_integration_social.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_integration_v3.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_integration_workflow.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_integration_worksheet_extra.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_member_relation_array_wrap.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_multi_profile.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_no_workflow_unsupported.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_org_approval_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_org_id_cli.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_org_id_docs.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_parameter_conventions.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_parameter_mapping_registry.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_record_batch_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_record_field_alias.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_record_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_select_rejects_relation_value.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_semantic_types_registry.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_update.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_update_mode.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_upload_host_resolution.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_v3_api_schema_loader.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_v3_dispatcher.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_v3_registry_coverage.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_v3_session.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_v3_yaml_translation.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_workflow_envelope_errors.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_workflow_list_cli.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_workflow_read_write_keys.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_workflow_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_worksheet_create_section.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_worksheet_crud_cli.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/tests/test_worksheet_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/utils/__init__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/utils/formatting.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/utils/options.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli/utils/parameter_mapping.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli.egg-info/dependency_links.txt +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli.egg-info/entry_points.txt +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli.egg-info/requires.txt +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/hap_cli.egg-info/top_level.txt +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/__init__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/__main__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/_wftest.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/charts.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/cleanup.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/compiler.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/config.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/errors.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/executor.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/fields.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/hap.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/recording/__init__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/recording/console.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/recording/jsonl.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/recording/mirror.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/recording/report.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/schema.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/seed/__init__.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/seed/cli.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/seed/executor.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/seed/template.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/selftest.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/smoke.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/step.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/steps.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/store.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/live_tests/workflow_dsl.py +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/setup.cfg +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/INDEX.json +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/add_member_to_role.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/batch_delete_records.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/create_optionset.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/create_role.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/delete_optionset.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/delete_record.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/delete_role.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/delete_worksheet.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/get_app_info.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/get_app_knowledge_list.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/get_app_worksheets_list.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/get_optionset_list.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/get_record_details.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/get_record_discussions.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/get_record_list.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/get_record_logs.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/get_record_pivot_data.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/get_record_relations.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/get_record_share_link.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/get_regions.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/get_role_details.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/get_role_list.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/knowledge_search.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/leave_all_roles.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/remove_member_from_role.yaml +0 -0
- {hap_cli-0.8.21 → hap_cli-0.8.23}/sources/v3-api-schema/update_optionset.yaml +0 -0
|
@@ -11,8 +11,5 @@ include sources/v3-api-schema/INDEX.json
|
|
|
11
11
|
include hap_cli/README.md
|
|
12
12
|
include hap_cli/README_CN.md
|
|
13
13
|
recursive-include hap_cli/locale *.json
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
# in the sdist so setup.py's build step can mirror them into
|
|
17
|
-
# hap_cli/core/editor/editspec/ for the ``hap app-editor`` runtime loader.
|
|
18
|
-
recursive-include skills/cli/hap-cli-app-editor/scripts/editspec *.json
|
|
14
|
+
include hap_cli/guide/index.json
|
|
15
|
+
recursive-include hap_cli/guide *.md
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hap-cli
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.23
|
|
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,27 @@ 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
|
+
|
|
309
|
+
### guide — built-in usage guide
|
|
310
|
+
|
|
311
|
+
| Command | Description |
|
|
312
|
+
|---|---|
|
|
313
|
+
| `guide` | Built-in usage guide: what this version can do, and the value formats that are easy to get wrong (`hap guide <topic>` for detail) |
|
|
314
|
+
|
|
301
315
|
### upload — file upload
|
|
302
316
|
|
|
303
317
|
| Command | Description |
|
|
304
318
|
|---|---|
|
|
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) |
|
|
319
|
+
| `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
320
|
|
|
307
|
-
> A cross-feature capability — the same descriptors can be attached to a worksheet Attachment field, a
|
|
321
|
+
> 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
322
|
|
|
309
323
|
### config — local CLI settings
|
|
310
324
|
|
|
@@ -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,27 @@ 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
|
+
|
|
280
|
+
### guide — built-in usage guide
|
|
281
|
+
|
|
282
|
+
| Command | Description |
|
|
283
|
+
|---|---|
|
|
284
|
+
| `guide` | Built-in usage guide: what this version can do, and the value formats that are easy to get wrong (`hap guide <topic>` for detail) |
|
|
285
|
+
|
|
272
286
|
### upload — file upload
|
|
273
287
|
|
|
274
288
|
| Command | Description |
|
|
275
289
|
|---|---|
|
|
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) |
|
|
290
|
+
| `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
291
|
|
|
278
|
-
> A cross-feature capability — the same descriptors can be attached to a worksheet Attachment field, a
|
|
292
|
+
> 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
293
|
|
|
280
294
|
### config — local CLI settings
|
|
281
295
|
|
|
@@ -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,27 @@ 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
|
+
|
|
280
|
+
### guide — built-in usage guide
|
|
281
|
+
|
|
282
|
+
| Command | Description |
|
|
283
|
+
|---|---|
|
|
284
|
+
| `guide` | Built-in usage guide: what this version can do, and the value formats that are easy to get wrong (`hap guide <topic>` for detail) |
|
|
285
|
+
|
|
272
286
|
### upload — file upload
|
|
273
287
|
|
|
274
288
|
| Command | Description |
|
|
275
289
|
|---|---|
|
|
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) |
|
|
290
|
+
| `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
291
|
|
|
278
|
-
> A cross-feature capability — the same descriptors can be attached to a worksheet Attachment field, a
|
|
292
|
+
> 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
293
|
|
|
280
294
|
### config — local CLI settings
|
|
281
295
|
|
|
@@ -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,27 @@ 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
|
+
|
|
254
|
+
### guide — 内置使用指南
|
|
255
|
+
|
|
256
|
+
| 命令 | 说明 |
|
|
257
|
+
|---|---|
|
|
258
|
+
| `guide` | 内置使用指南:当前版本能做什么、哪些取值格式容易写错(`hap guide <主题>` 看细节) |
|
|
259
|
+
|
|
246
260
|
### upload — 文件上传
|
|
247
261
|
|
|
248
262
|
| 命令 | 说明 |
|
|
249
263
|
|---|---|
|
|
250
|
-
| `upload [SOURCES...]` | 上传本地路径或 http(s) 直链到文件存储,返回中性的「已上传文件描述符」(fileID/key/url/serverName/filePath/fileName/fileExt/originalFileName/fileSize) |
|
|
264
|
+
| `upload [SOURCES...]` | 上传本地路径或 http(s) 直链到文件存储,返回中性的「已上传文件描述符」(fileID/key/url/urlExpiresAt/serverName/filePath/fileName/fileExt/originalFileName/fileSize) |
|
|
251
265
|
|
|
252
|
-
>
|
|
266
|
+
> 跨功能的通用能力——同一份描述符可用于工作表附件字段、动态、日程、评论等。返回的 `url` 只是给你自己临时取用的地址,到 `urlExpiresAt` 就失效,不要发给别人;要把文件给别人,请用对应的附件入口,例如 `hap chat send-to-one --file <路径>`。用 `--files '[{"name":"封面.png","url":"https://..."}]'` 指定显示名;`--worksheet-id` / `--app-id` 优化上传 token 路由。
|
|
253
267
|
|
|
254
268
|
### config — 本地 CLI 配置
|
|
255
269
|
|
|
@@ -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']}")
|
|
@@ -30,7 +30,11 @@ SERVER_HELP = (
|
|
|
30
30
|
)
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
@click.group(help=t(
|
|
33
|
+
@click.group(help=t(
|
|
34
|
+
'Manage authentication and session identity.\n\n'
|
|
35
|
+
'Signing in, keeping several environments and accounts, and choosing the '
|
|
36
|
+
'current organization are walked through in `hap guide setup`.'
|
|
37
|
+
))
|
|
34
38
|
def auth():
|
|
35
39
|
pass
|
|
36
40
|
|
|
@@ -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
|
|
|
@@ -72,7 +73,11 @@ def _output_chat_list_table(rows):
|
|
|
72
73
|
)
|
|
73
74
|
|
|
74
75
|
|
|
75
|
-
@click.group(help=t(
|
|
76
|
+
@click.group(help=t(
|
|
77
|
+
'Chat and messaging management.\n\n'
|
|
78
|
+
'To follow a notification back to the app record it belongs to, see '
|
|
79
|
+
'`hap guide messages`.'
|
|
80
|
+
))
|
|
76
81
|
def chat():
|
|
77
82
|
pass
|
|
78
83
|
|
|
@@ -251,19 +256,64 @@ def chat_messages(
|
|
|
251
256
|
|
|
252
257
|
@chat.command("send-to-one")
|
|
253
258
|
@click.option("--to", "-t", multiple=True, help="Target user account ID (can repeat)")
|
|
254
|
-
@click.option("--message", "-m",
|
|
259
|
+
@click.option("--message", "-m", default="", help="Message text")
|
|
260
|
+
@click.option(
|
|
261
|
+
"--file", "-f", "files", multiple=True,
|
|
262
|
+
help="Attach a file: a local path or an http(s) address. Repeat for "
|
|
263
|
+
"several. The file arrives as an attachment the recipient can "
|
|
264
|
+
"open at any time, not as a link that stops working.",
|
|
265
|
+
)
|
|
266
|
+
@click.option(
|
|
267
|
+
"--dry-run", is_flag=True, default=False,
|
|
268
|
+
help="Show what would be sent, without uploading or sending anything.",
|
|
269
|
+
)
|
|
255
270
|
@pass_context
|
|
256
|
-
def chat_send_to_one(ctx, to, message):
|
|
257
|
-
"""Send a
|
|
271
|
+
def chat_send_to_one(ctx, to, message, files, dry_run):
|
|
272
|
+
"""Send a message, optionally with files, to one or more users (1-on-1).
|
|
273
|
+
|
|
274
|
+
\b
|
|
275
|
+
hap chat send-to-one -t <accountId> -m "spec attached" -f ./spec.pdf
|
|
276
|
+
|
|
277
|
+
Text and each file arrive as separate messages, in that order. You
|
|
278
|
+
cannot message yourself — your own account is skipped.
|
|
279
|
+
"""
|
|
258
280
|
if not to:
|
|
259
281
|
ctx.handle_error(click.UsageError(
|
|
260
282
|
"Provide at least one --to <accountId>."
|
|
261
283
|
))
|
|
262
284
|
return
|
|
285
|
+
if not message and not files:
|
|
286
|
+
ctx.handle_error(click.UsageError(
|
|
287
|
+
"Provide --message, --file, or both."
|
|
288
|
+
))
|
|
289
|
+
return
|
|
290
|
+
sources = upload_mod.source_descriptors(list(files))
|
|
291
|
+
if dry_run:
|
|
292
|
+
ctx.output(
|
|
293
|
+
{"to": list(to), "message": message, "files": list(files),
|
|
294
|
+
"sent": False},
|
|
295
|
+
lambda d: click.echo(
|
|
296
|
+
"Dry run — nothing sent."
|
|
297
|
+
+ f"\n To: {', '.join(to)}"
|
|
298
|
+
+ (f"\n Message: {message}" if message else "")
|
|
299
|
+
+ "".join(f"\n File: {f}" for f in files)
|
|
300
|
+
),
|
|
301
|
+
)
|
|
302
|
+
return
|
|
263
303
|
try:
|
|
264
304
|
session = ctx.get_session()
|
|
265
|
-
|
|
266
|
-
|
|
305
|
+
if not sources:
|
|
306
|
+
data = chat_mod.send_message(session, list(to), message)
|
|
307
|
+
ctx.output(data, lambda d: click.echo("Message sent."))
|
|
308
|
+
return
|
|
309
|
+
descriptors = chat_mod.upload_chat_files(session, sources)
|
|
310
|
+
acks = chat_mod.send_files(session, list(to), descriptors, message)
|
|
311
|
+
ctx.output(
|
|
312
|
+
{"sent": len(acks), "files": len(descriptors), "acks": acks},
|
|
313
|
+
lambda d: click.echo(
|
|
314
|
+
f"Sent {len(descriptors)} file(s) to {len(to)} recipient(s)."
|
|
315
|
+
),
|
|
316
|
+
)
|
|
267
317
|
except Exception as e:
|
|
268
318
|
ctx.handle_error(e)
|
|
269
319
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""CLI command for the built-in usage guide."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from hap_cli.context import pass_context
|
|
6
|
+
from hap_cli.core import guide as guide_mod
|
|
7
|
+
from hap_cli.i18n import t
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@click.command("guide")
|
|
11
|
+
@click.argument("topic", required=False)
|
|
12
|
+
@pass_context
|
|
13
|
+
def guide(ctx, topic):
|
|
14
|
+
"""How to use this tool: what it can do, and how to get the values right.
|
|
15
|
+
|
|
16
|
+
\b
|
|
17
|
+
hap guide what hap can do, and which topics go deeper
|
|
18
|
+
hap guide record writing records: what value each field type wants
|
|
19
|
+
|
|
20
|
+
Run this before composing commands — it describes the version of hap
|
|
21
|
+
installed on this machine, so it never disagrees with what you get.
|
|
22
|
+
"""
|
|
23
|
+
try:
|
|
24
|
+
from hap_cli.hap_cli import cli as root
|
|
25
|
+
|
|
26
|
+
if topic:
|
|
27
|
+
body = guide_mod.render_topic(topic)
|
|
28
|
+
ctx.output({"topic": topic, "text": body},
|
|
29
|
+
lambda d: click.echo(d["text"]))
|
|
30
|
+
return
|
|
31
|
+
payload = guide_mod.overview_payload(root)
|
|
32
|
+
ctx.output(payload, lambda d: click.echo(d["text"]))
|
|
33
|
+
except guide_mod.UnknownTopic as e:
|
|
34
|
+
ctx.handle_error(e)
|
|
35
|
+
except Exception as e:
|
|
36
|
+
ctx.handle_error(e)
|
|
@@ -90,6 +90,10 @@ def record_create(ctx, worksheet_id, field, fields_json, no_workflow):
|
|
|
90
90
|
|
|
91
91
|
Pass values either as repeated -f CONTROL_ID=VALUE pairs or as one
|
|
92
92
|
--fields-json array.
|
|
93
|
+
|
|
94
|
+
What to put in a value depends on the field type, and a wrong shape is
|
|
95
|
+
usually accepted and stored broken rather than rejected — see
|
|
96
|
+
`hap guide record` before writing, and read the record back after.
|
|
93
97
|
"""
|
|
94
98
|
if field and fields_json:
|
|
95
99
|
raise click.UsageError("Pass exactly one of -f or --fields-json.")
|
|
@@ -162,6 +166,10 @@ def record_update(ctx, worksheet_id, row_id, field, fields_json, no_workflow):
|
|
|
162
166
|
fields change), a child row without a "rowid" adds a new row, and a
|
|
163
167
|
child row with "_delete": true removes that row. Rows you don't list
|
|
164
168
|
are left untouched. An empty list (or null) clears the sub-table.
|
|
169
|
+
|
|
170
|
+
Every other field type replaces rather than merges: passing a new value
|
|
171
|
+
for a multi-select, attachment or relation field drops whatever was
|
|
172
|
+
there. Value formats per field type are in `hap guide record`.
|
|
165
173
|
"""
|
|
166
174
|
if field and fields_json:
|
|
167
175
|
raise click.UsageError("Pass exactly one of -f or --fields-json.")
|
|
@@ -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(
|
|
@@ -11,7 +11,12 @@ from hap_cli.utils.options import org_id_option, require_api_project_id
|
|
|
11
11
|
from hap_cli.i18n import t
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
@click.group(help=t(
|
|
14
|
+
@click.group(help=t(
|
|
15
|
+
'Worksheet operations.\n\n'
|
|
16
|
+
'Writing records: the value each field type expects (options, members, '
|
|
17
|
+
'relations, sub-tables, attachments) is covered by `hap guide record` — '
|
|
18
|
+
'a wrong shape is usually accepted and stored broken.'
|
|
19
|
+
))
|
|
15
20
|
def worksheet():
|
|
16
21
|
pass
|
|
17
22
|
|
|
@@ -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
|
+
}
|