hap-cli 0.8.22__tar.gz → 0.8.24__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.22 → hap_cli-0.8.24}/MANIFEST.in +2 -5
- {hap_cli-0.8.22 → hap_cli-0.8.24}/PKG-INFO +7 -1
- {hap_cli-0.8.22/hap_cli → hap_cli-0.8.24}/README.md +6 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24/hap_cli}/README.md +6 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/README_CN.md +6 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/__init__.py +1 -1
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/auth_cmd.py +5 -1
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/chat_cmd.py +5 -1
- hap_cli-0.8.24/hap_cli/commands/guide_cmd.py +36 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/record_cmd.py +23 -6
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/worksheet_cmd.py +6 -1
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/editor/editspec.py +15 -20
- hap_cli-0.8.24/hap_cli/core/guide.py +176 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/record.py +103 -23
- hap_cli-0.8.24/hap_cli/guide/en/messages.md +54 -0
- hap_cli-0.8.24/hap_cli/guide/en/overview.md +46 -0
- hap_cli-0.8.24/hap_cli/guide/en/record.md +455 -0
- hap_cli-0.8.24/hap_cli/guide/en/setup.md +99 -0
- hap_cli-0.8.24/hap_cli/guide/en/skills.md +48 -0
- hap_cli-0.8.24/hap_cli/guide/index.json +36 -0
- hap_cli-0.8.24/hap_cli/guide/zh-Hans/messages.md +52 -0
- hap_cli-0.8.24/hap_cli/guide/zh-Hans/overview.md +39 -0
- hap_cli-0.8.24/hap_cli/guide/zh-Hans/record.md +430 -0
- hap_cli-0.8.24/hap_cli/guide/zh-Hans/setup.md +91 -0
- hap_cli-0.8.24/hap_cli/guide/zh-Hans/skills.md +45 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/hap_cli.py +8 -1
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_app_editor.py +35 -0
- hap_cli-0.8.24/hap_cli/tests/test_guide.py +173 -0
- hap_cli-0.8.24/hap_cli/tests/test_record_write_fixes.py +122 -0
- hap_cli-0.8.24/hap_cli/tests/test_select_add_option.py +78 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_select_rejects_relation_value.py +10 -6
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli.egg-info/PKG-INFO +7 -1
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli.egg-info/SOURCES.txt +20 -4
- {hap_cli-0.8.22 → hap_cli-0.8.24}/setup.py +7 -15
- {hap_cli-0.8.22 → hap_cli-0.8.24}/app_live_tests/__init__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/app_live_tests/__main__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/app_live_tests/config.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/app_live_tests/harness.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/app_live_tests/smoke.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/app_live_tests/state.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/__main__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/__init__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/app_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/app_creator_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/app_editor_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/attachment_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/calendar_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/chart_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/chatbot_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/config_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/contact_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/department_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/group_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/icon_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/instance_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/node_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/optionset_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/page_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/post_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/region_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/role_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/update_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/upload_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/v3_registry.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/commands/workflow_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/context.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/__init__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/action_spec_adapter.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/__init__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/_hapmeta/__init__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/_hapmeta/worksheet_templates.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/charts.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/cleanup.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/compiler.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/config.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/design/design.schema.json +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/errors.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/examples/minimal.design.json +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/executor.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/fields.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/hap.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/merge.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/recording/__init__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/recording/console.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/recording/jsonl.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/recording/mirror.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/recording/report.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/schema.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/seed/INSTRUCTIONS.md +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/seed/__init__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/seed/cli.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/seed/executor.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/seed/resources/attachments.json +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/seed/resources/sample.docx +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/seed/resources/sample.pdf +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/seed/resources/sample_images.json +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/seed/template.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/selftest.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/smoke.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/steps.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/store.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/validate.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/app_creator/workflow_dsl.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/attachment.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/auth.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/calendar_mod.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/chart.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/chat.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/chatbot.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/cli_access.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/contact.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/control_type_codes.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/department.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/editor/__init__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/editor/_hapmeta/__init__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/editor/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/editor/apply.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/editor/componentlower.py +0 -0
- {hap_cli-0.8.22/skills/cli/hap-cli-app-editor/scripts → hap_cli-0.8.24/hap_cli/core/editor}/editspec/component.schema.json +0 -0
- {hap_cli-0.8.22/skills/cli/hap-cli-app-editor/scripts → hap_cli-0.8.24/hap_cli/core/editor}/editspec/custom-action.schema.json +0 -0
- {hap_cli-0.8.22/skills/cli/hap-cli-app-editor/scripts → hap_cli-0.8.24/hap_cli/core/editor}/editspec/envelope.schema.json +0 -0
- {hap_cli-0.8.22/skills/cli/hap-cli-app-editor/scripts → hap_cli-0.8.24/hap_cli/core/editor}/editspec/field.schema.json +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/editor/errors.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/editor/fieldlower.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/editor/jsonschema_mini.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/editor/models.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/editor/ops.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/editor/planner.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/editor/reader.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/field_normalizer.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/field_spec_adapter.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/filter_translator.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/flow_node.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/global_meta.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/group.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/icon_index.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/instance.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/logger.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/optionset.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/page.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/post.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/response_crypto.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/role.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/role_perm_builder.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/session.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/token_crypto.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/update.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/upload.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/v3/__init__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/v3/dispatcher.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/v3/render.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/v3/schema.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/view_spec_adapter.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/workflow.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/workflow_node_dsl.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/worksheet.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/core/worksheet_templates.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/i18n.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/locale/__init__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/locale/messages.json +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/locale/messages.schema.json +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/__init__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/conftest.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_app_creator.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_app_export_usage.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_attachment_share.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_auth_prerelease.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_bug_036430.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_bug_036750.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_chart.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_chat_attachment_send.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_cli_access.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_config_cmd.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_content_language.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_control_lookup_guard.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_core.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_destructive_confirm_cli.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_full_e2e.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_global_meta.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_i18n.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_instance_history_cli.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_integration.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_integration_approval.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_integration_approval_actions.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_integration_calendar.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_integration_destructive.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_integration_misc.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_integration_post.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_integration_social.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_integration_v3.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_integration_workflow.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_integration_worksheet_extra.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_member_relation_array_wrap.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_multi_profile.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_no_workflow_unsupported.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_org_approval_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_org_id_cli.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_org_id_docs.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_parameter_conventions.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_parameter_mapping_registry.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_record_batch_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_record_field_alias.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_record_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_semantic_types_registry.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_update.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_update_mode.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_upload_host_resolution.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_v3_api_schema_loader.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_v3_dispatcher.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_v3_registry_coverage.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_v3_session.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_v3_yaml_translation.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_workflow_envelope_errors.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_workflow_list_cli.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_workflow_read_write_keys.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_workflow_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_worksheet_create_section.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_worksheet_crud_cli.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/tests/test_worksheet_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/utils/__init__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/utils/formatting.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/utils/options.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli/utils/parameter_mapping.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli.egg-info/dependency_links.txt +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli.egg-info/entry_points.txt +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli.egg-info/requires.txt +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/hap_cli.egg-info/top_level.txt +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/__init__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/__main__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/_wftest.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/charts.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/cleanup.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/compiler.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/config.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/errors.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/executor.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/fields.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/hap.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/recording/__init__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/recording/console.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/recording/jsonl.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/recording/mirror.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/recording/report.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/schema.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/seed/__init__.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/seed/cli.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/seed/executor.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/seed/template.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/selftest.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/smoke.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/step.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/steps.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/store.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/live_tests/workflow_dsl.py +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/setup.cfg +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/INDEX.json +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/add_member_to_role.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/batch_delete_records.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/create_optionset.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/create_role.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/delete_optionset.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/delete_record.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/delete_role.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/delete_worksheet.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/get_app_info.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/get_app_knowledge_list.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/get_app_worksheets_list.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/get_optionset_list.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/get_record_details.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/get_record_discussions.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/get_record_list.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/get_record_logs.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/get_record_pivot_data.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/get_record_relations.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/get_record_share_link.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/get_regions.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/get_role_details.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/get_role_list.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/knowledge_search.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/leave_all_roles.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/sources/v3-api-schema/remove_member_from_role.yaml +0 -0
- {hap_cli-0.8.22 → hap_cli-0.8.24}/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.24
|
|
4
4
|
Summary: CLI harness for Mingdao HAP - Enterprise no-code platform
|
|
5
5
|
Author: hap-cli
|
|
6
6
|
License: Apache-2.0
|
|
@@ -306,6 +306,12 @@ discover every subcommand.
|
|
|
306
306
|
|
|
307
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
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
|
+
|
|
309
315
|
### upload — file upload
|
|
310
316
|
|
|
311
317
|
| Command | Description |
|
|
@@ -277,6 +277,12 @@ discover every subcommand.
|
|
|
277
277
|
|
|
278
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
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
|
+
|
|
280
286
|
### upload — file upload
|
|
281
287
|
|
|
282
288
|
| Command | Description |
|
|
@@ -277,6 +277,12 @@ discover every subcommand.
|
|
|
277
277
|
|
|
278
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
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
|
+
|
|
280
286
|
### upload — file upload
|
|
281
287
|
|
|
282
288
|
| Command | Description |
|
|
@@ -251,6 +251,12 @@ hap --json worksheet record list WORKSHEET_ID
|
|
|
251
251
|
|
|
252
252
|
> ADDRESS 传文件的链接即可——**已经失效的链接照样能传,原样粘贴**——也可以只传路径部分。文件本身不会过期,过期的只是链接,所以失效链接随时可以重新生成。
|
|
253
253
|
|
|
254
|
+
### guide — 内置使用指南
|
|
255
|
+
|
|
256
|
+
| 命令 | 说明 |
|
|
257
|
+
|---|---|
|
|
258
|
+
| `guide` | 内置使用指南:当前版本能做什么、哪些取值格式容易写错(`hap guide <主题>` 看细节) |
|
|
259
|
+
|
|
254
260
|
### upload — 文件上传
|
|
255
261
|
|
|
256
262
|
| 命令 | 说明 |
|
|
@@ -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
|
|
|
@@ -73,7 +73,11 @@ def _output_chat_list_table(rows):
|
|
|
73
73
|
)
|
|
74
74
|
|
|
75
75
|
|
|
76
|
-
@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
|
+
))
|
|
77
81
|
def chat():
|
|
78
82
|
pass
|
|
79
83
|
|
|
@@ -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)
|
|
@@ -84,12 +84,20 @@ def record_get(ctx, worksheet_id, row_id, view_id):
|
|
|
84
84
|
"list of option names or keys; member/relation fields a "
|
|
85
85
|
"list of ids). Use either this or -f, not both.")
|
|
86
86
|
@click.option("--no-workflow", is_flag=True, help="Don't trigger workflows")
|
|
87
|
+
@click.option(
|
|
88
|
+
"--app-id", "-a", default="",
|
|
89
|
+
help="Application ID. Optional — the worksheet id is enough on its own; this only scopes the field lookup.",
|
|
90
|
+
)
|
|
87
91
|
@pass_context
|
|
88
|
-
def record_create(ctx, worksheet_id, field, fields_json, no_workflow):
|
|
92
|
+
def record_create(ctx, worksheet_id, field, fields_json, no_workflow, app_id):
|
|
89
93
|
"""Create a new record.
|
|
90
94
|
|
|
91
95
|
Pass values either as repeated -f CONTROL_ID=VALUE pairs or as one
|
|
92
96
|
--fields-json array.
|
|
97
|
+
|
|
98
|
+
What to put in a value depends on the field type, and a wrong shape is
|
|
99
|
+
usually accepted and stored broken rather than rejected — see
|
|
100
|
+
`hap guide record` before writing, and read the record back after.
|
|
93
101
|
"""
|
|
94
102
|
if field and fields_json:
|
|
95
103
|
raise click.UsageError("Pass exactly one of -f or --fields-json.")
|
|
@@ -108,10 +116,11 @@ def record_create(ctx, worksheet_id, field, fields_json, no_workflow):
|
|
|
108
116
|
raise click.UsageError(str(exc))
|
|
109
117
|
else:
|
|
110
118
|
raw = _parse_fields(field)
|
|
111
|
-
controls = rec_mod.encode_controls_by_id(
|
|
119
|
+
controls = rec_mod.encode_controls_by_id(
|
|
120
|
+
session, worksheet_id, raw, app_id=app_id)
|
|
112
121
|
data = rec_mod.create_record(
|
|
113
122
|
session, worksheet_id, controls,
|
|
114
|
-
trigger_workflow=not no_workflow,
|
|
123
|
+
trigger_workflow=not no_workflow, app_id=app_id,
|
|
115
124
|
)
|
|
116
125
|
ctx.output(data, lambda d: click.echo(f"Created: {d}"))
|
|
117
126
|
except Exception as e:
|
|
@@ -149,8 +158,12 @@ def _fields_json_to_raw(fields_json):
|
|
|
149
158
|
"list of option names or keys; member/relation fields a "
|
|
150
159
|
"list of ids). Use either this or -f, not both.")
|
|
151
160
|
@click.option("--no-workflow", is_flag=True, help="Don't trigger workflows")
|
|
161
|
+
@click.option(
|
|
162
|
+
"--app-id", "-a", default="",
|
|
163
|
+
help="Application ID. Optional — the worksheet id is enough on its own; this only scopes the field lookup.",
|
|
164
|
+
)
|
|
152
165
|
@pass_context
|
|
153
|
-
def record_update(ctx, worksheet_id, row_id, field, fields_json, no_workflow):
|
|
166
|
+
def record_update(ctx, worksheet_id, row_id, field, fields_json, no_workflow, app_id):
|
|
154
167
|
"""Update a record.
|
|
155
168
|
|
|
156
169
|
Pass values either as repeated -f CONTROL_ID=VALUE pairs or as one
|
|
@@ -162,6 +175,10 @@ def record_update(ctx, worksheet_id, row_id, field, fields_json, no_workflow):
|
|
|
162
175
|
fields change), a child row without a "rowid" adds a new row, and a
|
|
163
176
|
child row with "_delete": true removes that row. Rows you don't list
|
|
164
177
|
are left untouched. An empty list (or null) clears the sub-table.
|
|
178
|
+
|
|
179
|
+
Every other field type replaces rather than merges: passing a new value
|
|
180
|
+
for a multi-select, attachment or relation field drops whatever was
|
|
181
|
+
there. Value formats per field type are in `hap guide record`.
|
|
165
182
|
"""
|
|
166
183
|
if field and fields_json:
|
|
167
184
|
raise click.UsageError("Pass exactly one of -f or --fields-json.")
|
|
@@ -172,10 +189,10 @@ def record_update(ctx, worksheet_id, row_id, field, fields_json, no_workflow):
|
|
|
172
189
|
else:
|
|
173
190
|
raw = _parse_fields(field)
|
|
174
191
|
controls = rec_mod.encode_controls_by_id(
|
|
175
|
-
session, worksheet_id, raw, for_update=True)
|
|
192
|
+
session, worksheet_id, raw, for_update=True, app_id=app_id)
|
|
176
193
|
data = rec_mod.update_record(
|
|
177
194
|
session, worksheet_id, row_id, controls,
|
|
178
|
-
trigger_workflow=not no_workflow,
|
|
195
|
+
trigger_workflow=not no_workflow, app_id=app_id,
|
|
179
196
|
)
|
|
180
197
|
ctx.output(data, lambda d: click.echo(f"Updated: {d}"))
|
|
181
198
|
except Exception as e:
|
|
@@ -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
|
|
|
@@ -6,11 +6,10 @@ only the one module schema named by the op.type prefix is loaded and used
|
|
|
6
6
|
for deep validation (dispatched to the matching verb branch for precise
|
|
7
7
|
errors).
|
|
8
8
|
|
|
9
|
-
Schemas are canonical in
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
the same trick used for the V3 schemas).
|
|
9
|
+
Schemas are canonical in this package (``hap_cli/core/editor/editspec/``)
|
|
10
|
+
and ship with it, so they resolve identically in a checkout and in an
|
|
11
|
+
installed wheel — see :func:`schema_dir` for why they no longer live in
|
|
12
|
+
the hap-cli-app-editor skill.
|
|
14
13
|
"""
|
|
15
14
|
from __future__ import annotations
|
|
16
15
|
|
|
@@ -74,30 +73,26 @@ RETIRED_OPS = {
|
|
|
74
73
|
"section.delete": "hap app delete-section",
|
|
75
74
|
}
|
|
76
75
|
|
|
77
|
-
_SKILL_REL = ("skills", "cli", "hap-cli-app-editor", "scripts", "editspec")
|
|
78
|
-
|
|
79
|
-
|
|
80
76
|
@lru_cache(maxsize=1)
|
|
81
77
|
def schema_dir() -> Path:
|
|
82
78
|
"""Locate the edit-spec schema directory.
|
|
83
79
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
80
|
+
The schemas live next to this module and are tracked with the package,
|
|
81
|
+
so this resolves identically in a checkout and in an installed wheel.
|
|
82
|
+
|
|
83
|
+
They used to be canonical in the hap-cli-app-editor skill, mirrored in
|
|
84
|
+
at build time by setup.py. That broke when the skills moved to their
|
|
85
|
+
own repository and were linked back in: the build step found nothing
|
|
86
|
+
on a machine without that checkout, skipped silently, and shipped a
|
|
87
|
+
wheel whose ``hap app-editor`` could not load a single schema. A build
|
|
88
|
+
input has to be inside the repository that builds it.
|
|
89
89
|
"""
|
|
90
90
|
bundled = Path(__file__).resolve().parent / "editspec"
|
|
91
91
|
if bundled.is_dir() and any(bundled.glob("*.schema.json")):
|
|
92
92
|
return bundled
|
|
93
|
-
here = Path(__file__).resolve()
|
|
94
|
-
for parent in here.parents:
|
|
95
|
-
cand = parent.joinpath(*_SKILL_REL)
|
|
96
|
-
if cand.is_dir():
|
|
97
|
-
return cand
|
|
98
93
|
raise EditSpecError([
|
|
99
|
-
"could not locate edit-spec schemas
|
|
100
|
-
"
|
|
94
|
+
"could not locate the edit-spec schemas that ship with this "
|
|
95
|
+
"package (hap_cli/core/editor/editspec/)"])
|
|
101
96
|
|
|
102
97
|
|
|
103
98
|
def _load_schema(filename: str) -> dict[str, Any]:
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"""Usage guidance that ships with — and updates with — the CLI.
|
|
2
|
+
|
|
3
|
+
The hap-cli skill used to carry the command map as a static file on the
|
|
4
|
+
user's machine, frozen at install time. Guidance lives here instead, for
|
|
5
|
+
one reason: this package auto-updates, so whatever it says matches the
|
|
6
|
+
`hap` the caller is actually running. The skill shrinks to a stub that
|
|
7
|
+
says "run `hap guide`".
|
|
8
|
+
|
|
9
|
+
Two halves:
|
|
10
|
+
|
|
11
|
+
- **Generated** — the command map is walked off the live Click tree
|
|
12
|
+
(``command_map``). It cannot name a command that does not exist, and
|
|
13
|
+
it cannot omit one that does. Nothing about it is written down.
|
|
14
|
+
- **Written** — prose that the tree cannot express (how to log in, what
|
|
15
|
+
value shape each field type wants, which specialised skill to hand off
|
|
16
|
+
to) lives in ``hap_cli/guide/<lang>/<topic>.md``, declared in
|
|
17
|
+
``index.json``.
|
|
18
|
+
|
|
19
|
+
The bare overview enumerates its own topics so the skill stub never has
|
|
20
|
+
to name them; naming them there is exactly the detail that goes stale.
|
|
21
|
+
"""
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import json
|
|
25
|
+
import textwrap
|
|
26
|
+
from functools import lru_cache
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
from typing import Any, Optional
|
|
29
|
+
|
|
30
|
+
import click
|
|
31
|
+
|
|
32
|
+
GUIDE_DIR = Path(__file__).resolve().parent.parent / "guide"
|
|
33
|
+
BASE_LANG = "en"
|
|
34
|
+
|
|
35
|
+
# Two spaces of hanging indent under each group name, wide enough for the
|
|
36
|
+
# longest top-level group without the help column drifting.
|
|
37
|
+
_NAME_COL = 14
|
|
38
|
+
|
|
39
|
+
# Wrap the subcommand row so a wide group (worksheet has 27) stays
|
|
40
|
+
# readable in a normal terminal instead of running off the edge.
|
|
41
|
+
_WRAP_COL = 88
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class UnknownTopic(Exception):
|
|
45
|
+
"""Raised for a topic name the guide does not ship."""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@lru_cache(maxsize=1)
|
|
49
|
+
def _index() -> list[dict[str, Any]]:
|
|
50
|
+
with open(GUIDE_DIR / "index.json", encoding="utf-8") as fh:
|
|
51
|
+
return json.load(fh)["topics"]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _resolve_lang(lang: Optional[str]) -> str:
|
|
55
|
+
if lang is None:
|
|
56
|
+
from hap_cli.i18n import get_active_language
|
|
57
|
+
|
|
58
|
+
lang = get_active_language()
|
|
59
|
+
return lang
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _pick(entry: dict[str, Any], lang: str) -> str:
|
|
63
|
+
"""Localized string with the English base as fallback."""
|
|
64
|
+
return entry.get(lang) or entry[BASE_LANG]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def available_topics(lang: Optional[str] = None) -> list[dict[str, str]]:
|
|
68
|
+
"""Declared topics in display order: ``{name, title, summary}``."""
|
|
69
|
+
lang = _resolve_lang(lang)
|
|
70
|
+
return [
|
|
71
|
+
{
|
|
72
|
+
"name": t["name"],
|
|
73
|
+
"title": _pick(t["title"], lang),
|
|
74
|
+
"summary": _pick(t["summary"], lang),
|
|
75
|
+
}
|
|
76
|
+
for t in _index()
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def render_topic(name: str, lang: Optional[str] = None) -> str:
|
|
81
|
+
"""Body of one topic, falling back to English when the active
|
|
82
|
+
language has no copy of it."""
|
|
83
|
+
known = [t["name"] for t in _index()]
|
|
84
|
+
if name not in known:
|
|
85
|
+
raise UnknownTopic(
|
|
86
|
+
f"No guide topic named '{name}'. Available topics: "
|
|
87
|
+
+ ", ".join(known)
|
|
88
|
+
)
|
|
89
|
+
lang = _resolve_lang(lang)
|
|
90
|
+
for candidate in (lang, BASE_LANG):
|
|
91
|
+
path = GUIDE_DIR / candidate / f"{name}.md"
|
|
92
|
+
if path.exists():
|
|
93
|
+
return path.read_text(encoding="utf-8").strip()
|
|
94
|
+
raise UnknownTopic(f"Guide topic '{name}' has no content installed.")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def command_map(root: click.Group) -> str:
|
|
98
|
+
"""Render the live command tree: every group, and the commands under it.
|
|
99
|
+
|
|
100
|
+
Generated rather than written so it always describes the installed
|
|
101
|
+
version. Hidden commands are omitted — they are not part of the
|
|
102
|
+
surface a caller should be pointed at.
|
|
103
|
+
"""
|
|
104
|
+
lines: list[str] = []
|
|
105
|
+
for name, cmd in sorted(root.commands.items()):
|
|
106
|
+
if cmd.hidden:
|
|
107
|
+
continue
|
|
108
|
+
summary = (cmd.get_short_help_str(limit=60) or "").strip()
|
|
109
|
+
lines.append(f" {name:<{_NAME_COL}}{summary}")
|
|
110
|
+
children = _child_names(cmd)
|
|
111
|
+
if children:
|
|
112
|
+
indent = " " * (2 + _NAME_COL)
|
|
113
|
+
lines.extend(textwrap.wrap(
|
|
114
|
+
" ".join(children), width=_WRAP_COL,
|
|
115
|
+
initial_indent=indent, subsequent_indent=indent,
|
|
116
|
+
break_long_words=False, break_on_hyphens=False,
|
|
117
|
+
))
|
|
118
|
+
return "\n".join(lines)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _child_names(cmd: click.Command) -> list[str]:
|
|
122
|
+
"""Direct subcommand names of a group, one nesting level only.
|
|
123
|
+
|
|
124
|
+
Deeper levels (``worksheet record create``) are reachable through
|
|
125
|
+
``--help`` and would drown the map; the point here is to show that
|
|
126
|
+
the capability exists, not to restate every signature.
|
|
127
|
+
"""
|
|
128
|
+
if not isinstance(cmd, click.Group):
|
|
129
|
+
return []
|
|
130
|
+
return sorted(n for n, c in cmd.commands.items() if not c.hidden)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _topic_lines(lang: str) -> str:
|
|
134
|
+
rows = available_topics(lang)
|
|
135
|
+
width = max(len(t["name"]) for t in rows) + len("hap guide ") + 2
|
|
136
|
+
return "\n".join(
|
|
137
|
+
f" {('hap guide ' + t['name']):<{width}}{t['summary']}" for t in rows
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def render_overview(root: click.Group, lang: Optional[str] = None) -> str:
|
|
142
|
+
"""The bare ``hap guide``: how to work, what exists, where to go next."""
|
|
143
|
+
lang = _resolve_lang(lang)
|
|
144
|
+
for candidate in (lang, BASE_LANG):
|
|
145
|
+
path = GUIDE_DIR / candidate / "overview.md"
|
|
146
|
+
if path.exists():
|
|
147
|
+
template = path.read_text(encoding="utf-8")
|
|
148
|
+
break
|
|
149
|
+
else: # pragma: no cover - shipped content is validated by tests
|
|
150
|
+
raise UnknownTopic("The guide overview has no content installed.")
|
|
151
|
+
from hap_cli import __version__
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
template.replace("{version}", __version__)
|
|
155
|
+
.replace("{command_map}", command_map(root))
|
|
156
|
+
.replace("{topics}", _topic_lines(lang))
|
|
157
|
+
.strip()
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def overview_payload(root: click.Group, lang: Optional[str] = None) -> dict[str, Any]:
|
|
162
|
+
"""Machine-readable form of the overview for ``--json`` callers."""
|
|
163
|
+
lang = _resolve_lang(lang)
|
|
164
|
+
return {
|
|
165
|
+
"text": render_overview(root, lang),
|
|
166
|
+
"topics": available_topics(lang),
|
|
167
|
+
"commands": [
|
|
168
|
+
{
|
|
169
|
+
"name": name,
|
|
170
|
+
"summary": (cmd.get_short_help_str(limit=60) or "").strip(),
|
|
171
|
+
"subcommands": _child_names(cmd),
|
|
172
|
+
}
|
|
173
|
+
for name, cmd in sorted(root.commands.items())
|
|
174
|
+
if not cmd.hidden
|
|
175
|
+
],
|
|
176
|
+
}
|