minitest-cli 0.36.0__tar.gz → 0.37.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.
Files changed (222) hide show
  1. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/.env.example +6 -0
  2. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/PKG-INFO +5 -3
  3. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/README.md +4 -2
  4. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/pyproject.toml +1 -1
  5. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/api/client.py +9 -2
  6. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/apps.py +4 -0
  7. minitest_cli-0.37.0/src/minitest_cli/commands/draft.py +111 -0
  8. minitest_cli-0.37.0/src/minitest_cli/commands/draft_asks.py +148 -0
  9. minitest_cli-0.37.0/src/minitest_cli/commands/draft_conversation.py +84 -0
  10. minitest_cli-0.37.0/src/minitest_cli/commands/draft_create.py +66 -0
  11. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/draft_feature.py +9 -6
  12. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/draft_feature_apply.py +1 -1
  13. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/draft_feature_conflicts.py +1 -1
  14. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/draft_feature_helpers.py +1 -3
  15. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/draft_feature_show.py +1 -1
  16. minitest_cli-0.37.0/src/minitest_cli/commands/draft_helpers.py +131 -0
  17. minitest_cli-0.37.0/src/minitest_cli/commands/draft_legacy.py +40 -0
  18. minitest_cli-0.37.0/src/minitest_cli/commands/draft_lifecycle.py +103 -0
  19. minitest_cli-0.37.0/src/minitest_cli/commands/draft_pr.py +49 -0
  20. minitest_cli-0.37.0/src/minitest_cli/commands/draft_render.py +110 -0
  21. minitest_cli-0.37.0/src/minitest_cli/commands/draft_update.py +45 -0
  22. minitest_cli-0.37.0/src/minitest_cli/commands/draft_watch.py +90 -0
  23. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/env_helpers.py +4 -0
  24. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/core/config.py +5 -0
  25. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/main.py +2 -1
  26. minitest_cli-0.37.0/tests/draft_backend.py +98 -0
  27. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_deprecated_commands.py +18 -3
  28. minitest_cli-0.37.0/tests/test_draft_ask_commands.py +120 -0
  29. minitest_cli-0.37.0/tests/test_draft_commands.py +167 -0
  30. minitest_cli-0.37.0/tests/test_draft_conversation_commands.py +133 -0
  31. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_draft_feature_commands.py +1 -1
  32. minitest_cli-0.37.0/tests/test_draft_pr_commands.py +135 -0
  33. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/uv.lock +1 -1
  34. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/.github/workflows/ci.yml +0 -0
  35. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/.github/workflows/install-scripts.yml +0 -0
  36. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/.github/workflows/release.yml +0 -0
  37. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/.gitignore +0 -0
  38. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/.opencode/skill/release/SKILL.md +0 -0
  39. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/AGENTS.md +0 -0
  40. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/RELEASE.md +0 -0
  41. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/install.ps1 +0 -0
  42. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/install.sh +0 -0
  43. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/pyrightconfig.json +0 -0
  44. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/renovate.json +0 -0
  45. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/__init__.py +0 -0
  46. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/api/__init__.py +0 -0
  47. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/api/apps_manager_client.py +0 -0
  48. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/api/errors.py +0 -0
  49. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/assets/__init__.py +0 -0
  50. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/assets/callback.html +0 -0
  51. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/__init__.py +0 -0
  52. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/_response_errors.py +0 -0
  53. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/app_knowledge.py +0 -0
  54. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/app_knowledge_helpers.py +0 -0
  55. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/app_network_helpers.py +0 -0
  56. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/app_skill.py +0 -0
  57. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/app_skill_helpers.py +0 -0
  58. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/app_skill_secret.py +0 -0
  59. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/app_skill_write.py +0 -0
  60. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/apps_dependencies.py +0 -0
  61. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/apps_get.py +0 -0
  62. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/apps_helpers.py +0 -0
  63. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/apps_table.py +0 -0
  64. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/auth.py +0 -0
  65. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/auth_api_key.py +0 -0
  66. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/batch.py +0 -0
  67. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/batch_helpers.py +0 -0
  68. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/batch_warnings.py +0 -0
  69. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/build.py +0 -0
  70. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/build_commit.py +0 -0
  71. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/build_fix_prompts.py +0 -0
  72. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/build_get.py +0 -0
  73. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/build_helpers.py +0 -0
  74. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/capabilities.py +0 -0
  75. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/commit_helpers.py +0 -0
  76. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/deprecated_alias.py +0 -0
  77. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/env.py +0 -0
  78. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/flow_types.py +0 -0
  79. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/flow_types_helpers.py +0 -0
  80. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/flow_types_write.py +0 -0
  81. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/init.py +0 -0
  82. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/init_helpers.py +0 -0
  83. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/init_playbook.py +0 -0
  84. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/issues.py +0 -0
  85. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/issues_fix.py +0 -0
  86. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/issues_get.py +0 -0
  87. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/issues_helpers.py +0 -0
  88. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/issues_projection.py +0 -0
  89. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/issues_service.py +0 -0
  90. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/private_network.py +0 -0
  91. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/private_network_helpers.py +0 -0
  92. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/recording_timeline.py +0 -0
  93. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/residential_proxy.py +0 -0
  94. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/run.py +0 -0
  95. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/run_cancel.py +0 -0
  96. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/run_commit.py +0 -0
  97. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/run_commit_helpers.py +0 -0
  98. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/run_display.py +0 -0
  99. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/run_feedback.py +0 -0
  100. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/run_helpers.py +0 -0
  101. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/run_recording.py +0 -0
  102. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/run_recording_helpers.py +0 -0
  103. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/run_tagged.py +0 -0
  104. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/run_targets.py +0 -0
  105. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/screens.py +0 -0
  106. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/screens_detail.py +0 -0
  107. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/screens_format.py +0 -0
  108. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/screens_helpers.py +0 -0
  109. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/screens_tree.py +0 -0
  110. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/skill.py +0 -0
  111. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/tags.py +0 -0
  112. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/tags_helpers.py +0 -0
  113. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/test_file.py +0 -0
  114. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/test_file_helpers.py +0 -0
  115. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/test_file_list.py +0 -0
  116. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/test_profile.py +0 -0
  117. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/test_profile_card.py +0 -0
  118. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/test_profile_default.py +0 -0
  119. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/test_profile_helpers.py +0 -0
  120. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/test_profile_list.py +0 -0
  121. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/test_profile_update.py +0 -0
  122. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/upgrade.py +0 -0
  123. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/user_story.py +0 -0
  124. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/user_story_app_skills.py +0 -0
  125. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/user_story_bindings.py +0 -0
  126. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/user_story_camera.py +0 -0
  127. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/user_story_create.py +0 -0
  128. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/user_story_criteria.py +0 -0
  129. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/user_story_criterion_edits.py +0 -0
  130. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/user_story_delete.py +0 -0
  131. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/user_story_device_count.py +0 -0
  132. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/user_story_helpers.py +0 -0
  133. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/user_story_modify.py +0 -0
  134. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/user_story_overrides.py +0 -0
  135. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/user_story_profiles.py +0 -0
  136. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/user_story_setup_commit.py +0 -0
  137. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/user_story_update.py +0 -0
  138. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/verdicts.py +0 -0
  139. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/verdicts_helpers.py +0 -0
  140. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/commands/verdicts_projection.py +0 -0
  141. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/core/__init__.py +0 -0
  142. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/core/app_context.py +0 -0
  143. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/core/auth.py +0 -0
  144. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/core/credentials.py +0 -0
  145. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/core/oauth.py +0 -0
  146. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/core/tenants.py +0 -0
  147. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/core/token_exchange.py +0 -0
  148. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/models/__init__.py +0 -0
  149. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/models/app.py +0 -0
  150. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/models/app_env_vars.py +0 -0
  151. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/models/app_failure.py +0 -0
  152. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/models/app_screen.py +0 -0
  153. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/models/base.py +0 -0
  154. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/models/batch.py +0 -0
  155. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/models/build.py +0 -0
  156. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/models/commit_build.py +0 -0
  157. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/models/draft_feature.py +0 -0
  158. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/models/flow_type.py +0 -0
  159. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/models/issues.py +0 -0
  160. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/models/recording.py +0 -0
  161. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/models/story_run.py +0 -0
  162. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/models/tag.py +0 -0
  163. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/models/targets.py +0 -0
  164. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/models/user_story.py +0 -0
  165. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/utils/__init__.py +0 -0
  166. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/utils/confirm.py +0 -0
  167. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/utils/dependency_sim.py +0 -0
  168. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/utils/mermaid.py +0 -0
  169. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/utils/output.py +0 -0
  170. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/utils/skill_refresh.py +0 -0
  171. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/utils/update_check.py +0 -0
  172. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/src/minitest_cli/utils/video_frames.py +0 -0
  173. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/__init__.py +0 -0
  174. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/_commit_transport.py +0 -0
  175. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/_network_settings_server.py +0 -0
  176. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/conftest.py +0 -0
  177. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_api_client_auth.py +0 -0
  178. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_app_knowledge_commands.py +0 -0
  179. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_app_skill_commands.py +0 -0
  180. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_apps_commands.py +0 -0
  181. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_apps_dependencies.py +0 -0
  182. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_auth.py +0 -0
  183. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_auth_api_key.py +0 -0
  184. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_auth_commands.py +0 -0
  185. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_batch_commands.py +0 -0
  186. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_build_commands.py +0 -0
  187. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_build_fix_prompts.py +0 -0
  188. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_build_get_command.py +0 -0
  189. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_capabilities_command.py +0 -0
  190. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_channel_header.py +0 -0
  191. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_code_quality.py +0 -0
  192. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_commit_commands.py +0 -0
  193. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_deprecated_flags.py +0 -0
  194. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_env.py +0 -0
  195. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_flow_types_commands.py +0 -0
  196. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_init_command.py +0 -0
  197. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_issues.py +0 -0
  198. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_issues_commands.py +0 -0
  199. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_issues_get_command.py +0 -0
  200. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_mermaid.py +0 -0
  201. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_native_device_types.py +0 -0
  202. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_network_errors.py +0 -0
  203. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_private_network_commands.py +0 -0
  204. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_recording_timeline.py +0 -0
  205. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_residential_proxy_commands.py +0 -0
  206. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_response_errors.py +0 -0
  207. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_run_cancel.py +0 -0
  208. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_run_commands.py +0 -0
  209. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_run_frames_command.py +0 -0
  210. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_screens_commands.py +0 -0
  211. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_skill_command.py +0 -0
  212. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_suite_change_provenance.py +0 -0
  213. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_tags_commands.py +0 -0
  214. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_test_file_commands.py +0 -0
  215. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_test_profile_commands.py +0 -0
  216. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_upgrade_command.py +0 -0
  217. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_user_story_bindings_commands.py +0 -0
  218. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_user_story_commands.py +0 -0
  219. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_user_story_setup_commit.py +0 -0
  220. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_verdicts.py +0 -0
  221. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_verdicts_actionable.py +0 -0
  222. {minitest_cli-0.36.0 → minitest_cli-0.37.0}/tests/test_version.py +0 -0
