base-cli 0.4.2__tar.gz → 0.4.3__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 (209) hide show
  1. {base_cli-0.4.2 → base_cli-0.4.3}/.github/workflows/compatibility.yml +10 -1
  2. base_cli-0.4.3/.github/workflows/dependency-matrix.yml +48 -0
  3. {base_cli-0.4.2 → base_cli-0.4.3}/.github/workflows/docs.yml +18 -1
  4. {base_cli-0.4.2 → base_cli-0.4.3}/.github/workflows/package.yml +109 -1
  5. {base_cli-0.4.2 → base_cli-0.4.3}/.github/workflows/tests.yml +8 -1
  6. {base_cli-0.4.2 → base_cli-0.4.3}/CHANGELOG.md +78 -0
  7. {base_cli-0.4.2 → base_cli-0.4.3}/PKG-INFO +41 -12
  8. {base_cli-0.4.2 → base_cli-0.4.3}/README.md +32 -8
  9. base_cli-0.4.3/VERSION +1 -0
  10. {base_cli-0.4.2 → base_cli-0.4.3}/compatibility/README.md +12 -5
  11. {base_cli-0.4.2 → base_cli-0.4.3}/docs/adopter-readiness.md +8 -7
  12. base_cli-0.4.3/docs/adoption-evidence.md +67 -0
  13. base_cli-0.4.3/docs/api-reference.md +1974 -0
  14. {base_cli-0.4.2 → base_cli-0.4.3}/docs/api-stability.md +11 -7
  15. {base_cli-0.4.2 → base_cli-0.4.3}/docs/cache-ownership-and-layout.md +3 -2
  16. base_cli-0.4.3/docs/compatibility-dashboard.md +53 -0
  17. {base_cli-0.4.2 → base_cli-0.4.3}/docs/consumer-profiles.md +5 -3
  18. base_cli-0.4.3/docs/coverage-policy.md +22 -0
  19. base_cli-0.4.3/docs/dependency-support.md +41 -0
  20. {base_cli-0.4.2 → base_cli-0.4.3}/docs/extensions.md +29 -0
  21. base_cli-0.4.3/docs/framework-choice.md +45 -0
  22. {base_cli-0.4.2 → base_cli-0.4.3}/docs/index.md +18 -4
  23. {base_cli-0.4.2 → base_cli-0.4.3}/docs/json-contracts.md +11 -0
  24. {base_cli-0.4.2 → base_cli-0.4.3}/docs/local-config.md +2 -1
  25. base_cli-0.4.3/docs/migration-argparse.md +70 -0
  26. base_cli-0.4.3/docs/migration-cement.md +80 -0
  27. base_cli-0.4.3/docs/migration-click.md +75 -0
  28. base_cli-0.4.3/docs/migration-typer.md +72 -0
  29. base_cli-0.4.3/docs/migrations.md +93 -0
  30. {base_cli-0.4.2 → base_cli-0.4.3}/docs/output-contracts.md +16 -2
  31. {base_cli-0.4.2 → base_cli-0.4.3}/docs/platform-support.md +12 -0
  32. {base_cli-0.4.2 → base_cli-0.4.3}/docs/releasing.md +60 -4
  33. base_cli-0.4.3/docs/schemas.md +33 -0
  34. {base_cli-0.4.2 → base_cli-0.4.3}/docs/security-threat-model.md +1 -1
  35. {base_cli-0.4.2 → base_cli-0.4.3}/docs/typer-adapter.md +2 -2
  36. {base_cli-0.4.2 → base_cli-0.4.3}/examples/nested_click_app/README.md +2 -1
  37. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/__init__.py +24 -0
  38. base_cli-0.4.3/lib/python/base_cli/_app_core.py +1567 -0
  39. base_cli-0.4.3/lib/python/base_cli/_attach.py +613 -0
  40. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/_click_compat.py +19 -1
  41. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/_dependencies.py +4 -2
  42. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/_lifecycle.py +9 -12
  43. base_cli-0.4.3/lib/python/base_cli/_lifecycle_install.py +854 -0
  44. base_cli-0.4.3/lib/python/base_cli/_run.py +431 -0
  45. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/_runtime.py +1 -1
  46. base_cli-0.4.3/lib/python/base_cli/app.py +31 -0
  47. base_cli-0.4.3/lib/python/base_cli/asyncio_adapter.py +39 -0
  48. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/command_protocol.py +12 -1
  49. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/config.py +4 -1
  50. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/extensions.py +70 -1
  51. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/history.py +55 -11
  52. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/json_contracts.py +5 -1
  53. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/output.py +62 -10
  54. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/redaction.py +24 -3
  55. base_cli-0.4.3/lib/python/base_cli/schemas/v1/command-protocol.schema.json +15 -0
  56. base_cli-0.4.3/lib/python/base_cli/schemas/v1/error.schema.json +17 -0
  57. base_cli-0.4.3/lib/python/base_cli/schemas/v1/inspection.schema.json +15 -0
  58. base_cli-0.4.3/lib/python/base_cli/schemas/v1/log.schema.json +18 -0
  59. base_cli-0.4.3/lib/python/base_cli/schemas/v1/ndjson.schema.json +13 -0
  60. base_cli-0.4.3/lib/python/base_cli/schemas/v1/output.schema.json +17 -0
  61. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/testing.py +4 -4
  62. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli.egg-info/PKG-INFO +41 -12
  63. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli.egg-info/SOURCES.txt +42 -1
  64. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli.egg-info/requires.txt +5 -2
  65. {base_cli-0.4.2 → base_cli-0.4.3}/pyproject.toml +23 -4
  66. base_cli-0.4.3/scripts/generate_api_reference.py +148 -0
  67. base_cli-0.4.3/scripts/generate_compatibility_dashboard.py +176 -0
  68. base_cli-0.4.3/scripts/generate_release_metadata.py +150 -0
  69. base_cli-0.4.3/scripts/record_compatibility_evidence.py +58 -0
  70. base_cli-0.4.3/scripts/validate_changelog.py +129 -0
  71. {base_cli-0.4.2 → base_cli-0.4.3}/scripts/validate_consumers.py +2 -2
  72. base_cli-0.4.3/scripts/validate_contract_fixtures.py +98 -0
  73. base_cli-0.4.3/scripts/validate_coverage.py +72 -0
  74. {base_cli-0.4.2 → base_cli-0.4.3}/scripts/validate_docs.py +51 -1
  75. {base_cli-0.4.2 → base_cli-0.4.3}/scripts/validate_package_artifact.py +15 -1
  76. base_cli-0.4.3/scripts/validate_release_metadata.py +69 -0
  77. base_cli-0.4.3/scripts/validate_release_ref.py +60 -0
  78. base_cli-0.4.3/scripts/validate_schemas.py +61 -0
  79. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_adversarial_regressions.py +6 -2
  80. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_api_stability.py +12 -0
  81. base_cli-0.4.3/tests/test_app_module_boundaries.py +28 -0
  82. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_app_run_metadata.py +11 -8
  83. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_command_protocol.py +38 -0
  84. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_extensions.py +50 -1
  85. base_cli-0.4.3/tests/test_generate_compatibility_dashboard.py +36 -0
  86. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_generic_core.py +27 -0
  87. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_history.py +26 -0
  88. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_json_contracts.py +169 -0
  89. base_cli-0.4.3/tests/test_optional_yaml_dependency.py +42 -0
  90. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_output.py +100 -6
  91. base_cli-0.4.3/tests/test_platform_edge_paths.py +209 -0
  92. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_public_api.py +3 -0
  93. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_redaction_security.py +60 -0
  94. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_run_bundle_retention.py +16 -0
  95. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_testing.py +40 -0
  96. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_typed_contracts.py +37 -0
  97. base_cli-0.4.3/tests/test_validate_changelog.py +64 -0
  98. base_cli-0.4.3/tests/test_validate_docs.py +33 -0
  99. base_cli-0.4.3/tests/test_validate_release_ref.py +57 -0
  100. base_cli-0.4.3/tests/test_validate_schemas.py +42 -0
  101. base_cli-0.4.2/VERSION +0 -1
  102. base_cli-0.4.2/docs/migrations.md +0 -53
  103. base_cli-0.4.2/lib/python/base_cli/app.py +0 -3175
  104. {base_cli-0.4.2 → base_cli-0.4.3}/.github/ISSUE_TEMPLATE/support.md +0 -0
  105. {base_cli-0.4.2 → base_cli-0.4.3}/.github/base-project.yml +0 -0
  106. {base_cli-0.4.2 → base_cli-0.4.3}/.github/pull_request_template.md +0 -0
  107. {base_cli-0.4.2 → base_cli-0.4.3}/.github/workflows/examples.yml +0 -0
  108. {base_cli-0.4.2 → base_cli-0.4.3}/.github/workflows/issue-branch-policy.yml +0 -0
  109. {base_cli-0.4.2 → base_cli-0.4.3}/.github/workflows/project-intake.yml +0 -0
  110. {base_cli-0.4.2 → base_cli-0.4.3}/CONTRIBUTING.md +0 -0
  111. {base_cli-0.4.2 → base_cli-0.4.3}/LICENSE +0 -0
  112. {base_cli-0.4.2 → base_cli-0.4.3}/MANIFEST.in +0 -0
  113. {base_cli-0.4.2 → base_cli-0.4.3}/SECURITY.md +0 -0
  114. {base_cli-0.4.2 → base_cli-0.4.3}/base_manifest.yaml +0 -0
  115. {base_cli-0.4.2 → base_cli-0.4.3}/compatibility/consumers/atlas_click/README.md +0 -0
  116. {base_cli-0.4.2 → base_cli-0.4.3}/compatibility/consumers/atlas_click/pyproject.toml +0 -0
  117. {base_cli-0.4.2 → base_cli-0.4.3}/compatibility/consumers/atlas_click/src/atlas_click/__init__.py +0 -0
  118. {base_cli-0.4.2 → base_cli-0.4.3}/compatibility/consumers/atlas_click/src/atlas_click/cli.py +0 -0
  119. {base_cli-0.4.2 → base_cli-0.4.3}/compatibility/consumers/atlas_click/tests/test_consumer.py +0 -0
  120. {base_cli-0.4.2 → base_cli-0.4.3}/compatibility/consumers/beacon_typer/README.md +0 -0
  121. {base_cli-0.4.2 → base_cli-0.4.3}/compatibility/consumers/beacon_typer/pyproject.toml +0 -0
  122. {base_cli-0.4.2 → base_cli-0.4.3}/compatibility/consumers/beacon_typer/src/beacon_typer/__init__.py +0 -0
  123. {base_cli-0.4.2 → base_cli-0.4.3}/compatibility/consumers/beacon_typer/src/beacon_typer/cli.py +0 -0
  124. {base_cli-0.4.2 → base_cli-0.4.3}/compatibility/consumers/beacon_typer/tests/test_consumer.py +0 -0
  125. {base_cli-0.4.2 → base_cli-0.4.3}/compatibility/consumers/cinder_automation/README.md +0 -0
  126. {base_cli-0.4.2 → base_cli-0.4.3}/compatibility/consumers/cinder_automation/pyproject.toml +0 -0
  127. {base_cli-0.4.2 → base_cli-0.4.3}/compatibility/consumers/cinder_automation/src/cinder_automation/__init__.py +0 -0
  128. {base_cli-0.4.2 → base_cli-0.4.3}/compatibility/consumers/cinder_automation/src/cinder_automation/cli.py +0 -0
  129. {base_cli-0.4.2 → base_cli-0.4.3}/compatibility/consumers/cinder_automation/tests/test_consumer.py +0 -0
  130. {base_cli-0.4.2 → base_cli-0.4.3}/compatibility/consumers/manifest.json +0 -0
  131. {base_cli-0.4.2 → base_cli-0.4.3}/docs/integrations.md +0 -0
  132. {base_cli-0.4.2 → base_cli-0.4.3}/docs/performance.md +0 -0
  133. {base_cli-0.4.2 → base_cli-0.4.3}/docs/security-review.md +0 -0
  134. {base_cli-0.4.2 → base_cli-0.4.3}/docs/user-config-typing.md +0 -0
  135. {base_cli-0.4.2 → base_cli-0.4.3}/examples/README.md +0 -0
  136. {base_cli-0.4.2 → base_cli-0.4.3}/examples/automation_observability_app/README.md +0 -0
  137. {base_cli-0.4.2 → base_cli-0.4.3}/examples/automation_observability_app/pyproject.toml +0 -0
  138. {base_cli-0.4.2 → base_cli-0.4.3}/examples/automation_observability_app/src/automation_observability_app/__init__.py +0 -0
  139. {base_cli-0.4.2 → base_cli-0.4.3}/examples/automation_observability_app/src/automation_observability_app/cli.py +0 -0
  140. {base_cli-0.4.2 → base_cli-0.4.3}/examples/automation_observability_app/tests/test_cli.py +0 -0
  141. {base_cli-0.4.2 → base_cli-0.4.3}/examples/minimal_cli/README.md +0 -0
  142. {base_cli-0.4.2 → base_cli-0.4.3}/examples/minimal_cli/pyproject.toml +0 -0
  143. {base_cli-0.4.2 → base_cli-0.4.3}/examples/minimal_cli/src/minimal_cli/__init__.py +0 -0
  144. {base_cli-0.4.2 → base_cli-0.4.3}/examples/minimal_cli/src/minimal_cli/cli.py +0 -0
  145. {base_cli-0.4.2 → base_cli-0.4.3}/examples/minimal_cli/tests/test_cli.py +0 -0
  146. {base_cli-0.4.2 → base_cli-0.4.3}/examples/nested_click_app/pyproject.toml +0 -0
  147. {base_cli-0.4.2 → base_cli-0.4.3}/examples/nested_click_app/src/nested_click_app/__init__.py +0 -0
  148. {base_cli-0.4.2 → base_cli-0.4.3}/examples/nested_click_app/src/nested_click_app/cli.py +0 -0
  149. {base_cli-0.4.2 → base_cli-0.4.3}/examples/nested_click_app/src/nested_click_app/plugin.py +0 -0
  150. {base_cli-0.4.2 → base_cli-0.4.3}/examples/nested_click_app/tests/test_cli.py +0 -0
  151. {base_cli-0.4.2 → base_cli-0.4.3}/examples/typed_consumer.py +0 -0
  152. {base_cli-0.4.2 → base_cli-0.4.3}/examples/typer_app/README.md +0 -0
  153. {base_cli-0.4.2 → base_cli-0.4.3}/examples/typer_app/pyproject.toml +0 -0
  154. {base_cli-0.4.2 → base_cli-0.4.3}/examples/typer_app/src/typer_app/__init__.py +0 -0
  155. {base_cli-0.4.2 → base_cli-0.4.3}/examples/typer_app/src/typer_app/cli.py +0 -0
  156. {base_cli-0.4.2 → base_cli-0.4.3}/examples/typer_app/tests/test_cli.py +0 -0
  157. {base_cli-0.4.2 → base_cli-0.4.3}/examples/typer_consumer.py +0 -0
  158. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/_cleanup.py +0 -0
  159. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/_private_files.py +0 -0
  160. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/attachment.py +0 -0
  161. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/command_filters.py +0 -0
  162. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/context.py +0 -0
  163. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/deprecations.py +0 -0
  164. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/errors.py +0 -0
  165. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/exit_codes.py +0 -0
  166. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/experimental.py +0 -0
  167. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/inspection.py +0 -0
  168. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/integrations.py +0 -0
  169. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/lifecycle_options.py +0 -0
  170. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/logging.py +0 -0
  171. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/paths.py +0 -0
  172. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/profile.py +0 -0
  173. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/py.typed +0 -0
  174. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/runtime.py +0 -0
  175. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli/typer.py +0 -0
  176. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli.egg-info/dependency_links.txt +0 -0
  177. {base_cli-0.4.2 → base_cli-0.4.3}/lib/python/base_cli.egg-info/top_level.txt +0 -0
  178. {base_cli-0.4.2 → base_cli-0.4.3}/scripts/benchmark_runtime.py +0 -0
  179. {base_cli-0.4.2 → base_cli-0.4.3}/scripts/validate_examples.py +0 -0
  180. {base_cli-0.4.2 → base_cli-0.4.3}/scripts/validate_installed_package.py +0 -0
  181. {base_cli-0.4.2 → base_cli-0.4.3}/setup.cfg +0 -0
  182. {base_cli-0.4.2 → base_cli-0.4.3}/tests/conftest.py +0 -0
  183. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_app_dry_run.py +0 -0
  184. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_app_lifecycle.py +0 -0
  185. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_app_log_retention.py +0 -0
  186. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_app_quiet.py +0 -0
  187. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_app_registration.py +0 -0
  188. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_app_run.py +0 -0
  189. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_app_runtime_boundary.py +0 -0
  190. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_app_runtime_errors.py +0 -0
  191. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_app_security_boundaries.py +0 -0
  192. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_app_startup_transaction.py +0 -0
  193. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_app_subcommands.py +0 -0
  194. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_batteries_included_config.py +0 -0
  195. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_benchmark_runtime.py +0 -0
  196. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_cleanup_security.py +0 -0
  197. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_click_tree_attachment.py +0 -0
  198. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_command_filters.py +0 -0
  199. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_context_workspace.py +0 -0
  200. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_explicit_config_validation.py +0 -0
  201. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_inspection.py +0 -0
  202. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_integrations.py +0 -0
  203. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_invocation_parity.py +0 -0
  204. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_lifecycle_options.py +0 -0
  205. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_logging.py +0 -0
  206. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_paths.py +0 -0
  207. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_profile.py +0 -0
  208. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_security_documentation.py +0 -0
  209. {base_cli-0.4.2 → base_cli-0.4.3}/tests/test_typer_adapter.py +0 -0
