minitest-cli 0.40.0__tar.gz → 0.41.0__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.
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/.env.example +1 -1
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/PKG-INFO +80 -6
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/README.md +78 -5
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/pyproject.toml +2 -1
- minitest_cli-0.41.0/src/minitest_cli/commands/glossary.py +140 -0
- minitest_cli-0.41.0/src/minitest_cli/commands/knowledge.py +105 -0
- minitest_cli-0.41.0/src/minitest_cli/commands/knowledge_documents.py +86 -0
- minitest_cli-0.41.0/src/minitest_cli/commands/knowledge_helpers.py +97 -0
- minitest_cli-0.41.0/src/minitest_cli/commands/schedules.py +156 -0
- minitest_cli-0.41.0/src/minitest_cli/commands/schedules_body.py +139 -0
- minitest_cli-0.41.0/src/minitest_cli/commands/schedules_create.py +145 -0
- minitest_cli-0.41.0/src/minitest_cli/commands/schedules_display.py +106 -0
- minitest_cli-0.41.0/src/minitest_cli/commands/schedules_helpers.py +83 -0
- minitest_cli-0.41.0/src/minitest_cli/commands/schedules_history.py +109 -0
- minitest_cli-0.41.0/src/minitest_cli/commands/schedules_options.py +195 -0
- minitest_cli-0.41.0/src/minitest_cli/commands/schedules_scope.py +60 -0
- minitest_cli-0.41.0/src/minitest_cli/commands/schedules_spec.py +113 -0
- minitest_cli-0.41.0/src/minitest_cli/commands/schedules_update.py +92 -0
- minitest_cli-0.41.0/src/minitest_cli/commands/schedules_where.py +127 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/secret.py +43 -50
- minitest_cli-0.41.0/src/minitest_cli/commands/secret_create.py +185 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/secret_helpers.py +4 -3
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/secret_lint.py +6 -1
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/secret_manage.py +2 -29
- minitest_cli-0.41.0/src/minitest_cli/commands/secret_state.py +42 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/test_profile_secret_refs.py +4 -1
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/core/config.py +2 -2
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/main.py +9 -0
- minitest_cli-0.41.0/tests/test_config_defaults.py +32 -0
- minitest_cli-0.41.0/tests/test_knowledge_v2_commands.py +289 -0
- minitest_cli-0.41.0/tests/test_schedules_commands.py +329 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_secret_commands.py +51 -32
- minitest_cli-0.41.0/tests/test_secret_create.py +181 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_secret_lint_extract.py +14 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/uv.lock +49 -1
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/.github/workflows/ci.yml +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/.github/workflows/install-scripts.yml +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/.github/workflows/release.yml +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/.gitignore +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/.opencode/skill/release/SKILL.md +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/AGENTS.md +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/RELEASE.md +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/install.ps1 +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/install.sh +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/pyrightconfig.json +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/renovate.json +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/__init__.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/api/__init__.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/api/apps_manager_client.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/api/client.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/api/errors.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/assets/__init__.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/assets/callback.html +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/__init__.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/_abi_mismatch.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/_response_errors.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/app_knowledge.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/app_knowledge_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/app_network_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/app_skill.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/app_skill_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/app_skill_secret.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/app_skill_write.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/apps.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/apps_dependencies.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/apps_get.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/apps_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/apps_table.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/auth.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/auth_api_key.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/batch.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/batch_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/batch_warnings.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/build.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/build_bundle.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/build_commit.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/build_conversion.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/build_fix_prompts.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/build_get.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/build_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/build_signing.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/capabilities.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/commit_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/deprecated_alias.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/draft.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/draft_asks.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/draft_conversation.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/draft_create.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/draft_feature.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/draft_feature_apply.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/draft_feature_conflicts.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/draft_feature_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/draft_feature_show.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/draft_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/draft_legacy.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/draft_lifecycle.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/draft_pr.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/draft_render.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/draft_update.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/draft_watch.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/env.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/env_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/flow_types.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/flow_types_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/flow_types_write.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/init.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/init_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/init_playbook.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/issues.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/issues_fix.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/issues_get.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/issues_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/issues_projection.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/issues_service.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/private_network.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/private_network_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/recording_timeline.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/residential_proxy.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/run.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/run_cancel.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/run_commit.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/run_commit_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/run_display.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/run_feedback.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/run_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/run_list.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/run_logs.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/run_recording.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/run_recording_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/run_tagged.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/run_targets.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/screens.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/screens_detail.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/screens_format.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/screens_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/screens_tree.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/secret_extract.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/secret_value.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/skill.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/tags.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/tags_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/test_file.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/test_file_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/test_file_list.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/test_profile.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/test_profile_card.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/test_profile_default.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/test_profile_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/test_profile_list.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/test_profile_update.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/upgrade.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/user_story.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/user_story_app_skills.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/user_story_bindings.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/user_story_camera.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/user_story_create.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/user_story_criteria.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/user_story_criterion_edits.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/user_story_delete.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/user_story_device_count.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/user_story_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/user_story_iap.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/user_story_modify.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/user_story_overrides.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/user_story_profiles.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/user_story_setup_commit.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/user_story_update.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/verdicts.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/verdicts_helpers.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/commands/verdicts_projection.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/core/__init__.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/core/app_context.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/core/auth.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/core/credentials.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/core/oauth.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/core/tenants.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/core/token_exchange.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/__init__.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/app.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/app_env_vars.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/app_failure.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/app_screen.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/base.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/batch.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/build.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/commit_build.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/draft_feature.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/flow_type.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/issues.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/lane_logs.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/recording.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/story_run.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/tag.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/targets.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/models/user_story.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/utils/__init__.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/utils/confirm.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/utils/dependency_sim.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/utils/mermaid.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/utils/output.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/utils/skill_refresh.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/utils/update_check.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/src/minitest_cli/utils/video_frames.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/__init__.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/_commit_transport.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/_network_settings_server.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/_secret_router.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/conftest.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/draft_backend.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_api_client_auth.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_app_context.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_app_knowledge_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_app_skill_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_apps_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_apps_dependencies.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_auth.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_auth_api_key.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_auth_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_batch_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_build_bundle.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_build_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_build_fix_prompts.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_build_get_command.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_capabilities_command.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_channel_header.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_code_quality.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_commit_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_deprecated_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_deprecated_flags.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_draft_ask_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_draft_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_draft_conversation_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_draft_feature_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_draft_pr_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_env.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_flow_types_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_init_command.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_issues.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_issues_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_issues_get_command.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_mermaid.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_native_device_types.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_network_errors.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_physical_devices.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_private_network_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_recording_timeline.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_residential_proxy_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_response_errors.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_run_cancel.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_run_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_run_frames_command.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_run_logs_command.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_screens_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_skill_command.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_suite_change_provenance.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_tags_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_test_file_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_test_profile_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_test_profile_secret_refs.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_upgrade_command.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_user_story_bindings_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_user_story_commands.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_user_story_in_app_purchases.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_user_story_setup_commit.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_verdicts.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_verdicts_actionable.py +0 -0
- {minitest_cli-0.40.0 → minitest_cli-0.41.0}/tests/test_version.py +0 -0
|
@@ -24,7 +24,7 @@ MINITEST_CONDUCTOR_URL=https://conductor.dev.minitap.ai
|
|
|
24
24
|
|
|
25
25
|
# —— Integrations ——
|
|
26
26
|
# Production
|
|
27
|
-
# MINITEST_INTEGRATIONS_URL=https://integrations.minitap.ai
|
|
27
|
+
# MINITEST_INTEGRATIONS_URL=https://integrations.app.minitap.ai
|
|
28
28
|
# Development
|
|
29
29
|
MINITEST_INTEGRATIONS_URL=https://integrations.dev.minitap.ai
|
|
30
30
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: minitest-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.41.0
|
|
4
4
|
Summary: Minitest CLI – command-line interface for the Minitest testing platform
|
|
5
5
|
Project-URL: Homepage, https://minitap.ai/
|
|
6
6
|
Project-URL: Source, https://github.com/minitap-ai/minitest-cli
|
|
@@ -23,6 +23,7 @@ Requires-Python: >=3.12
|
|
|
23
23
|
Requires-Dist: httpx>=0.28.1
|
|
24
24
|
Requires-Dist: pydantic-settings>=2.13.1
|
|
25
25
|
Requires-Dist: pydantic>=2.12.5
|
|
26
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
26
27
|
Requires-Dist: rich>=14.3.3
|
|
27
28
|
Requires-Dist: typer>=0.24.1
|
|
28
29
|
Provides-Extra: dev
|
|
@@ -214,12 +215,18 @@ app defaults.
|
|
|
214
215
|
| `minitest df` | Low-level suite branches Mini writes (draft features) |
|
|
215
216
|
| `minitest test-profile` | Test profiles (Test accounts in the webapp) |
|
|
216
217
|
| `minitest tags` | List, create, update and delete scenario tags |
|
|
218
|
+
| `minitest brief` | Product brief: what the app is, who uses it, its core flows (Knowledge v2) |
|
|
219
|
+
| `minitest app-guide` | App guide: how to use the app when testing it (Knowledge v2) |
|
|
220
|
+
| `minitest glossary` | Glossary: product terms, their meaning and aliases (Knowledge v2) |
|
|
221
|
+
| `minitest knowledge` | Change history of the brief, app guide and glossary, and reverts |
|
|
222
|
+
| `minitest app-knowledge` | The single Memory document of workspaces without Knowledge v2 |
|
|
217
223
|
| `minitest app-skill` | App skills (Skills in the webapp): procedures Mini loads to arrange test state |
|
|
218
224
|
| `minitest secret` | App secrets vault: passwords, OTP seeds, cards, API tokens referenced as `{{secret:NAME}}` (write-only values) |
|
|
219
225
|
| `minitest screens` | Inspect the screens exploration mapped for an app |
|
|
220
226
|
| `minitest build` | Native iOS/Android build management |
|
|
221
227
|
| `minitest run` | Start runs and inspect their scenario runs |
|
|
222
228
|
| `minitest batch` | List, inspect and cancel runs (a batch is a Run in the webapp) |
|
|
229
|
+
| `minitest schedules` | Scheduled runs: run scenarios at a set time and post a Slack summary |
|
|
223
230
|
| `minitest issues` | Read app issues and their fix prompts, mark them fixed |
|
|
224
231
|
| `minitest skill` | Print the CLI skill for your AI coding agent (not app skills) |
|
|
225
232
|
|
|
@@ -240,6 +247,65 @@ stderr and leave `--json` stdout unchanged. Switch to the new names.
|
|
|
240
247
|
| `run cancel --srp`, `run recording --srp` | `--target-id` |
|
|
241
248
|
| `--type` on `scenario create/update/list` | `--tag` |
|
|
242
249
|
|
|
250
|
+
## Scheduled runs
|
|
251
|
+
|
|
252
|
+
A schedule starts an ordinary run on its own at a wall-clock time on chosen
|
|
253
|
+
weekdays, then posts one summary to a Slack channel. What runs (the whole suite,
|
|
254
|
+
tags minus exclusions, or picked scenarios) is re-resolved at every start, so
|
|
255
|
+
scenarios tagged later join on their own.
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# Weekdays at 03:00 (this machine's timezone), tagged scenarios on desktop and Android Chrome
|
|
259
|
+
minitest schedules create --name "Nightly sanity check" --at 03:00 \
|
|
260
|
+
--tag Navigation --exclude "Deals page opens" \
|
|
261
|
+
--url https://www.example.com --browser chrome --browser chrome:android \
|
|
262
|
+
--slack-channel C0123ABCD --slack-channel-name minitap
|
|
263
|
+
|
|
264
|
+
# Native: newest installable build on Android, a fixed iOS build, every day in Oslo
|
|
265
|
+
minitest schedules create --name "Monitoring" --at 05:00 --days every-day --timezone Europe/Oslo \
|
|
266
|
+
--android --ios-build <build-id> --slack-channel C0123ABCD
|
|
267
|
+
|
|
268
|
+
minitest schedules preview "Nightly sanity check" # duration, builds tonight would pick, next starts
|
|
269
|
+
minitest schedules list # cadence, next run, scenario count
|
|
270
|
+
minitest --json schedules get "Nightly sanity check" > nightly.json
|
|
271
|
+
minitest schedules create --from-file nightly.json --name "Nightly copy" # JSON or YAML
|
|
272
|
+
minitest schedules update "Nightly sanity check" --at 04:00 --android-branch main
|
|
273
|
+
minitest schedules pause|resume "Nightly sanity check"
|
|
274
|
+
minitest schedules run "Nightly sanity check" # start one now (posts to Slack too)
|
|
275
|
+
minitest schedules fires "Nightly sanity check" # last runs: verdict, new / still open / fixed, or why it didn't run
|
|
276
|
+
minitest schedules delete "Nightly sanity check" --yes # `schedules restore <id>` undoes it
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Platforms: `--browser BROWSER[:SURFACE]` (`chrome`, `chrome:mobile`,
|
|
280
|
+
`chrome:tablet`, `chrome:android`, `safari:ios`…) tests `--url` or builds
|
|
281
|
+
`--web-branch` first. `--ios` / `--android` run the newest build that installs;
|
|
282
|
+
`--<platform>-build <id>` pins one build, `--<platform>-branch <branch>` builds
|
|
283
|
+
the branch before each run. On `update`, any `--<platform>-*` flag redefines that
|
|
284
|
+
platform, `--browser` replaces the browsers, `--drop web|ios|android` removes one.
|
|
285
|
+
|
|
286
|
+
A night that can't run is still a fire, with a reason (out of credits, no
|
|
287
|
+
installable build, branch build failed, previous run still going, no phone
|
|
288
|
+
free…); `fires` shows it and Slack gets a message. On a server without
|
|
289
|
+
scheduled runs, every command exits 4 with `Scheduled runs are not available
|
|
290
|
+
on this workspace yet.`
|
|
291
|
+
|
|
292
|
+
## Knowledge
|
|
293
|
+
|
|
294
|
+
On workspaces with Knowledge v2, what Mini knows about an app is split by job:
|
|
295
|
+
|
|
296
|
+
| Element | Holds | Commands |
|
|
297
|
+
| ------- | ----- | -------- |
|
|
298
|
+
| Product brief | What the app is, who uses it, its core flows. Short (max 2000 chars). | `brief get`, `brief update --content/--content-file` |
|
|
299
|
+
| App guide | How to use the app when testing: navigation, quirks, test data. | `app-guide get`, `app-guide update --content/--content-file` |
|
|
300
|
+
| Glossary | Product terms and what they mean, with aliases. | `glossary list`, `glossary add --term --meaning [--alias]`, `glossary update <id-or-term>`, `glossary remove <id-or-term> --yes` |
|
|
301
|
+
|
|
302
|
+
Every change is versioned with its author and channel (`cli` for these
|
|
303
|
+
commands): `minitest knowledge history [--element product_brief|app_guide|glossary]`
|
|
304
|
+
lists each change with its version ID, and `minitest knowledge revert <version-id>`
|
|
305
|
+
restores that version as a new `reverted` change.
|
|
306
|
+
On a workspace without Knowledge v2, writes fail with a message pointing to
|
|
307
|
+
`minitest app-knowledge`.
|
|
308
|
+
|
|
243
309
|
## Secrets
|
|
244
310
|
|
|
245
311
|
Credentials live in the app's vault, never in scenario text. Write
|
|
@@ -250,18 +316,26 @@ Workspaces without the feature get `Secrets are not enabled for this workspace y
|
|
|
250
316
|
|
|
251
317
|
```bash
|
|
252
318
|
printf '%s' "$ADMIN_PW" | minitest secret set ADMIN_PASSWORD --kind password --note "Admin login"
|
|
253
|
-
echo '{"number":"
|
|
319
|
+
echo '{"number":"<number>","expiry":"<MM/YY>","cvc":"<cvc>"}' \
|
|
254
320
|
| minitest secret set STRIPE_CARD --kind card # optional holder_name, postal_code
|
|
255
|
-
minitest secret
|
|
321
|
+
minitest secret create QA_PASSWORD --kind password --generate [--length 24] [--charset default|alnum]
|
|
322
|
+
minitest secret create SANDBOX_KEY --kind token --empty --reason "Checkout calls the sandbox" [--scenario <id>]
|
|
323
|
+
minitest secret list [--missing] # names, kinds, state (set / missing + reason), usages
|
|
256
324
|
minitest secret describe ADMIN_PASSWORD # usages + reference to copy
|
|
257
|
-
minitest secret lint --scenario <id> # exit 1 on leaks or missing
|
|
325
|
+
minitest secret lint --scenario <id> # exit 1 on leaks or missing; warns on pending
|
|
258
326
|
minitest secret extract <id> --as ADMIN_PASSWORD --kind password [--dry-run]
|
|
259
327
|
minitest test-profile update <id> --password-secret ADMIN_PASSWORD
|
|
260
328
|
```
|
|
261
329
|
|
|
262
330
|
`set` reads stdin only and refuses a terminal (`--interactive` opens a hidden
|
|
263
|
-
prompt)
|
|
264
|
-
|
|
331
|
+
prompt) and also fills a secret that is waiting for a value. Inside a test run
|
|
332
|
+
(`MINITAP_SECRETS_SOCKET` or `STORY_RUN_ID` set) it refuses: use `secret create`
|
|
333
|
+
instead, which never handles a value. `--generate` (password, token, text) lets
|
|
334
|
+
the server pick a random value (default 24 chars, 12–64); `--empty --reason`
|
|
335
|
+
creates the secret without a value for a human to fill, and runs that need it
|
|
336
|
+
wait until then. Personas can point at either (`--password-secret` etc.).
|
|
337
|
+
`secret request` is a deprecated alias of `create --empty`; on servers that
|
|
338
|
+
predate `create`, `--empty` falls back to the old request endpoint.
|
|
265
339
|
`extract` reads the leaked literal from the scenario on your machine, creates
|
|
266
340
|
the secret with it, then rewrites every occurrence to `{{secret:NAME}}`. Older
|
|
267
341
|
scenario versions and past run logs may still hold the literal: rotate it.
|
|
@@ -181,12 +181,18 @@ app defaults.
|
|
|
181
181
|
| `minitest df` | Low-level suite branches Mini writes (draft features) |
|
|
182
182
|
| `minitest test-profile` | Test profiles (Test accounts in the webapp) |
|
|
183
183
|
| `minitest tags` | List, create, update and delete scenario tags |
|
|
184
|
+
| `minitest brief` | Product brief: what the app is, who uses it, its core flows (Knowledge v2) |
|
|
185
|
+
| `minitest app-guide` | App guide: how to use the app when testing it (Knowledge v2) |
|
|
186
|
+
| `minitest glossary` | Glossary: product terms, their meaning and aliases (Knowledge v2) |
|
|
187
|
+
| `minitest knowledge` | Change history of the brief, app guide and glossary, and reverts |
|
|
188
|
+
| `minitest app-knowledge` | The single Memory document of workspaces without Knowledge v2 |
|
|
184
189
|
| `minitest app-skill` | App skills (Skills in the webapp): procedures Mini loads to arrange test state |
|
|
185
190
|
| `minitest secret` | App secrets vault: passwords, OTP seeds, cards, API tokens referenced as `{{secret:NAME}}` (write-only values) |
|
|
186
191
|
| `minitest screens` | Inspect the screens exploration mapped for an app |
|
|
187
192
|
| `minitest build` | Native iOS/Android build management |
|
|
188
193
|
| `minitest run` | Start runs and inspect their scenario runs |
|
|
189
194
|
| `minitest batch` | List, inspect and cancel runs (a batch is a Run in the webapp) |
|
|
195
|
+
| `minitest schedules` | Scheduled runs: run scenarios at a set time and post a Slack summary |
|
|
190
196
|
| `minitest issues` | Read app issues and their fix prompts, mark them fixed |
|
|
191
197
|
| `minitest skill` | Print the CLI skill for your AI coding agent (not app skills) |
|
|
192
198
|
|
|
@@ -207,6 +213,65 @@ stderr and leave `--json` stdout unchanged. Switch to the new names.
|
|
|
207
213
|
| `run cancel --srp`, `run recording --srp` | `--target-id` |
|
|
208
214
|
| `--type` on `scenario create/update/list` | `--tag` |
|
|
209
215
|
|
|
216
|
+
## Scheduled runs
|
|
217
|
+
|
|
218
|
+
A schedule starts an ordinary run on its own at a wall-clock time on chosen
|
|
219
|
+
weekdays, then posts one summary to a Slack channel. What runs (the whole suite,
|
|
220
|
+
tags minus exclusions, or picked scenarios) is re-resolved at every start, so
|
|
221
|
+
scenarios tagged later join on their own.
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
# Weekdays at 03:00 (this machine's timezone), tagged scenarios on desktop and Android Chrome
|
|
225
|
+
minitest schedules create --name "Nightly sanity check" --at 03:00 \
|
|
226
|
+
--tag Navigation --exclude "Deals page opens" \
|
|
227
|
+
--url https://www.example.com --browser chrome --browser chrome:android \
|
|
228
|
+
--slack-channel C0123ABCD --slack-channel-name minitap
|
|
229
|
+
|
|
230
|
+
# Native: newest installable build on Android, a fixed iOS build, every day in Oslo
|
|
231
|
+
minitest schedules create --name "Monitoring" --at 05:00 --days every-day --timezone Europe/Oslo \
|
|
232
|
+
--android --ios-build <build-id> --slack-channel C0123ABCD
|
|
233
|
+
|
|
234
|
+
minitest schedules preview "Nightly sanity check" # duration, builds tonight would pick, next starts
|
|
235
|
+
minitest schedules list # cadence, next run, scenario count
|
|
236
|
+
minitest --json schedules get "Nightly sanity check" > nightly.json
|
|
237
|
+
minitest schedules create --from-file nightly.json --name "Nightly copy" # JSON or YAML
|
|
238
|
+
minitest schedules update "Nightly sanity check" --at 04:00 --android-branch main
|
|
239
|
+
minitest schedules pause|resume "Nightly sanity check"
|
|
240
|
+
minitest schedules run "Nightly sanity check" # start one now (posts to Slack too)
|
|
241
|
+
minitest schedules fires "Nightly sanity check" # last runs: verdict, new / still open / fixed, or why it didn't run
|
|
242
|
+
minitest schedules delete "Nightly sanity check" --yes # `schedules restore <id>` undoes it
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Platforms: `--browser BROWSER[:SURFACE]` (`chrome`, `chrome:mobile`,
|
|
246
|
+
`chrome:tablet`, `chrome:android`, `safari:ios`…) tests `--url` or builds
|
|
247
|
+
`--web-branch` first. `--ios` / `--android` run the newest build that installs;
|
|
248
|
+
`--<platform>-build <id>` pins one build, `--<platform>-branch <branch>` builds
|
|
249
|
+
the branch before each run. On `update`, any `--<platform>-*` flag redefines that
|
|
250
|
+
platform, `--browser` replaces the browsers, `--drop web|ios|android` removes one.
|
|
251
|
+
|
|
252
|
+
A night that can't run is still a fire, with a reason (out of credits, no
|
|
253
|
+
installable build, branch build failed, previous run still going, no phone
|
|
254
|
+
free…); `fires` shows it and Slack gets a message. On a server without
|
|
255
|
+
scheduled runs, every command exits 4 with `Scheduled runs are not available
|
|
256
|
+
on this workspace yet.`
|
|
257
|
+
|
|
258
|
+
## Knowledge
|
|
259
|
+
|
|
260
|
+
On workspaces with Knowledge v2, what Mini knows about an app is split by job:
|
|
261
|
+
|
|
262
|
+
| Element | Holds | Commands |
|
|
263
|
+
| ------- | ----- | -------- |
|
|
264
|
+
| Product brief | What the app is, who uses it, its core flows. Short (max 2000 chars). | `brief get`, `brief update --content/--content-file` |
|
|
265
|
+
| App guide | How to use the app when testing: navigation, quirks, test data. | `app-guide get`, `app-guide update --content/--content-file` |
|
|
266
|
+
| Glossary | Product terms and what they mean, with aliases. | `glossary list`, `glossary add --term --meaning [--alias]`, `glossary update <id-or-term>`, `glossary remove <id-or-term> --yes` |
|
|
267
|
+
|
|
268
|
+
Every change is versioned with its author and channel (`cli` for these
|
|
269
|
+
commands): `minitest knowledge history [--element product_brief|app_guide|glossary]`
|
|
270
|
+
lists each change with its version ID, and `minitest knowledge revert <version-id>`
|
|
271
|
+
restores that version as a new `reverted` change.
|
|
272
|
+
On a workspace without Knowledge v2, writes fail with a message pointing to
|
|
273
|
+
`minitest app-knowledge`.
|
|
274
|
+
|
|
210
275
|
## Secrets
|
|
211
276
|
|
|
212
277
|
Credentials live in the app's vault, never in scenario text. Write
|
|
@@ -217,18 +282,26 @@ Workspaces without the feature get `Secrets are not enabled for this workspace y
|
|
|
217
282
|
|
|
218
283
|
```bash
|
|
219
284
|
printf '%s' "$ADMIN_PW" | minitest secret set ADMIN_PASSWORD --kind password --note "Admin login"
|
|
220
|
-
echo '{"number":"
|
|
285
|
+
echo '{"number":"<number>","expiry":"<MM/YY>","cvc":"<cvc>"}' \
|
|
221
286
|
| minitest secret set STRIPE_CARD --kind card # optional holder_name, postal_code
|
|
222
|
-
minitest secret
|
|
287
|
+
minitest secret create QA_PASSWORD --kind password --generate [--length 24] [--charset default|alnum]
|
|
288
|
+
minitest secret create SANDBOX_KEY --kind token --empty --reason "Checkout calls the sandbox" [--scenario <id>]
|
|
289
|
+
minitest secret list [--missing] # names, kinds, state (set / missing + reason), usages
|
|
223
290
|
minitest secret describe ADMIN_PASSWORD # usages + reference to copy
|
|
224
|
-
minitest secret lint --scenario <id> # exit 1 on leaks or missing
|
|
291
|
+
minitest secret lint --scenario <id> # exit 1 on leaks or missing; warns on pending
|
|
225
292
|
minitest secret extract <id> --as ADMIN_PASSWORD --kind password [--dry-run]
|
|
226
293
|
minitest test-profile update <id> --password-secret ADMIN_PASSWORD
|
|
227
294
|
```
|
|
228
295
|
|
|
229
296
|
`set` reads stdin only and refuses a terminal (`--interactive` opens a hidden
|
|
230
|
-
prompt)
|
|
231
|
-
|
|
297
|
+
prompt) and also fills a secret that is waiting for a value. Inside a test run
|
|
298
|
+
(`MINITAP_SECRETS_SOCKET` or `STORY_RUN_ID` set) it refuses: use `secret create`
|
|
299
|
+
instead, which never handles a value. `--generate` (password, token, text) lets
|
|
300
|
+
the server pick a random value (default 24 chars, 12–64); `--empty --reason`
|
|
301
|
+
creates the secret without a value for a human to fill, and runs that need it
|
|
302
|
+
wait until then. Personas can point at either (`--password-secret` etc.).
|
|
303
|
+
`secret request` is a deprecated alias of `create --empty`; on servers that
|
|
304
|
+
predate `create`, `--empty` falls back to the old request endpoint.
|
|
232
305
|
`extract` reads the leaked literal from the scenario on your machine, creates
|
|
233
306
|
the secret with it, then rewrites every occurrence to `{{secret:NAME}}`. Older
|
|
234
307
|
scenario versions and past run logs may still hold the literal: rotate it.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "minitest-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.41.0"
|
|
4
4
|
description = "Minitest CLI – command-line interface for the Minitest testing platform"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -32,6 +32,7 @@ dependencies = [
|
|
|
32
32
|
"pydantic>=2.12.5",
|
|
33
33
|
"pydantic-settings>=2.13.1",
|
|
34
34
|
"rich>=14.3.3",
|
|
35
|
+
"pyyaml>=6.0.3",
|
|
35
36
|
]
|
|
36
37
|
|
|
37
38
|
[project.optional-dependencies]
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""`minitest glossary`: the app's product terms, their meaning and aliases."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated, Any
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from minitest_cli.api.client import ApiClient
|
|
8
|
+
from minitest_cli.commands.knowledge_helpers import (
|
|
9
|
+
app_path,
|
|
10
|
+
call_for_app,
|
|
11
|
+
check_response,
|
|
12
|
+
describe_actor,
|
|
13
|
+
)
|
|
14
|
+
from minitest_cli.commands.user_story_helpers import EXIT_NOT_FOUND, is_json_mode
|
|
15
|
+
from minitest_cli.utils.confirm import confirm_or_exit
|
|
16
|
+
from minitest_cli.utils.output import output, print_error, print_info, print_success, print_table
|
|
17
|
+
|
|
18
|
+
app = typer.Typer(
|
|
19
|
+
name="glossary",
|
|
20
|
+
help="Glossary: product terms Mini must understand, with their meaning and aliases.",
|
|
21
|
+
no_args_is_help=True,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
TermRef = Annotated[str, typer.Argument(help="Term ID, or the term itself (case-insensitive).")]
|
|
25
|
+
AliasOption = Annotated[
|
|
26
|
+
list[str] | None,
|
|
27
|
+
typer.Option("--alias", help="Other name for the term (repeatable; replaces the aliases)."),
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
async def _fetch_terms(client: ApiClient, app_id: str) -> list[dict[str, Any]]:
|
|
32
|
+
resp = await client.get(app_path(app_id, "glossary"))
|
|
33
|
+
check_response(resp, resource="Glossary")
|
|
34
|
+
return resp.json().get("terms", [])
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _find_term(terms: list[dict[str, Any]], ref: str) -> dict[str, Any]:
|
|
38
|
+
wanted = ref.strip().casefold()
|
|
39
|
+
for term in terms:
|
|
40
|
+
if term.get("id") == ref or str(term.get("term", "")).casefold() == wanted:
|
|
41
|
+
return term
|
|
42
|
+
print_error(f"Glossary term not found: {ref}. Run `minitest glossary list` to see the terms.")
|
|
43
|
+
raise typer.Exit(code=EXIT_NOT_FOUND)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@app.command(name="list")
|
|
47
|
+
def list_terms() -> None:
|
|
48
|
+
"""List every term with its meaning, aliases and last author."""
|
|
49
|
+
terms = call_for_app(_fetch_terms)
|
|
50
|
+
if is_json_mode():
|
|
51
|
+
output({"terms": terms}, json_mode=True)
|
|
52
|
+
return
|
|
53
|
+
if not terms:
|
|
54
|
+
print_info("No glossary terms yet. Add one with `minitest glossary add`.")
|
|
55
|
+
return
|
|
56
|
+
rows = [
|
|
57
|
+
[
|
|
58
|
+
t.get("term", ""),
|
|
59
|
+
t.get("meaning", ""),
|
|
60
|
+
", ".join(t.get("aliases") or []),
|
|
61
|
+
describe_actor(t.get("actor")),
|
|
62
|
+
t.get("id", ""),
|
|
63
|
+
]
|
|
64
|
+
for t in terms
|
|
65
|
+
]
|
|
66
|
+
print_table(["Term", "Meaning", "Aliases", "Last edited by", "ID"], rows, title="Glossary")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@app.command(name="add")
|
|
70
|
+
def add_term(
|
|
71
|
+
term: Annotated[str, typer.Option("--term", help="The product term, as users say it.")],
|
|
72
|
+
meaning: Annotated[str, typer.Option("--meaning", help="What the term means in this app.")],
|
|
73
|
+
alias: AliasOption = None,
|
|
74
|
+
) -> None:
|
|
75
|
+
"""Add a term to the glossary."""
|
|
76
|
+
body = {"term": term, "meaning": meaning, "aliases": alias or []}
|
|
77
|
+
|
|
78
|
+
async def _add(client: ApiClient, app_id: str) -> dict[str, Any]:
|
|
79
|
+
resp = await client.post(app_path(app_id, "glossary"), json=body)
|
|
80
|
+
check_response(resp, resource="Glossary")
|
|
81
|
+
return resp.json()
|
|
82
|
+
|
|
83
|
+
created = call_for_app(_add)
|
|
84
|
+
if not is_json_mode():
|
|
85
|
+
print_success(f"Glossary term added: {created.get('term')} ({created.get('id')})")
|
|
86
|
+
output(created, json_mode=is_json_mode())
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@app.command(name="update")
|
|
90
|
+
def update_term(
|
|
91
|
+
term_ref: TermRef,
|
|
92
|
+
term: Annotated[str | None, typer.Option("--term", help="Rename the term.")] = None,
|
|
93
|
+
meaning: Annotated[str | None, typer.Option("--meaning", help="New meaning.")] = None,
|
|
94
|
+
alias: AliasOption = None,
|
|
95
|
+
clear_aliases: Annotated[
|
|
96
|
+
bool, typer.Option("--clear-aliases", help="Remove every alias. Excludes --alias.")
|
|
97
|
+
] = False,
|
|
98
|
+
) -> None:
|
|
99
|
+
"""Change a term's name, meaning or aliases."""
|
|
100
|
+
if clear_aliases and alias:
|
|
101
|
+
print_error("Use either --alias or --clear-aliases, not both.")
|
|
102
|
+
raise typer.Exit(code=1)
|
|
103
|
+
fields: dict[str, Any] = {"term": term, "meaning": meaning}
|
|
104
|
+
fields["aliases"] = [] if clear_aliases else alias or None
|
|
105
|
+
payload = {key: value for key, value in fields.items() if value is not None}
|
|
106
|
+
if not payload:
|
|
107
|
+
print_error("Provide at least one of --term, --meaning, --alias or --clear-aliases.")
|
|
108
|
+
raise typer.Exit(code=1)
|
|
109
|
+
|
|
110
|
+
async def _update(client: ApiClient, app_id: str) -> dict[str, Any]:
|
|
111
|
+
found = _find_term(await _fetch_terms(client, app_id), term_ref)
|
|
112
|
+
resp = await client.patch(app_path(app_id, f"glossary/{found['id']}"), json=payload)
|
|
113
|
+
check_response(resp, resource="Glossary term")
|
|
114
|
+
return resp.json()
|
|
115
|
+
|
|
116
|
+
updated = call_for_app(_update)
|
|
117
|
+
if not is_json_mode():
|
|
118
|
+
print_success(f"Glossary term updated: {updated.get('term')}")
|
|
119
|
+
output(updated, json_mode=is_json_mode())
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@app.command(name="remove")
|
|
123
|
+
def remove_term(
|
|
124
|
+
term_ref: TermRef,
|
|
125
|
+
yes: Annotated[bool, typer.Option("--yes", help="Confirm the removal.")] = False,
|
|
126
|
+
) -> None:
|
|
127
|
+
"""Remove a term from the glossary (kept in its history)."""
|
|
128
|
+
confirm_or_exit(yes, f"Removing glossary term {term_ref!r}")
|
|
129
|
+
|
|
130
|
+
async def _remove(client: ApiClient, app_id: str) -> dict[str, Any]:
|
|
131
|
+
found = _find_term(await _fetch_terms(client, app_id), term_ref)
|
|
132
|
+
resp = await client.delete(app_path(app_id, f"glossary/{found['id']}"))
|
|
133
|
+
check_response(resp, resource="Glossary term")
|
|
134
|
+
return found
|
|
135
|
+
|
|
136
|
+
removed = call_for_app(_remove)
|
|
137
|
+
if is_json_mode():
|
|
138
|
+
output({"removed": True, "id": removed["id"], "term": removed["term"]}, json_mode=True)
|
|
139
|
+
else:
|
|
140
|
+
print_success(f"Glossary term removed: {removed['term']}")
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""`minitest knowledge history|revert`: who changed the Product brief, App guide or Glossary."""
|
|
2
|
+
|
|
3
|
+
from enum import StrEnum
|
|
4
|
+
from typing import Annotated, Any
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from minitest_cli.api.client import ApiClient
|
|
9
|
+
from minitest_cli.commands.knowledge_helpers import (
|
|
10
|
+
app_path,
|
|
11
|
+
call_for_app,
|
|
12
|
+
check_response,
|
|
13
|
+
describe_actor,
|
|
14
|
+
)
|
|
15
|
+
from minitest_cli.commands.user_story_helpers import is_json_mode
|
|
16
|
+
from minitest_cli.utils.output import output, print_info, print_success, print_table
|
|
17
|
+
|
|
18
|
+
app = typer.Typer(
|
|
19
|
+
name="knowledge",
|
|
20
|
+
help="Change history of the Product brief, App guide and Glossary, and reverts.",
|
|
21
|
+
no_args_is_help=True,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class KnowledgeElement(StrEnum):
|
|
26
|
+
product_brief = "product_brief"
|
|
27
|
+
app_guide = "app_guide"
|
|
28
|
+
glossary = "glossary"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@app.callback()
|
|
32
|
+
def _callback() -> None:
|
|
33
|
+
"""Knowledge operations."""
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@app.command(name="history")
|
|
37
|
+
def history(
|
|
38
|
+
element: Annotated[
|
|
39
|
+
KnowledgeElement | None,
|
|
40
|
+
typer.Option("--element", help="Only this element (default: all three, merged)."),
|
|
41
|
+
] = None,
|
|
42
|
+
limit: Annotated[int, typer.Option("--limit", min=1, max=200, help="Max changes.")] = 20,
|
|
43
|
+
) -> None:
|
|
44
|
+
"""List recent changes, newest first, with author, channel and version."""
|
|
45
|
+
elements = [element] if element else list(KnowledgeElement)
|
|
46
|
+
|
|
47
|
+
async def _history(client: ApiClient, app_id: str) -> list[dict[str, Any]]:
|
|
48
|
+
changes: list[dict[str, Any]] = []
|
|
49
|
+
for wanted in elements:
|
|
50
|
+
resp = await client.get(
|
|
51
|
+
app_path(app_id, "knowledge/history"),
|
|
52
|
+
params={"element": wanted.value, "limit": limit},
|
|
53
|
+
)
|
|
54
|
+
check_response(resp, resource="Knowledge history")
|
|
55
|
+
changes.extend(resp.json())
|
|
56
|
+
changes.sort(key=lambda change: change.get("createdAt") or "", reverse=True)
|
|
57
|
+
return changes[:limit]
|
|
58
|
+
|
|
59
|
+
changes = call_for_app(_history)
|
|
60
|
+
if is_json_mode():
|
|
61
|
+
output(changes, json_mode=True)
|
|
62
|
+
return
|
|
63
|
+
if not changes:
|
|
64
|
+
print_info("No knowledge changes yet.")
|
|
65
|
+
return
|
|
66
|
+
rows = [
|
|
67
|
+
[
|
|
68
|
+
c.get("createdAt", ""),
|
|
69
|
+
c.get("element", ""),
|
|
70
|
+
c.get("change", ""),
|
|
71
|
+
_subject(c),
|
|
72
|
+
describe_actor(c.get("actor")),
|
|
73
|
+
c.get("versionId", ""),
|
|
74
|
+
]
|
|
75
|
+
for c in changes
|
|
76
|
+
]
|
|
77
|
+
print_table(["When", "Element", "Change", "Version / term", "By", "Version ID"], rows)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _subject(change: dict[str, Any]) -> str:
|
|
81
|
+
if change.get("versionNumber") is not None:
|
|
82
|
+
return f"v{change['versionNumber']}"
|
|
83
|
+
after = change.get("after") if isinstance(change.get("after"), dict) else None
|
|
84
|
+
before = change.get("before") if isinstance(change.get("before"), dict) else None
|
|
85
|
+
snapshot = after or before or {}
|
|
86
|
+
return str(snapshot.get("term") or change.get("termId") or "")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@app.command(name="revert")
|
|
90
|
+
def revert(
|
|
91
|
+
version_id: Annotated[
|
|
92
|
+
str, typer.Argument(help="Version ID from `minitest knowledge history`.")
|
|
93
|
+
],
|
|
94
|
+
) -> None:
|
|
95
|
+
"""Restore an element to that version, recorded as a new 'reverted' change."""
|
|
96
|
+
|
|
97
|
+
async def _revert(client: ApiClient, app_id: str) -> None:
|
|
98
|
+
resp = await client.post(app_path(app_id, f"knowledge/history/{version_id}/revert"))
|
|
99
|
+
check_response(resp, resource="Knowledge version")
|
|
100
|
+
|
|
101
|
+
call_for_app(_revert)
|
|
102
|
+
if is_json_mode():
|
|
103
|
+
output({"versionId": version_id, "reverted": True}, json_mode=True)
|
|
104
|
+
return
|
|
105
|
+
print_success(f"Reverted to version {version_id}.")
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""`minitest brief` and `minitest app-guide`: the two versioned Knowledge v2 documents."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from minitest_cli.api.client import ApiClient
|
|
8
|
+
from minitest_cli.commands.knowledge_helpers import (
|
|
9
|
+
ContentFileOption,
|
|
10
|
+
ContentOption,
|
|
11
|
+
app_path,
|
|
12
|
+
call_for_app,
|
|
13
|
+
check_response,
|
|
14
|
+
describe_actor,
|
|
15
|
+
resolve_content,
|
|
16
|
+
)
|
|
17
|
+
from minitest_cli.commands.user_story_helpers import is_json_mode
|
|
18
|
+
from minitest_cli.utils.output import output, print_info, print_success
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _document_app(name: str, route: str, label: str, help_text: str) -> typer.Typer:
|
|
22
|
+
group = typer.Typer(name=name, help=help_text, no_args_is_help=True)
|
|
23
|
+
|
|
24
|
+
@group.command(name="get")
|
|
25
|
+
def get_document() -> None:
|
|
26
|
+
"""Print the current content (with --json: content, version and author)."""
|
|
27
|
+
|
|
28
|
+
async def _get(client: ApiClient, app_id: str) -> dict[str, Any]:
|
|
29
|
+
resp = await client.get(app_path(app_id, route))
|
|
30
|
+
check_response(resp, resource=label)
|
|
31
|
+
return resp.json()
|
|
32
|
+
|
|
33
|
+
record = call_for_app(_get)
|
|
34
|
+
if is_json_mode():
|
|
35
|
+
output(record, json_mode=True)
|
|
36
|
+
return
|
|
37
|
+
if not record.get("content"):
|
|
38
|
+
print_info(f"No {label} written yet.")
|
|
39
|
+
return
|
|
40
|
+
print_info(_version_line(record))
|
|
41
|
+
print(record["content"]) # noqa: T201
|
|
42
|
+
|
|
43
|
+
@group.command(name="update")
|
|
44
|
+
def update_document(
|
|
45
|
+
content: ContentOption = None, content_file: ContentFileOption = None
|
|
46
|
+
) -> None:
|
|
47
|
+
"""Replace the content, creating a new version authored by you via the CLI."""
|
|
48
|
+
body = {"content": resolve_content(content, content_file)}
|
|
49
|
+
|
|
50
|
+
async def _put(client: ApiClient, app_id: str) -> dict[str, Any]:
|
|
51
|
+
resp = await client.put(app_path(app_id, route), json=body)
|
|
52
|
+
check_response(resp, resource=label)
|
|
53
|
+
return resp.json()
|
|
54
|
+
|
|
55
|
+
record = call_for_app(_put)
|
|
56
|
+
if is_json_mode():
|
|
57
|
+
output(record, json_mode=True)
|
|
58
|
+
return
|
|
59
|
+
print_success(f"{label} updated (version {record.get('versionNumber')}).")
|
|
60
|
+
print(record.get("versionNumber")) # noqa: T201
|
|
61
|
+
|
|
62
|
+
return group
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _version_line(record: dict[str, Any]) -> str:
|
|
66
|
+
author = describe_actor(record.get("actor"))
|
|
67
|
+
line = f"Version {record.get('versionNumber')}"
|
|
68
|
+
if author:
|
|
69
|
+
line += f" by {author}"
|
|
70
|
+
if record.get("createdAt"):
|
|
71
|
+
line += f", {record['createdAt']}"
|
|
72
|
+
return line
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
brief_app = _document_app(
|
|
76
|
+
"brief",
|
|
77
|
+
"product-brief",
|
|
78
|
+
"Product brief",
|
|
79
|
+
"Product brief: what the app is, who uses it and its core flows (max 2000 chars).",
|
|
80
|
+
)
|
|
81
|
+
app_guide_app = _document_app(
|
|
82
|
+
"app-guide",
|
|
83
|
+
"app-guide",
|
|
84
|
+
"App guide",
|
|
85
|
+
"App guide: how to use the app when testing it (navigation, quirks, test data).",
|
|
86
|
+
)
|