@@ -16,6 +16,12 @@ MINITEST_API_URL=https://testing-service.dev.minitap.ai
16
16
  # Development
17
17
  MINITEST_APPS_MANAGER_URL=https://apps-manager.dev.minitap.ai
18
18
 
19
+ # —— Conductor (minitest draft) ——
20
+ # Production
21
+ # MINITEST_CONDUCTOR_URL=https://conductor.app.minitap.ai
22
+ # Development
23
+ MINITEST_CONDUCTOR_URL=https://conductor.dev.minitap.ai
24
+
19
25
  # —— Integrations ——
20
26
  # Production
21
27
  # MINITEST_INTEGRATIONS_URL=https://integrations.minitap.ai
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: minitest-cli
3
- Version: 0.36.0
3
+ Version: 0.37.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
@@ -145,6 +145,7 @@ app defaults.
145
145
  | `MINITEST_APP_ID` | Default app ID | No (can use `--app` flag) |
146
146
  | `MINITEST_API_URL` | testing-service base URL | No (defaults to production) |
147
147
  | `MINITEST_APPS_MANAGER_URL` | apps-manager base URL (used by `minitest apps create`) | No (defaults to production) |
148
+ | `MINITEST_CONDUCTOR_URL` | Conductor base URL (used by `minitest draft`) | No (defaults to production) |
148
149
  | `MINITEST_INTEGRATIONS_URL` | minihands-integrations base URL (used to list tenants) | No (defaults to production) |