@@ -20,7 +20,7 @@ jobs:
20
20
  fail-fast: false
21
21
  matrix:
22
22
  python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
23
- typer-version: ["0.25.1", "0.26.0", "0.27.1"]
23
+ typer-version: ["0.25.1", "0.26.0", "0.27.1", "0.27.2"]
24
24
  steps:
25
25
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
26
26
  - name: Set up Python
@@ -66,3 +66,12 @@ jobs:
66
66
  for tests in compatibility/consumers/*/tests; do
67
67
  python -m pytest "$tests"
68
68
  done
69
+ - name: Record dated compatibility evidence
70
+ run: python scripts/record_compatibility_evidence.py > compatibility-evidence.json
71
+ - name: Upload compatibility evidence
72
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
73
+ with:
74
+ name: base-cli-compatibility-evidence-${{ github.run_id }}
75
+ path: compatibility-evidence.json
76
+ if-no-files-found: error
77
+ retention-days: 90
@@ -0,0 +1,48 @@
1
+ name: Dependency compatibility
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ concurrency:
11
+ group: ${{ github.workflow }}-${{ github.ref }}
12
+ cancel-in-progress: true
13
+
14
+ jobs:
15
+ core:
16
+ name: Click ${{ matrix.click-version }} / PyYAML ${{ matrix.pyyaml-version }} / Python ${{ matrix.python-version }}
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 15
19
+ strategy:
20
+ fail-fast: false
21
+ matrix:
22
+ python-version: ["3.10", "3.14"]
23
+ click-version: ["8.1.*", "8.2.*", "8.3.*", "8.4.*"]
24
+ pyyaml-version: ["6.0.*"]
25
+ steps:
26
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
27
+ - name: Set up Python
28
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
29
+ with:
30
+ python-version: ${{ matrix.python-version }}
31
+ - name: Install framework and test dependencies
32
+ run: python -m pip install "setuptools<77" "wheel" ".[dev]"
33
+ - name: Select tested core dependency lines
34
+ run: |
35
+ python -m pip install --upgrade --force-reinstall \
36
+ "click==${{ matrix.click-version }}" \
37
+ "PyYAML==${{ matrix.pyyaml-version }}"
38
+ - name: Verify resolved dependency contract
39
+ run: |
40
+ python - <<'PY'
41
+ from importlib.metadata import version
42
+
43
+ click_version = version("click")
44
+ yaml_version = version("PyYAML")
45
+ print(f"Click {click_version}; PyYAML {yaml_version}")
46
+ PY
47
+ - name: Run core suite
48
+ run: python -m pytest
@@ -11,6 +11,16 @@ on:
11
11
  - "mkdocs.yml"
12
12
  - "pyproject.toml"
13
13
  - "scripts/validate_docs.py"
14
+ - "scripts/validate_changelog.py"
15
+ - "scripts/generate_compatibility_dashboard.py"
16
+ - ".github/workflows/tests.yml"
17
+ - ".github/workflows/dependency-matrix.yml"
18
+ - ".github/workflows/compatibility.yml"
19
+ - "scripts/generate_api_reference.py"
20
+ - "scripts/generate_compatibility_dashboard.py"
21
+ - ".github/workflows/tests.yml"
22
+ - ".github/workflows/dependency-matrix.yml"
23
+ - ".github/workflows/compatibility.yml"
14
24
  - "tests/validate.sh"
15
25
  - ".github/workflows/docs.yml"
16
26
  pull_request:
@@ -21,6 +31,7 @@ on:
21
31
  - "mkdocs.yml"
22
32
  - "pyproject.toml"
23
33
  - "scripts/validate_docs.py"
34
+ - "scripts/generate_api_reference.py"
24
35
  - "tests/validate.sh"
25
36
  - ".github/workflows/docs.yml"
26
37
  workflow_dispatch:
@@ -50,7 +61,13 @@ jobs:
50
61
  run: python -m pip install ".[docs]"
51
62
 
52
63
  - name: Validate repository links and examples
53
- run: python scripts/validate_docs.py
64
+ run: |
65
+ python scripts/validate_docs.py
66
+ python scripts/validate_changelog.py
67
+ python scripts/generate_compatibility_dashboard.py --check
68
+
69
+ - name: Validate generated public API reference
70
+ run: python scripts/generate_api_reference.py --check
54
71
 
55
72
  - name: Build documentation with strict warnings
56
73
  run: python -m mkdocs build --strict --site-dir site
@@ -12,6 +12,11 @@ on:
12
12
  - "scripts/validate_package_artifact.py"
13
13
  - "scripts/validate_installed_package.py"
14
14
  - "scripts/validate_examples.py"
15
+ - "scripts/generate_release_metadata.py"
16
+ - "scripts/validate_release_metadata.py"
17
+ - "scripts/validate_changelog.py"
18
+ - "scripts/validate_release_ref.py"
19
+ - "CHANGELOG.md"
15
20
  - "examples/**"
16
21
  - "compatibility/**"
17
22
  - "docs/releasing.md"
@@ -78,6 +83,15 @@ jobs:
78
83
  - name: Validate repository baseline
79
84
  run: ./tests/validate.sh
80
85
 
86
+ - name: Validate changelog
87
+ run: python scripts/validate_changelog.py
88
+
89
+ - name: Validate tagged release notes
90
+ if: ${{ github.ref_type == 'tag' }}
91
+ env:
92
+ RELEASE_TAG: ${{ github.ref_name }}
93
+ run: python scripts/validate_release_ref.py
94
+
81
95
  - name: Prepare clean artifact destination
82
96
  run: |
83
97
  git clean -ffdx
@@ -95,14 +109,37 @@ jobs:
95
109
  - name: Validate package indexes
96
110
  run: python -m twine check dist/*
97
111
 
112
+ - name: Generate release checksums and SPDX SBOM
113
+ env:
114
+ SOURCE_REVISION: ${{ github.sha }}
115
+ SOURCE_DATE_EPOCH: ${{ github.event.head_commit.timestamp || '0' }}
116
+ run: python scripts/generate_release_metadata.py dist
117
+
118
+ - name: Validate release checksums and SPDX SBOM
119
+ env:
120
+ SOURCE_REVISION: ${{ github.sha }}
121
+ run: python scripts/validate_release_metadata.py dist
122
+
98
123
  - name: Upload reviewed distributions
99
124
  uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
100
125
  with:
101
126
  name: base-cli-dist-${{ github.run_id }}
102
- path: dist/*
127
+ path: |
128
+ dist/*.whl
129
+ dist/*.tar.gz
103
130
  if-no-files-found: error
104
131
  retention-days: 14
105
132
 
133
+ - name: Upload release metadata
134
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
135
+ with:
136
+ name: base-cli-release-metadata-${{ github.run_id }}
137
+ path: |
138
+ dist/SBOM.spdx.json
139
+ dist/SHA256SUMS
140
+ if-no-files-found: error
141
+ retention-days: 90
142
+
106
143
  smoke:
107
144
  name: Install smoke test (Python ${{ matrix.python-version }})
108
145
  needs: build
@@ -184,3 +221,74 @@ jobs:
184
221
  uses: pypa/gh-action-pypi-publish@4bb033805d9e19112d8c697528791ff53f6c2f74
185
222
  with:
186
223
  packages-dir: dist
224
+
225
+ attest:
226
+ name: Attest reviewed release
227
+ needs: [build, smoke]
228
+ if: ${{ (github.event_name == 'push' && github.ref_type == 'tag') || github.event_name == 'workflow_dispatch' }}
229
+ runs-on: ubuntu-latest
230
+ timeout-minutes: 10
231
+ permissions:
232
+ contents: read
233
+ id-token: write
234
+ attestations: write
235
+ steps:
236
+ - name: Download reviewed distributions
237
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
238
+ with:
239
+ name: base-cli-dist-${{ github.run_id }}
240
+ path: dist
241
+
242
+ - name: Download release metadata
243
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
244
+ with:
245
+ name: base-cli-release-metadata-${{ github.run_id }}
246
+ path: dist
247
+
248
+ - name: Attest artifact provenance
249
+ uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4
250
+ with:
251
+ subject-checksums: dist/SHA256SUMS
252
+
253
+ - name: Attest SPDX SBOM
254
+ uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4
255
+ with:
256
+ subject-checksums: dist/SHA256SUMS
257
+ sbom-path: dist/SBOM.spdx.json
258
+
259
+ release:
260
+ name: Create GitHub Release
261
+ needs: [build, smoke, publish, attest]
262
+ if: ${{ github.event_name == 'push' && github.ref_type == 'tag' }}
263
+ runs-on: ubuntu-latest
264
+ timeout-minutes: 10
265
+ permissions:
266
+ contents: write
267
+ steps:
268
+ - name: Download reviewed distributions
269
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
270
+ with:
271
+ name: base-cli-dist-${{ github.run_id }}
272
+ path: dist
273
+
274
+ - name: Download release metadata
275
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
276
+ with:
277
+ name: base-cli-release-metadata-${{ github.run_id }}
278
+ path: dist
279
+
280
+ - name: Create or update GitHub Release
281
+ env:
282
+ GH_TOKEN: ${{ github.token }}
283
+ run: |
284
+ tag="$GITHUB_REF_NAME"
285
+ assets=(dist/*.whl dist/*.tar.gz dist/SHA256SUMS dist/SBOM.spdx.json)
286
+ if gh release view "$tag" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
287
+ gh release upload "$tag" "${assets[@]}" --clobber --repo "$GITHUB_REPOSITORY"
288
+ else
289
+ gh release create "$tag" "${assets[@]}" \
290
+ --repo "$GITHUB_REPOSITORY" \
291
+ --title "$tag" \
292
+ --generate-notes \
293
+ --notes "Published distributions and release metadata for $tag. See CHANGELOG.md for the reviewed release notes."
294
+ fi
@@ -65,10 +65,17 @@ jobs:
65
65
  python -m mypy --strict examples/typed_consumer.py
66
66
  python -m mypy --strict lib/python/base_cli
67
67
  python scripts/validate_docs.py
68
+ python scripts/validate_changelog.py
69
+ python scripts/validate_schemas.py
70
+ python scripts/validate_contract_fixtures.py
71
+ node scripts/validate_contract_fixtures.mjs
72
+ python scripts/generate_compatibility_dashboard.py --check
68
73
  python scripts/benchmark_runtime.py --check
69
74
  python -m compileall -q examples
70
75
  - name: Run tests with coverage threshold
71
- run: python -m pytest --cov=base_cli --cov-report=term-missing --cov-fail-under=80
76
+ run: python -m pytest --cov=base_cli --cov-report=term-missing --cov-report=json:coverage.json --cov-fail-under=80
77
+ - name: Enforce high-risk module coverage floors
78
+ run: python scripts/validate_coverage.py coverage.json
72
79
  - name: Run static security checks
73
80
  run: |
74
81
  bandit -q -r lib/python/base_cli scripts -lll -iii
@@ -11,6 +11,76 @@ and versions are tracked in the repo-root `VERSION` file.
11
11
 
12
12
  - Continue compatibility hardening and adoption work for the next release.
13
13
 
14
+ ## [0.4.3] - 2026-08-29
15
+
16
+ This is a compatible pre-1.0 patch release. It contains lifecycle hardening,
17
+ security fixes, versioned machine-readable contracts, and adoption tooling
18
+ after 0.4.2; it does not introduce a new API or JSON-contract compatibility
19
+ boundary. Existing Click and Typer command trees remain supported.
20
+
21
+ ### Changed
22
+
23
+ - Add branch-aware coverage reporting with documented floors for lifecycle,
24
+ filesystem, compatibility, history, and contract modules.
25
+ - Decompose the application implementation behind a compatibility facade into
26
+ focused core, lifecycle-installation, attachment, and invocation-runner
27
+ modules without changing the public import surface.
28
+ - Bound the core Click and PyYAML dependency windows, publish the tested
29
+ compatibility matrix, and document the dependency update policy.
30
+ - Validate Click 8.1 through 8.4 on the supported Python floor and ceiling,
31
+ and reject unvalidated Click 8.5+ versions through package metadata.
32
+ - Move PyYAML behind the optional `base-cli[yaml]` extra and provide an
33
+ actionable installation hint when YAML configuration or output is selected.
34
+ - Add an explicit `App.async_command()` adapter and `run_async()` helper for
35
+ deterministic async callbacks without changing the synchronous core.
36
+ - Add versioned NDJSON output and typed writer protocols for bounded,
37
+ flush-per-record machine output.
38
+ - Formalize typed extension callback protocols, entry-point capability metadata,
39
+ and pre-load API-version negotiation.
40
+
41
+ ### Security
42
+
43
+ - Redact recognized secret keys embedded in query strings, comma-separated
44
+ values, and header-style `key: value` arguments before they reach logs or
45
+ persisted history.
46
+
47
+ ### Fixed
48
+
49
+ - Keep the Typer adapter compatible with Typer 0.27.2's vendored exit
50
+ exception layout and validate that release in the compatibility matrix.
51
+ - Apply the documented count-only 20-bundle retention default to implicit JSON
52
+ mode while preserving explicit retention policies, human-mode safe defaults,
53
+ and the `max_log_files` compatibility path.
54
+ - Honor combined positive/negative JSON option declarations and explicit
55
+ `--no-json` values when deciding whether pre-parse errors use JSON output.
56
+ - Isolate malformed third-party entry-point metadata so one invalid extension
57
+ cannot prevent healthy extensions from being discovered.
58
+
59
+ ### Added
60
+
61
+ - Automate GitHub Releases from matching version tags with reviewed
62
+ distributions, checksums, SBOM metadata, and generated comparison notes.
63
+ - Publish a generated dependency and platform compatibility dashboard linked
64
+ from the README and documentation site.
65
+ - Add framework-specific migration guides for Click, Typer, Cement, and
66
+ `argparse`, with rollout and rollback checklists.
67
+ - Add golden success, error, inspection, log, NDJSON, and command-protocol
68
+ fixtures with Python and Node.js validators for cross-language consumers.
69
+ - Publish versioned JSON Schema artifacts for output, error, inspection, log,
70
+ NDJSON, and decoded command-protocol contracts in the package and docs site.
71
+ - Add a framework choice guide, five-minute evaluation path, and clearer
72
+ production-lifecycle positioning for Click and Typer adopters.
73
+ - Add deterministic SPDX SBOMs, artifact checksums, and OIDC-backed GitHub
74
+ attestations to protected release workflows.
75
+ - Add a generated public API reference and a strict CI drift check so every
76
+ stable facade export remains searchable and documented.
77
+ - Add a permissioned-adopter evidence policy and dated compatibility-run
78
+ artifacts without presenting maintained fixtures as customer adoption.
79
+
80
+ - Align the README, documentation landing page, package metadata, and search
81
+ keywords around the production lifecycle layer positioning for Click and
82
+ Typer CLIs.
83
+
14
84
  ## [0.4.2] - 2026-08-08
15
85
 
16
86
  This is a compatible pre-1.0 patch release. It contains correctness fixes,
@@ -234,6 +304,14 @@ the API stability policy and migration guide before upgrading from `0.3.x`.
234
304
  - Initialized the repository with the Base-managed repo baseline.
235
305
  - Added the guarded package build, artifact validation, and protected
236
306
  TestPyPI/PyPI publication workflow.
307
+
308
+ [Unreleased]: https://github.com/basefoundry/base-cli/compare/v0.4.3...HEAD
309
+ [0.4.3]: https://github.com/basefoundry/base-cli/compare/v0.4.2...v0.4.3
310
+ [0.4.2]: https://github.com/basefoundry/base-cli/compare/v0.4.1...v0.4.2
311
+ [0.4.1]: https://github.com/basefoundry/base-cli/compare/v0.4.0...v0.4.1
312
+ [0.4.0]: https://github.com/basefoundry/base-cli/compare/v0.3.0...v0.4.0
313
+ [0.3.0]: https://github.com/basefoundry/base-cli/compare/v0.2.0...v0.3.0
314
+ [0.2.0]: https://github.com/basefoundry/base-cli/releases/tag/v0.2.0
237
315
  - Exposed `base_cli.__version__` from the repository and installed package
238
316
  version contract.
239
317
  - Pinned the build backend to metadata compatible with the bundled publication
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: base-cli
3
- Version: 0.4.2
4
- Summary: A small, consumer-neutral Python CLI framework
3
+ Version: 0.4.3
4
+ Summary: The production lifecycle layer for Click and Typer Python CLIs
5
5
  Author: Base Foundry
6
6
  License: Apache-2.0
7
7
  Project-URL: Homepage, https://github.com/basefoundry/base-cli
@@ -9,6 +9,7 @@ Project-URL: Repository, https://github.com/basefoundry/base-cli
9
9
  Project-URL: Issues, https://github.com/basefoundry/base-cli/issues
10
10
  Project-URL: Documentation, https://basefoundry.github.io/base-cli/
11
11
  Project-URL: Code of Conduct, https://github.com/basefoundry/base-cli/blob/main/CODE_OF_CONDUCT.md
12
+ Keywords: cli,python-cli,command-line,command-line-interface,cli-framework,click,typer,framework,lifecycle,logging,structured-logging,configuration
12
13
  Classifier: Development Status :: 4 - Beta
13
14
  Classifier: Intended Audience :: Developers
14
15
  Classifier: License :: OSI Approved :: Apache Software License
@@ -23,15 +24,19 @@ Classifier: Programming Language :: Python :: 3.12
23
24
  Classifier: Programming Language :: Python :: 3.13
24
25
  Classifier: Programming Language :: Python :: 3.14
25
26
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
28
+ Classifier: Topic :: System :: Shells
26
29
  Requires-Python: >=3.10
27
30
  Description-Content-Type: text/markdown
28
31
  License-File: LICENSE
29
- Requires-Dist: click>=8.1
30
- Requires-Dist: PyYAML>=6.0
32
+ Requires-Dist: click<8.5,>=8.1
33
+ Provides-Extra: yaml
34
+ Requires-Dist: PyYAML<7,>=6.0; extra == "yaml"
31
35
  Provides-Extra: dev
32
36
  Requires-Dist: build>=1.2; extra == "dev"
33
37
  Requires-Dist: hypothesis<7,>=6.100; extra == "dev"
34
38
  Requires-Dist: mypy<2,>=1.17; extra == "dev"
39
+ Requires-Dist: PyYAML<7,>=6.0; extra == "dev"
35
40
  Requires-Dist: pytest>=8.0; extra == "dev"
36
41
  Requires-Dist: types-PyYAML<7,>=6.0; extra == "dev"
37
42
  Provides-Extra: typer
@@ -58,9 +63,18 @@ Requires-Dist: mkdocs-material<10,>=9.5; extra == "docs"
58
63
 
59
64
  | Version | License | Install | Release notes |
60
65
  | --- | --- | --- | --- |
61
- | `0.4.2` | [Apache-2.0](LICENSE) | `python -m pip install base-cli` | [v0.4.2](https://github.com/basefoundry/base-cli/releases/tag/v0.4.2) |
66
+ | `0.4.3` | [Apache-2.0](LICENSE) | `python -m pip install base-cli` | [v0.4.3](https://github.com/basefoundry/base-cli/releases/tag/v0.4.3) |
62
67
 
63
- `base-cli` is the PyPI distribution; import it in Python as `base_cli`.
68
+ `base-cli` is the production lifecycle layer for Click and Typer Python CLIs.
69
+ It standardizes context, logging, configuration, cleanup, and machine-readable
70
+ contracts while leaving command and product policy in the consumer application.
71
+ The PyPI distribution is `base-cli`; import it in Python as `base_cli`.
72
+
73
+ It is for teams shipping operational CLIs that need the same diagnostics,
74
+ configuration boundary, cleanup behavior, and automation contracts in every
75
+ command. It is not a parser replacement or an application scaffold: Click and
76
+ Typer still own parsing and command definitions, while the consuming project
77
+ owns its domain policy and services.
64
78
 
65
79
  Install it with:
66
80
 
@@ -71,6 +85,11 @@ python -m pip install base-cli
71
85
  Read the complete documentation at
72
86
  <https://basefoundry.github.io/base-cli/>.
73
87
 
88
+ Compatibility results and the permissioned-adopter policy are documented in
89
+ the [adoption and compatibility evidence guide](https://basefoundry.github.io/base-cli/adoption-evidence/).
90
+ The [compatibility dashboard](https://basefoundry.github.io/base-cli/compatibility-dashboard/)
91
+ shows the declared and CI-tested dependency and platform support boundaries.
92
+
74
93
  ## Quick start
75
94
 
76
95
  Create a small command with a consistent context, logging, and cleanup
@@ -107,10 +126,9 @@ documented in [`docs/releasing.md`](https://basefoundry.github.io/base-cli/relea
107
126
  The package is distributed under the Apache License 2.0. Base itself remains
108
127
  licensed separately under AGPL-3.0-or-later.
109
128
 
110
- `base_cli` is a small Python framework for writing command-line tools with
111
- a consistent lifecycle. It is designed to be embedded by applications rather
112
- than to define an application's project model. Base is one consumer of the
113
- library, not part of its generic contract.
129
+ `base_cli` is designed to be embedded by applications rather than to define
130
+ an application's project model. Base is one consumer of the library, not part
131
+ of its generic contract.
114
132
 
115
133
  It is intentionally thin. Click still owns argument parsing and command
116
134
  execution, while `base_cli` provides reusable lifecycle behavior:
@@ -137,6 +155,8 @@ The supported public facade, compatibility promises, deprecation warning
137
155
  mechanism, and migration requirements are documented in
138
156
  [`docs/api-stability.md`](https://basefoundry.github.io/base-cli/api-stability/) and
139
157
  [`docs/migrations.md`](https://basefoundry.github.io/base-cli/migrations/).
158
+ The complete generated facade is listed in the
159
+ [`public API reference`](https://basefoundry.github.io/base-cli/api-reference/).
140
160
 
141
161
  Security reporting, runtime trust boundaries, threat assumptions, and the
142
162
  release security checklist are documented in [`SECURITY.md`](SECURITY.md),
@@ -283,6 +303,10 @@ catalog](examples/README.md). It covers a minimal command, nested/plugin Click,
283
303
  Typer, and automation/observability flows; each example has its own packaging,
284
304
  tests, completion, release, and troubleshooting guidance.
285
305
 
306
+ Teams comparing frameworks can start with the [framework choice guide](docs/framework-choice.md),
307
+ which explains what base-cli adds to Click or Typer and when a different
308
+ framework is a better fit.
309
+
286
310
  Teams evaluating adoption can follow the [adopter readiness and migration
287
311
  guide](https://basefoundry.github.io/base-cli/adopter-readiness/) and run the three independent
288
312
  [downstream compatibility consumers](compatibility/README.md).
@@ -753,6 +777,10 @@ command execution as `130` without a traceback. After the command outcome has
753
777
  settled, history, metadata, and cleanup are best-effort teardown: even a second
754
778
  interrupt there cannot replace the primary result.
755
779
 
780
+ Terminal lifecycle status is `ok` for exit code `0`, `aborted` for the
781
+ interrupt exit code `130`, and `error` for other nonzero exit codes. The
782
+ technical outcome remains precise: Ctrl+C is recorded as `interrupted`.
783
+
756
784
  An unexpected exception returns `1` with a stable, detail-free message. The run
757
785
  ID and diagnostic-log path are included when context and file logging are
758
786
  available. The traceback is kept in the persistent log when enabled and is
@@ -1106,8 +1134,9 @@ stdout or stderr for expected usage or application failures.
1106
1134
 
1107
1135
  `invoke()` sets `HOME` plus the relevant `USERPROFILE`, `LOCALAPPDATA`, and
1108
1136
  `XDG_CACHE_HOME` values when requested, and supplies `cwd` to the invocation for
1109
- the duration of the test. Calls that use `cwd` are serialized and the caller's
1110
- cwd is restored afterward, but this remains process-global: do not use it
1137
+ the duration of the test. All helper calls are serialized because `cwd` is
1138
+ process-global: a no-`cwd` call cannot observe another call's temporary
1139
+ directory, and the caller's cwd is restored afterward. Do not use it
1111
1140
  concurrently with code that changes cwd outside `invoke()` or from threads
1112
1141
  spawned by the invoked command. A generic profile should receive project
1113
1142
  fixtures through its `discover_project` callback. The helper does not create or
@@ -7,9 +7,18 @@
7
7
 
8
8
  | Version | License | Install | Release notes |
9
9
  | --- | --- | --- | --- |
10
- | `0.4.2` | [Apache-2.0](LICENSE) | `python -m pip install base-cli` | [v0.4.2](https://github.com/basefoundry/base-cli/releases/tag/v0.4.2) |
10
+ | `0.4.3` | [Apache-2.0](LICENSE) | `python -m pip install base-cli` | [v0.4.3](https://github.com/basefoundry/base-cli/releases/tag/v0.4.3) |
11
11
 
12
- `base-cli` is the PyPI distribution; import it in Python as `base_cli`.
12
+ `base-cli` is the production lifecycle layer for Click and Typer Python CLIs.
13
+ It standardizes context, logging, configuration, cleanup, and machine-readable
14
+ contracts while leaving command and product policy in the consumer application.
15
+ The PyPI distribution is `base-cli`; import it in Python as `base_cli`.
16
+
17
+ It is for teams shipping operational CLIs that need the same diagnostics,
18
+ configuration boundary, cleanup behavior, and automation contracts in every
19
+ command. It is not a parser replacement or an application scaffold: Click and
20
+ Typer still own parsing and command definitions, while the consuming project
21
+ owns its domain policy and services.
13
22
 
14
23
  Install it with:
15
24
 
@@ -20,6 +29,11 @@ python -m pip install base-cli
20
29
  Read the complete documentation at
21
30
  <https://basefoundry.github.io/base-cli/>.
22
31
 
32
+ Compatibility results and the permissioned-adopter policy are documented in
33
+ the [adoption and compatibility evidence guide](https://basefoundry.github.io/base-cli/adoption-evidence/).
34
+ The [compatibility dashboard](https://basefoundry.github.io/base-cli/compatibility-dashboard/)
35
+ shows the declared and CI-tested dependency and platform support boundaries.
36
+
23
37
  ## Quick start
24
38
 
25
39
  Create a small command with a consistent context, logging, and cleanup
@@ -56,10 +70,9 @@ documented in [`docs/releasing.md`](https://basefoundry.github.io/base-cli/relea
56
70
  The package is distributed under the Apache License 2.0. Base itself remains
57
71
  licensed separately under AGPL-3.0-or-later.
58
72
 
59
- `base_cli` is a small Python framework for writing command-line tools with
60
- a consistent lifecycle. It is designed to be embedded by applications rather
61
- than to define an application's project model. Base is one consumer of the
62
- library, not part of its generic contract.
73
+ `base_cli` is designed to be embedded by applications rather than to define
74
+ an application's project model. Base is one consumer of the library, not part
75
+ of its generic contract.
63
76
 
64
77
  It is intentionally thin. Click still owns argument parsing and command
65
78
  execution, while `base_cli` provides reusable lifecycle behavior:
@@ -86,6 +99,8 @@ The supported public facade, compatibility promises, deprecation warning
86
99
  mechanism, and migration requirements are documented in
87
100
  [`docs/api-stability.md`](https://basefoundry.github.io/base-cli/api-stability/) and
88
101
  [`docs/migrations.md`](https://basefoundry.github.io/base-cli/migrations/).
102
+ The complete generated facade is listed in the
103
+ [`public API reference`](https://basefoundry.github.io/base-cli/api-reference/).
89
104
 
90
105
  Security reporting, runtime trust boundaries, threat assumptions, and the
91
106
  release security checklist are documented in [`SECURITY.md`](SECURITY.md),
@@ -232,6 +247,10 @@ catalog](examples/README.md). It covers a minimal command, nested/plugin Click,
232
247
  Typer, and automation/observability flows; each example has its own packaging,
233
248
  tests, completion, release, and troubleshooting guidance.
234
249
 
250
+ Teams comparing frameworks can start with the [framework choice guide](docs/framework-choice.md),
251
+ which explains what base-cli adds to Click or Typer and when a different
252
+ framework is a better fit.
253
+
235
254
  Teams evaluating adoption can follow the [adopter readiness and migration
236
255
  guide](https://basefoundry.github.io/base-cli/adopter-readiness/) and run the three independent
237
256
  [downstream compatibility consumers](compatibility/README.md).
@@ -702,6 +721,10 @@ command execution as `130` without a traceback. After the command outcome has
702
721
  settled, history, metadata, and cleanup are best-effort teardown: even a second
703
722
  interrupt there cannot replace the primary result.
704
723
 
724
+ Terminal lifecycle status is `ok` for exit code `0`, `aborted` for the
725
+ interrupt exit code `130`, and `error` for other nonzero exit codes. The
726
+ technical outcome remains precise: Ctrl+C is recorded as `interrupted`.
727
+
705
728
  An unexpected exception returns `1` with a stable, detail-free message. The run
706
729
  ID and diagnostic-log path are included when context and file logging are
707
730
  available. The traceback is kept in the persistent log when enabled and is
@@ -1055,8 +1078,9 @@ stdout or stderr for expected usage or application failures.
1055
1078
 
1056
1079
  `invoke()` sets `HOME` plus the relevant `USERPROFILE`, `LOCALAPPDATA`, and
1057
1080
  `XDG_CACHE_HOME` values when requested, and supplies `cwd` to the invocation for
1058
- the duration of the test. Calls that use `cwd` are serialized and the caller's
1059
- cwd is restored afterward, but this remains process-global: do not use it
1081
+ the duration of the test. All helper calls are serialized because `cwd` is
1082
+ process-global: a no-`cwd` call cannot observe another call's temporary
1083
+ directory, and the caller's cwd is restored afterward. Do not use it
1060
1084
  concurrently with code that changes cwd outside `invoke()` or from threads
1061
1085
  spawned by the invoked command. A generic profile should receive project
1062
1086
  fixtures through its `discover_project` callback. The helper does not create or
base_cli-0.4.3/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.4.3
@@ -1,9 +1,10 @@
1
1
  # Downstream compatibility consumers
2
2
 
3
- These are three independent, maintainable consumer fixtures used as adoption
4
- evidence until a non-Base team grants permission for a public case study. They
5
- are deliberately separate packages with separate names, entry points, and test
6
- suites; none imports another fixture or Base product code.
3
+ These are three maintained reference consumer fixtures used as compatibility
4
+ evidence. They are deliberately separate packages with separate names, entry
5
+ points, and test suites; none imports another fixture or Base product code.
6
+ They are not independent adopters and must not be presented as customer
7
+ outcomes.
7
8
 
8
9
  | Consumer | Shape | Use case | Compatibility outcome |
9
10
  | --- | --- | --- | --- |
@@ -20,6 +21,12 @@ own dependencies, and runs each consumer's tests. This catches import,
20
21
  packaging, adapter, and contract regressions without relying on repository
21
22
  source imports.
22
23
 
24
+ The downstream job records a dated JSON result as the
25
+ `base-cli-compatibility-evidence-<run-id>` artifact. It binds the result to the
26
+ framework revision and version and lists the exact fixture and matrix that
27
+ passed. See [`adoption-evidence.md`](../docs/adoption-evidence.md) for the
28
+ claim and permission boundary.
29
+
23
30
  The same workflow runs the Typer adapter and Beacon fixture against Typer
24
31
  0.25.1, 0.26.0, and 0.27.1 on Python 3.10 through 3.14. This matrix covers the
25
32
  transition from Click's public command classes to Typer's vendored Click fork.
@@ -35,4 +42,4 @@ for tests in compatibility/consumers/*/tests; do python -m pytest "$tests"; done
35
42
  ```
36
43
 
37
44
  The fixtures are not customer claims. A permissioned public adopter can be
38
- substituted in the manifest while retaining the same downstream contract tests.
45
+ added as a separate record while retaining the same downstream contract tests.
@@ -11,7 +11,8 @@ Before the first production pilot, the adopter should be able to check every
11
11
  box below:
12
12
 
13
13
  - [ ] Pin a supported `base-cli` minor release (for example, `~=0.4.0`) and
14
- record Click, PyYAML, and any optional integration versions in a lock file.
14
+ record Click, the optional YAML extra (when used), and any other integration
15
+ versions in a lock file.
15
16
  - [ ] Run the adopter's command suite on CPython 3.10--3.14 on every platform
16
17
  the product supports; retain at least one installed-wheel smoke job.
17
18
  - [ ] Use only the documented `base_cli` facade and module `__all__` exports;
@@ -72,18 +73,18 @@ release-blocking finding back to the compatibility register.
72
73
 
73
74
  ## Evidence and downstream compatibility
74
75
 
75
- The repository does not claim a customer identity without permission. Until an
76
- external team authorizes a public case study, three independent consumer
77
- fixtures provide the reviewable evidence:
76
+ The repository does not claim a customer identity without permission. Three
77
+ maintained reference fixtures provide compatibility evidence, but they are not
78
+ independent adopters or customer outcomes:
78
79
 
79
80
  - **Atlas** — a Click inventory command migrated without rebuilding its tree;
80
81
  - **Beacon** — a typed Typer deployment command using the optional adapter; and
81
82
  - **Cinder** — a scheduled reconciliation command with dry-run and JSON output.
82
83
 
83
84
  Each fixture has its own package metadata and tests, is installed against the
84
- published framework wheel in CI, and records a stable invocation outcome. A
85
- permissioned adopter can replace a fixture with a public case study without
86
- changing the compatibility test contract.
85
+ published framework wheel in CI, and records a stable invocation outcome. The
86
+ [adoption and compatibility evidence](adoption-evidence.md) guide defines the
87
+ permissioned adopter program and the public-claim boundary.
87
88
 
88
89
  ## Adoption friction and release gate
89
90