149
150
  | `MINITEST_WEBAPP_URL` | Minitest webapp base URL (used for review links) | No (defaults to production) |
150
151
  | `MINITEST_SUPABASE_URL` | Supabase project URL used for OAuth login | No (defaults to production) |
@@ -169,7 +170,8 @@ app defaults.
169
170
  | `minitest apps` | List, inspect, and create apps; residential proxy and private network settings |
170
171
  | `minitest scenario` | Create, update, list and delete scenarios |
171
172
  | `minitest scenario-binding` | Bind test accounts, test files or app skills to scenarios |
172
- | `minitest draft` | Drafts — branches of the test suite |
173
+ | `minitest draft` | Ask Mini for a suite change, follow it, check and merge it (drafts in the webapp) |
174
+ | `minitest df` | Low-level suite branches Mini writes (draft features) |
173
175
  | `minitest test-profile` | Test profiles (Test accounts in the webapp) |
174
176
  | `minitest tags` | List, create, update and delete scenario tags |
175
177
  | `minitest app-skill` | App skills (Skills in the webapp): procedures Mini loads to arrange test state |
@@ -190,7 +192,7 @@ stderr and leave `--json` stdout unchanged. Switch to the new names.
190
192
  | `minitest user-story` | `minitest scenario` |
191
193
  | `minitest user-story-binding` | `minitest scenario-binding` |
192
194
  | `minitest scenario-binding set-skills` | `minitest scenario-binding set-app-skills` |
193
- | `minitest df` | `minitest draft` |
195
+ | `minitest draft show/apply/delete` (v0.34–v0.36) | `minitest df show/apply/delete` |
194
196
  | `minitest flow-types` | `minitest tags` |
195
197
  | `run from-commit --user-story` / `-u` | `run from-commit --scenario` / `-s` |
196
198
  | `batch list --user-story-id` | `batch list --scenario` |
@@ -112,6 +112,7 @@ app defaults.
112
112
  | `MINITEST_APP_ID` | Default app ID | No (can use `--app` flag) |
113
113
  | `MINITEST_API_URL` | testing-service base URL | No (defaults to production) |
114
114
  | `MINITEST_APPS_MANAGER_URL` | apps-manager base URL (used by `minitest apps create`) | No (defaults to production) |
115
+ | `MINITEST_CONDUCTOR_URL` | Conductor base URL (used by `minitest draft`) | No (defaults to production) |
115
116
  | `MINITEST_INTEGRATIONS_URL` | minihands-integrations base URL (used to list tenants) | No (defaults to production) |
116
117
  | `MINITEST_WEBAPP_URL` | Minitest webapp base URL (used for review links) | No (defaults to production) |
117
118
  | `MINITEST_SUPABASE_URL` | Supabase project URL used for OAuth login | No (defaults to production) |
@@ -136,7 +137,8 @@ app defaults.
136
137
  | `minitest apps` | List, inspect, and create apps; residential proxy and private network settings |
137
138
  | `minitest scenario` | Create, update, list and delete scenarios |
138
139
  | `minitest scenario-binding` | Bind test accounts, test files or app skills to scenarios |
139
- | `minitest draft` | Drafts — branches of the test suite |
140
+ | `minitest draft` | Ask Mini for a suite change, follow it, check and merge it (drafts in the webapp) |
141
+ | `minitest df` | Low-level suite branches Mini writes (draft features) |
140
142
  | `minitest test-profile` | Test profiles (Test accounts in the webapp) |
141
143
  | `minitest tags` | List, create, update and delete scenario tags |
142
144
  | `minitest app-skill` | App skills (Skills in the webapp): procedures Mini loads to arrange test state |
@@ -157,7 +159,7 @@ stderr and leave `--json` stdout unchanged. Switch to the new names.
157
159
  | `minitest user-story` | `minitest scenario` |
158
160
  | `minitest user-story-binding` | `minitest scenario-binding` |
159
161
  | `minitest scenario-binding set-skills` | `minitest scenario-binding set-app-skills` |
160
- | `minitest df` | `minitest draft` |
162
+ | `minitest draft show/apply/delete` (v0.34–v0.36) | `minitest df show/apply/delete` |
161
163
  | `minitest flow-types` | `minitest tags` |
162
164
  | `run from-commit --user-story` / `-u` | `run from-commit --scenario` / `-s` |
163
165
  | `batch list --user-story-id` | `batch list --scenario` |
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "minitest-cli"
3
- version = "0.36.0"
3
+ version = "0.37.0"
4
4
  description = "Minitest CLI – command-line interface for the Minitest testing platform"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -39,9 +39,16 @@ class ApiClient:
39
39
  response = await client.get("/api/v1/apps")
40
40
  """
41
41
 
42
- def __init__(self, settings: Settings, *, token_override: str | None = None) -> None:
42
+ def __init__(
43
+ self,
44
+ settings: Settings,
45
+ *,
46
+ token_override: str | None = None,
47
+ base_url: str | None = None,
48
+ ) -> None:
43
49
  self._settings = settings
44
50
  self._token_override = token_override
51
+ self._base_url = base_url or settings.api_url
45
52
  self._client: httpx.AsyncClient | None = None
46
53
 
47
54
  async def __aenter__(self) -> "ApiClient":
@@ -53,7 +60,7 @@ class ApiClient:
53
60
  if self._settings.cause is not None:
54
61
  headers[CAUSE_HEADER] = self._settings.cause
55
62
  self._client = httpx.AsyncClient(
56
- base_url=self._settings.api_url,
63
+ base_url=self._base_url,
57
64
  headers=headers,
58
65
  auth=_BearerAuth(self._settings, self._token_override),
59
66
  timeout=DEFAULT_TIMEOUT,
@@ -30,6 +30,7 @@ from minitest_cli.utils.output import (
30
30
  print_table,
31
31
  )
32
32
 
33
+ EXIT_GENERAL_ERROR = 1
33
34
  EXIT_NETWORK_ERROR = 3
34
35
 
35
36
  app = typer.Typer(name="apps", help="App management.")
@@ -70,6 +71,9 @@ def list_apps() -> None:
70
71
  detail = body.get("detail") or body.get("message") or detail
71
72
  except Exception: # noqa: BLE001
72
73
  pass
74
+ if resp.status_code in (401, 403):
75
+ print_error(f"Authentication failed ({resp.status_code}): {detail}")
76
+ raise typer.Exit(code=EXIT_GENERAL_ERROR)
73
77
  print_error(f"API error ({resp.status_code}): {detail}")
74
78
  raise typer.Exit(code=EXIT_NETWORK_ERROR)
75
79
  return AppListResponse.model_validate(resp.json())
@@ -0,0 +1,111 @@
1
+ """`minitest draft`: ask Mini for a suite change and drive it to merge.
2
+
3
+ A draft is the workbench the webapp shows under Drafts: a branch of the suite plus
4
+ Mini's conversation about it. Mini is the only author of the branch; never `df apply`
5
+ into a draft's branch yourself.
6
+ """
7
+
8
+ from typing import Annotated
9
+
10
+ import typer
11
+
12
+ from minitest_cli.commands import (
13
+ draft_asks,
14
+ draft_conversation,
15
+ draft_create,
16
+ draft_legacy,
17
+ draft_lifecycle,
18
+ draft_pr,
19
+ draft_update,
20
+ )
21
+ from minitest_cli.commands.draft_helpers import (
22
+ DRAFTS_PATH,
23
+ call,
24
+ draft_path,
25
+ resolve_target,
26
+ run_conductor,
27
+ )
28
+ from minitest_cli.commands.draft_render import (
29
+ DRAFT_TABLE_HEADERS,
30
+ draft_row,
31
+ show_draft,
32
+ )
33
+ from minitest_cli.commands.draft_watch import WatchUntil, watch
34
+ from minitest_cli.utils.output import (
35
+ print_info,
36
+ print_json,
37
+ print_table,
38
+ )
39
+
40
+ app = typer.Typer(
41
+ name="draft",
42
+ help="Ask Mini for a suite change, follow the conversation, and check/merge the result.",
43
+ no_args_is_help=True,
44
+ )
45
+ EXIT_WATCH_TIMEOUT = 1
46
+
47
+
48
+ @app.command(name="list")
49
+ def list_drafts(
50
+ history: Annotated[
51
+ bool, typer.Option("--history", help="List merged and discarded drafts instead.")
52
+ ] = False,
53
+ ) -> None:
54
+ """List the active app's drafts (open ones by default)."""
55
+ target = resolve_target()
56
+ params = {"appId": target.app_id, "scope": "history" if history else "open"}
57
+ body = call(target, "GET", DRAFTS_PATH, retry=True, params=params)
58
+ drafts = body.get("drafts", [])
59
+ if target.json_mode:
60
+ print_json(drafts)
61
+ return
62
+ if not drafts:
63
+ print_info("No drafts found.")
64
+ return
65
+ print_table(
66
+ DRAFT_TABLE_HEADERS, [draft_row(d) for d in drafts], title=f"Drafts ({len(drafts)})"
67
+ )
68
+
69
+
70
+ @app.command(name="get")
71
+ def get_draft(
72
+ draft_id: Annotated[str, typer.Argument(help="Draft ID.")],
73
+ watch_flag: Annotated[
74
+ bool, typer.Option("--watch", help="Poll until the draft is stable, then print it.")
75
+ ] = False,
76
+ until: Annotated[
77
+ WatchUntil,
78
+ typer.Option(
79
+ "--until",
80
+ help="idle: Mini has nothing queued. settled: also no check or draft build running.",
81
+ ),
82
+ ] = WatchUntil.IDLE,
83
+ interval: Annotated[
84
+ float, typer.Option("--interval", min=1.0, help="Seconds between polls.")
85
+ ] = 5.0,
86
+ timeout: Annotated[
87
+ float, typer.Option("--timeout", min=1.0, help="Give up after this many seconds (exit 1).")
88
+ ] = 900.0,
89
+ ) -> None:
90
+ """Show a draft: state, Mini's status, scenarios and open asks."""
91
+ target = resolve_target()
92
+ path = draft_path(draft_id)
93
+ if not watch_flag:
94
+ show_draft(call(target, "GET", path, retry=True), json_mode=target.json_mode)
95
+ return
96
+ draft, stable = run_conductor(
97
+ watch(target, path, until=until, interval=interval, timeout=timeout)
98
+ )
99
+ show_draft(draft, json_mode=target.json_mode)
100
+ if not stable:
101
+ print_info(f"Still not {until.value} after {timeout:.0f}s; run the same command again.")
102
+ raise typer.Exit(code=EXIT_WATCH_TIMEOUT)
103
+
104
+
105
+ draft_create.register(app)
106
+ draft_update.register(app)
107
+ draft_conversation.register(app)
108
+ draft_lifecycle.register(app)
109
+ draft_pr.register(app)
110
+ app.add_typer(draft_asks.app)
111
+ draft_legacy.register(app)
@@ -0,0 +1,148 @@
1
+ """`minitest draft ask list|answer|decline`: answer what Mini asked on a draft.
2
+
3
+ Secret fields (``secret: true`` in an ask's answerFields) are only read from a file or
4
+ stdin (``--field-file KEY=PATH``, ``-`` for stdin) — never from the command line, where
5
+ shells and process lists keep them — and are never printed back.
6
+ """
7
+
8
+ from pathlib import Path
9
+ from typing import Annotated, Any
10
+
11
+ import typer
12
+
13
+ from minitest_cli.commands.draft_helpers import (
14
+ EXIT_GENERAL_ERROR,
15
+ EXIT_NOT_FOUND,
16
+ DraftTarget,
17
+ call,
18
+ draft_path,
19
+ resolve_target,
20
+ )
21
+ from minitest_cli.commands.draft_render import (
22
+ ASK_TABLE_HEADERS,
23
+ ask_fields,
24
+ read_file,
25
+ read_text,
26
+ show_draft,
27
+ )
28
+ from minitest_cli.commands.run_helpers import ensure_uuid
29
+ from minitest_cli.utils.output import (
30
+ print_error,
31
+ print_info,
32
+ print_json,
33
+ print_success,
34
+ print_table,
35
+ )
36
+
37
+ app = typer.Typer(
38
+ name="ask", help="Read and answer Mini's questions on a draft.", no_args_is_help=True
39
+ )
40
+ DraftIdArg = Annotated[str, typer.Argument(help="Draft ID.")]
41
+ AskIdArg = Annotated[str, typer.Argument(help="Ask ID (from `draft ask list`).")]
42
+
43
+
44
+ def _open_asks(target: DraftTarget, draft_id: str) -> list[dict[str, Any]]:
45
+ return call(target, "GET", draft_path(draft_id), retry=True).get("asks") or []
46
+
47
+
48
+ def _find_ask(target: DraftTarget, draft_id: str, ask_id: str) -> dict[str, Any]:
49
+ ensure_uuid(ask_id, kind="ask id")
50
+ for ask in _open_asks(target, draft_id):
51
+ if ask.get("id") == ask_id:
52
+ return ask
53
+ print_error(f"No open ask {ask_id} on draft {draft_id}; see `minitest draft ask list`.")
54
+ raise typer.Exit(code=EXIT_NOT_FOUND)
55
+
56
+
57
+ def _pair(raw: str, flag: str) -> tuple[str, str]:
58
+ key, sep, value = raw.partition("=")
59
+ if not sep or not key:
60
+ print_error(f"{flag} expects KEY=VALUE.")
61
+ raise typer.Exit(code=EXIT_GENERAL_ERROR)
62
+ return key, value
63
+
64
+
65
+ def _fields(ask: dict[str, Any], inline: list[str], files: list[str]) -> dict[str, str]:
66
+ known = {f["key"]: f for f in ask.get("answerFields") or []}
67
+ values: dict[str, str] = {}
68
+ for raw in inline:
69
+ key, value = _pair(raw, "--field")
70
+ if known.get(key, {}).get("secret"):
71
+ print_error(f"'{key}' is secret: pass it with --field-file {key}=PATH (- = stdin).")
72
+ raise typer.Exit(code=EXIT_GENERAL_ERROR)
73
+ values[key] = value
74
+ if sum(1 for raw in files if _pair(raw, "--field-file")[1] == "-") > 1:
75
+ print_error("Only one --field-file can read stdin.")
76
+ raise typer.Exit(code=EXIT_GENERAL_ERROR)
77
+ for raw in files:
78
+ key, path = _pair(raw, "--field-file")
79
+ values[key] = read_file(Path(path)).removesuffix("\n")
80
+ unknown = sorted(set(values) - set(known))
81
+ if unknown:
82
+ print_error(f"Unknown field(s) {', '.join(unknown)}; this ask takes: {ask_fields(ask)}.")
83
+ raise typer.Exit(code=EXIT_GENERAL_ERROR)
84
+ return values
85
+
86
+
87
+ @app.command(name="list")
88
+ def list_asks(draft_id: DraftIdArg) -> None:
89
+ """List Mini's open questions on a draft, with the fields each answer takes."""
90
+ target = resolve_target()
91
+ asks = _open_asks(target, draft_id)
92
+ if target.json_mode:
93
+ print_json(asks)
94
+ return
95
+ if not asks:
96
+ print_info("Mini is not asking anything.")
97
+ return
98
+ rows = [[a["id"], a.get("askType", "-"), a["question"], ask_fields(a)] for a in asks]
99
+ print_table(ASK_TABLE_HEADERS, rows)
100
+
101
+
102
+ @app.command(name="answer")
103
+ def answer_ask(
104
+ draft_id: DraftIdArg,
105
+ ask_id: AskIdArg,
106
+ answer: Annotated[str | None, typer.Option("--answer", help="Free-text answer.")] = None,
107
+ answer_file: Annotated[
108
+ Path | None, typer.Option("--answer-file", help="Read the answer from a file (- = stdin).")
109
+ ] = None,
110
+ field: Annotated[
111
+ list[str] | None, typer.Option("--field", help="KEY=VALUE for a non-secret field.")
112
+ ] = None,
113
+ field_file: Annotated[
114
+ list[str] | None,
115
+ typer.Option("--field-file", help="KEY=PATH, value read from a file (- = stdin)."),
116
+ ] = None,
117
+ ) -> None:
118
+ """Answer an ask; Mini resumes the draft with it. Turns auto-merge off."""
119
+ text = read_text(answer, answer_file, flag="answer", required=False)
120
+ target = resolve_target()
121
+ ask = _find_ask(target, draft_id, ask_id)
122
+ values = _fields(ask, field or [], field_file or [])
123
+ if text is None and not values:
124
+ print_error("Pass --answer/--answer-file, or the ask's fields with --field/--field-file.")
125
+ raise typer.Exit(code=EXIT_GENERAL_ERROR)
126
+ body: dict[str, object] = {}
127
+ if text is not None:
128
+ body["answer"] = text
129
+ if values:
130
+ body["fields"] = values
131
+ draft = call(target, "POST", draft_path(draft_id, f"/asks/{ask_id}/answer"), json=body)
132
+ print_success("Answered; Mini picks it up next.")
133
+ show_draft(draft, json_mode=target.json_mode)
134
+
135
+
136
+ @app.command(name="decline")
137
+ def decline_ask(
138
+ draft_id: DraftIdArg,
139
+ ask_id: AskIdArg,
140
+ reason: Annotated[str | None, typer.Option("--reason", help="Why, so Mini can adapt.")] = None,
141
+ ) -> None:
142
+ """Decline an ask; Mini carries on without it."""
143
+ target = resolve_target()
144
+ ensure_uuid(ask_id, kind="ask id")
145
+ body = {"reason": reason} if reason else None
146
+ draft = call(target, "POST", draft_path(draft_id, f"/asks/{ask_id}/decline"), json=body)
147
+ print_success("Declined.")
148
+ show_draft(draft, json_mode=target.json_mode)
@@ -0,0 +1,84 @@
1
+ """`minitest draft message|messages|stop`: talk to Mini about a draft."""
2
+
3
+ import uuid
4
+ from pathlib import Path
5
+ from typing import Annotated, Any
6
+
7
+ import typer
8
+
9
+ from minitest_cli.commands.draft_helpers import call, draft_path, resolve_target
10
+ from minitest_cli.commands.draft_render import MESSAGE_TABLE_HEADERS, read_text
11
+ from minitest_cli.utils.output import print_info, print_json, print_success, print_table
12
+
13
+
14
+ def _message_row(message: dict[str, Any]) -> list[str]:
15
+ return [str(message.get("createdAt", "-")), str(message.get("role", "-")), message["content"]]
16
+
17
+
18
+ def register(app: typer.Typer) -> None:
19
+ @app.command(name="message")
20
+ def post_message(
21
+ draft_id: Annotated[str, typer.Argument(help="Draft ID.")],
22
+ message: Annotated[str | None, typer.Option("--message", help="What to tell Mini.")] = None,
23
+ message_file: Annotated[
24
+ Path | None,
25
+ typer.Option("--message-file", help="Read the message from a file (- = stdin)."),
26
+ ] = None,
27
+ client_message_id: Annotated[
28
+ str | None,
29
+ typer.Option(
30
+ "--client-message-id", help="Re-send with the same id to never post it twice."
31
+ ),
32
+ ] = None,
33
+ ) -> None:
34
+ """Send Mini a follow-up message; Mini answers it in the background, in order."""
35
+ text = read_text(message, message_file, flag="message", required=True)
36
+ target = resolve_target()
37
+ message_id = client_message_id or f"cli-{uuid.uuid4()}"
38
+ posted = call(
39
+ target,
40
+ "POST",
41
+ draft_path(draft_id, "/messages"),
42
+ retry=True,
43
+ json={"message": text, "clientMessageId": message_id},
44
+ )
45
+ if target.json_mode:
46
+ print_json(posted)
47
+ return
48
+ verb = "Sent" if posted.get("created") else "Already sent"
49
+ print_success(f"{verb} (client message id: {message_id}).")
50
+ print_info(f"Wait for Mini's reply with `minitest draft get {draft_id} --watch`.")
51
+
52
+ @app.command(name="messages")
53
+ def list_messages(
54
+ draft_id: Annotated[str, typer.Argument(help="Draft ID.")],
55
+ last: Annotated[
56
+ int | None, typer.Option("--last", min=1, help="Only the last N messages.")
57
+ ] = None,
58
+ ) -> None:
59
+ """Read the conversation with Mini, oldest first."""
60
+ target = resolve_target()
61
+ body = call(target, "GET", draft_path(draft_id, "/messages"), retry=True)
62
+ messages = body.get("messages", [])
63
+ if last is not None:
64
+ messages = messages[-last:]
65
+ if target.json_mode:
66
+ print_json(messages)
67
+ return
68
+ if not messages:
69
+ print_info("No messages yet.")
70
+ return
71
+ print_table(MESSAGE_TABLE_HEADERS, [_message_row(m) for m in messages])
72
+
73
+ @app.command(name="stop")
74
+ def stop_turn(draft_id: Annotated[str, typer.Argument(help="Draft ID.")]) -> None:
75
+ """Interrupt what Mini is writing right now."""
76
+ target = resolve_target()
77
+ body = call(target, "POST", draft_path(draft_id, "/stop"))
78
+ if target.json_mode:
79
+ print_json(body)
80
+ return
81
+ if body.get("stopped"):
82
+ print_success("Mini stopped.")
83
+ else:
84
+ print_info("Mini was not writing.")
@@ -0,0 +1,66 @@
1
+ """`minitest draft create`: open a draft with a first message for Mini."""
2
+
3
+ import uuid
4
+ from pathlib import Path
5
+ from typing import Annotated
6
+
7
+ import typer
8
+
9
+ from minitest_cli.commands.draft_helpers import DRAFTS_PATH, call, resolve_target
10
+ from minitest_cli.commands.draft_render import read_text, show_draft
11
+ from minitest_cli.utils.output import print_info, print_success, print_warning
12
+
13
+
14
+ def register(app: typer.Typer) -> None:
15
+ @app.command(name="create")
16
+ def create_draft(
17
+ message: Annotated[
18
+ str | None, typer.Option("--message", help="What you want Mini to change.")
19
+ ] = None,
20
+ message_file: Annotated[
21
+ Path | None,
22
+ typer.Option("--message-file", help="Read the message from a file (- = stdin)."),
23
+ ] = None,
24
+ title: Annotated[
25
+ str | None, typer.Option("--title", help="Draft title (Mini names it otherwise).")
26
+ ] = None,
27
+ auto_check: Annotated[
28
+ bool,
29
+ typer.Option("--auto-check/--no-auto-check", help="Check each change Mini writes."),
30
+ ] = False,
31
+ auto_merge: Annotated[
32
+ bool,
33
+ typer.Option(
34
+ "--auto-merge/--no-auto-merge", help="Merge on its own once proven and ready."
35
+ ),
36
+ ] = False,
37
+ idempotency_key: Annotated[
38
+ str | None,
39
+ typer.Option(
40
+ "--idempotency-key", help="Re-run with the same key to get the same draft back."
41
+ ),
42
+ ] = None,
43
+ ) -> None:
44
+ """Open a draft with a first message; Mini starts working on it right away."""
45
+ text = read_text(message, message_file, flag="message", required=True)
46
+ if auto_merge and not auto_check:
47
+ print_warning(
48
+ "--auto-merge only merges proven changes; add --auto-check or run `draft check`."
49
+ )
50
+ target = resolve_target()
51
+ key = idempotency_key or f"cli-{uuid.uuid4()}"
52
+ body: dict[str, object] = {
53
+ "tenantId": target.tenant_id,
54
+ "appId": target.app_id,
55
+ "message": text,
56
+ "autoCheck": auto_check,
57
+ "autoMerge": auto_merge,
58
+ "idempotencyKey": key,
59
+ }
60
+ if title is not None:
61
+ body["title"] = title
62
+ draft = call(target, "POST", DRAFTS_PATH, retry=True, json=body)
63
+ print_success(f"Draft {draft['id']} opened; Mini is on it.")
64
+ print_info(f"Idempotency key: {key} — reuse it with --idempotency-key to retry safely.")
65
+ print_info(f"Follow it with `minitest draft get {draft['id']} --watch`.")
66
+ show_draft(draft, json_mode=target.json_mode)
@@ -1,7 +1,8 @@
1
- """Draft-feature commands: list, create, delete.
1
+ """Low-level draft-feature commands (`minitest df`): list, create, delete.
2
2
 
3
3
  A draft feature is a branch of the app's test suite — it holds a delta against
4
4
  main rather than a copy of it, so `show` is the only way to see what it changes.
5
+ Mini writes these branches; customer agents work with Mini through `minitest draft`.
5
6
  """
6
7
 
7
8
  import json
@@ -11,7 +12,6 @@ import typer
11
12
 
12
13
  from minitest_cli.api.client import ApiClient
13
14
  from minitest_cli.commands import draft_feature_apply, draft_feature_show
14
- from minitest_cli.commands.deprecated_alias import deprecated_alias
15
15
  from minitest_cli.commands.draft_feature_helpers import (
16
16
  DRAFT_FEATURE_TABLE_HEADERS,
17
17
  base_path,
@@ -22,7 +22,13 @@ from minitest_cli.commands.run_helpers import ensure_uuid, resolve_app, run_api_
22
22
  from minitest_cli.models.draft_feature import DraftFeatureResponse, DraftFeatureStatus
23
23
  from minitest_cli.utils.output import output, print_error, print_info, print_success, print_table
24
24
 
25
- app = typer.Typer(name="draft", help="Drafts — branches of the app's test suite.")
25
+ app = typer.Typer(
26
+ name="df",
27
+ help=(
28
+ "Low-level branches of the app's test suite (draft features). "
29
+ "To ask Mini for a change, use `minitest draft`."
30
+ ),
31
+ )
26
32
  draft_feature_show.register(app)
27
33
  draft_feature_apply.register(app)
28
34
 
@@ -116,6 +122,3 @@ def delete_draft_feature(
116
122
  output(feature.model_dump(mode="json", by_alias=True), json_mode=True)
117
123
  else:
118
124
  print_success(f"Draft abandoned: {feature.id} (status: {feature.status.value})")
119
-
120
-
121
- legacy_app = deprecated_alias(app, old_name="df")
@@ -1,4 +1,4 @@
1
- """`minitest draft apply` — post a changeset file to a branch."""
1
+ """`minitest df apply` — post a changeset file to a branch."""
2
2
 
3
3
  from pathlib import Path
4
4
  from typing import Annotated
@@ -1,4 +1,4 @@
1
- """Rendering for `minitest draft show --view conflicts`.
1
+ """Rendering for `minitest df show --view conflicts`.
2
2
 
3
3
  The three sides of a conflict are whole story tuples, so printing them as three
4
4
  JSON blobs in a table makes the one thing a resolver needs — which key is in
@@ -59,9 +59,7 @@ def handle_response_error(resp: httpx.Response, *, resource: str = "Draft featur
59
59
  if resp.status_code == 409:
60
60
  detail = extract_detail(resp)
61
61
  print_error(detail or f"{resource} changed since it was read.")
62
- print_info(
63
- "Re-run `draft show --view diff`, rebuild against the mainRev it returns, retry."
64
- )
62
+ print_info("Re-run `df show --view diff`, rebuild against the mainRev it returns, retry.")
65
63
  raise typer.Exit(code=EXIT_CONFLICT)
66
64
  if resp.status_code >= 400:
67
65
  detail = extract_detail(resp)
@@ -1,4 +1,4 @@
1
- """`minitest draft show` — read a branch as a diff, as the suite it runs, or as its conflicts."""
1
+ """`minitest df show` — read a branch as a diff, as the suite it runs, or as its conflicts."""
2
2
 
3
3
  from enum import StrEnum
4
4
  from typing import Annotated