boost-skill-cli 1.0.265__tar.gz → 1.0.267__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 (504) hide show
  1. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/PKG-INFO +1 -1
  2. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/_version.py +2 -2
  3. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/commands/discovery.py +15 -8
  4. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/commands/info.py +17 -11
  5. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/commands/quality.py +15 -11
  6. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/commands/safety.py +6 -5
  7. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_skill_cli.egg-info/PKG-INFO +1 -1
  8. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_skill_cli.egg-info/SOURCES.txt +2 -0
  9. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/pyproject.toml +9 -0
  10. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/requirements/release-tools.in +4 -0
  11. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/requirements/release-tools.txt +12 -0
  12. boost_skill_cli-1.0.267/scripts/check_licenses.py +108 -0
  13. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_cli_discovery.py +11 -0
  14. boost_skill_cli-1.0.267/tests/unit/test_check_licenses.py +163 -0
  15. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/.gitattributes +0 -0
  16. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/.gitignore +0 -0
  17. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/.gitleaks.toml +0 -0
  18. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/.htmlvalidate.json +0 -0
  19. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/.lighthouserc.json +0 -0
  20. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/.lycheeignore +0 -0
  21. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/.markdownlint-cli2.jsonc +0 -0
  22. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/.pre-commit-config.yaml +0 -0
  23. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/.stylelintrc.json +0 -0
  24. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/.vale/styles/boost/Terminology.yml +0 -0
  25. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/.vale/styles/config/vocabularies/boost/accept.txt +0 -0
  26. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/.vale.ini +0 -0
  27. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/CLAUDE.md +0 -0
  28. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/CODE_OF_CONDUCT.md +0 -0
  29. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/CONTRIBUTING.md +0 -0
  30. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/LICENSE +0 -0
  31. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/MANIFEST.in +0 -0
  32. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/Makefile +0 -0
  33. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/README.md +0 -0
  34. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/SECURITY.md +0 -0
  35. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost +0 -0
  36. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/__init__.py +0 -0
  37. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/__main__.py +0 -0
  38. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/cli.py +0 -0
  39. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/cliparse.py +0 -0
  40. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/commands/__init__.py +0 -0
  41. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/commands/_common.py +0 -0
  42. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/commands/bmad.py +0 -0
  43. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/commands/configuration.py +0 -0
  44. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/commands/hooks.py +0 -0
  45. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/commands/intelligence.py +0 -0
  46. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/commands/pkg.py +0 -0
  47. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/commands/run.py +0 -0
  48. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/commands/taps.py +0 -0
  49. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/commands/team.py +0 -0
  50. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/__init__.py +0 -0
  51. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/adapters.py +0 -0
  52. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/agents.py +0 -0
  53. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/ai.py +0 -0
  54. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/capabilities.py +0 -0
  55. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/catalog.py +0 -0
  56. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/claude_settings.py +0 -0
  57. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/config.py +0 -0
  58. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/dense.py +0 -0
  59. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/ed25519.py +0 -0
  60. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/embed.py +0 -0
  61. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/faithfulness.py +0 -0
  62. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/frontmatter.py +0 -0
  63. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/gitutil.py +0 -0
  64. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/imperative.py +0 -0
  65. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/injectscan.py +0 -0
  66. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/integrity.py +0 -0
  67. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/journal.py +0 -0
  68. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/lockfile.py +0 -0
  69. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/logs.py +0 -0
  70. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/mcp.py +0 -0
  71. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/mcpdecl.py +0 -0
  72. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/minisign.py +0 -0
  73. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/nethttp.py +0 -0
  74. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/output.py +0 -0
  75. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/paths.py +0 -0
  76. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/policy.py +0 -0
  77. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/projectlock.py +0 -0
  78. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/provenance.py +0 -0
  79. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/rag.py +0 -0
  80. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/registry.py +0 -0
  81. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/resolve.py +0 -0
  82. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/rules.py +0 -0
  83. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/scopes.py +0 -0
  84. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/secretscan.py +0 -0
  85. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/selfupdate.py +0 -0
  86. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/serve.py +0 -0
  87. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/stackprobe.py +0 -0
  88. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/staleness.py +0 -0
  89. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/store.py +0 -0
  90. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/trustaudit.py +0 -0
  91. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/typosquat.py +0 -0
  92. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/updatediff.py +0 -0
  93. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/util.py +0 -0
  94. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/core/workflows.py +0 -0
  95. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/data/registries.json +0 -0
  96. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/errors.py +0 -0
  97. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_cli/spin.py +0 -0
  98. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
  99. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_skill_cli.egg-info/entry_points.txt +0 -0
  100. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_skill_cli.egg-info/requires.txt +0 -0
  101. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/boost_skill_cli.egg-info/top_level.txt +0 -0
  102. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/codecov.yml +0 -0
  103. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/.claude/settings.local.json +0 -0
  104. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/DEBUGGING.md +0 -0
  105. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/adapters.html +0 -0
  106. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/carousel/gifs/distill.gif +0 -0
  107. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/carousel/gifs/doctor.gif +0 -0
  108. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/carousel/gifs/explain.gif +0 -0
  109. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/carousel/gifs/hooks.gif +0 -0
  110. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/carousel/gifs/install.gif +0 -0
  111. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/carousel/gifs/pulse.gif +0 -0
  112. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/carousel/gifs/search.gif +0 -0
  113. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/carousel/gifs/tap.gif +0 -0
  114. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/carousel/tapes/distill.tape +0 -0
  115. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/carousel/tapes/doctor.tape +0 -0
  116. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/carousel/tapes/explain.tape +0 -0
  117. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/carousel/tapes/hooks.tape +0 -0
  118. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/carousel/tapes/install.tape +0 -0
  119. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/carousel/tapes/pulse.tape +0 -0
  120. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/carousel/tapes/search.tape +0 -0
  121. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/carousel/tapes/tap.tape +0 -0
  122. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/carousel.html +0 -0
  123. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/commands.html +0 -0
  124. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/demo.gif +0 -0
  125. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/demo.tape +0 -0
  126. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/design-roadmap.html +0 -0
  127. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/eval.html +0 -0
  128. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/index.html +0 -0
  129. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/mcp-hub.html +0 -0
  130. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/rag-architecture.md +0 -0
  131. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D01.md +0 -0
  132. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D02.md +0 -0
  133. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D03.md +0 -0
  134. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D04.md +0 -0
  135. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D05.md +0 -0
  136. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D06.md +0 -0
  137. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D07.md +0 -0
  138. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D08.md +0 -0
  139. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D09.md +0 -0
  140. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D10.md +0 -0
  141. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D11.md +0 -0
  142. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D12.md +0 -0
  143. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D13.md +0 -0
  144. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D14.md +0 -0
  145. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D15.md +0 -0
  146. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D16.md +0 -0
  147. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D17.md +0 -0
  148. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D18.md +0 -0
  149. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D19.md +0 -0
  150. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D20.md +0 -0
  151. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D21.md +0 -0
  152. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D22.md +0 -0
  153. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D23.md +0 -0
  154. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D24.md +0 -0
  155. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D25.md +0 -0
  156. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/BOOST-D26.md +0 -0
  157. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
  158. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/adapter-conformance-langgraph-leg-never-ran.md +0 -0
  159. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/ai-bridge-silent-failure-logging.md +0 -0
  160. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/ambiguous-tap-short-name-resolution.md +0 -0
  161. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
  162. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
  163. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
  164. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/boost-run-live-agents.md +0 -0
  165. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
  166. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
  167. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
  168. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
  169. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
  170. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
  171. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/ci-job-timeout-minutes.md +0 -0
  172. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/ci-summary-step-fails-itself.md +0 -0
  173. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
  174. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/command-carousel-page.md +0 -0
  175. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/command-reference-docs-site.md +0 -0
  176. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
  177. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
  178. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
  179. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
  180. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/crash-listing-branch-untested.md +0 -0
  181. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
  182. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/demo-gif-workflow-has-never-succeeded.md +0 -0
  183. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/dense-search-fallback-and-stale-tap-pruning.md +0 -0
  184. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/dependabot-missing-pip-ecosystem.md +0 -0
  185. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
  186. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/docsite-chrome-and-content-audit.md +0 -0
  187. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
  188. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
  189. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
  190. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
  191. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
  192. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
  193. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
  194. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
  195. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
  196. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/framework-adapter-multi-agent.md +0 -0
  197. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
  198. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
  199. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/github-community-health-files.md +0 -0
  200. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
  201. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
  202. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
  203. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/html-validation-html-validate.md +0 -0
  204. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/install-docs-never-mentioned-upgrading.md +0 -0
  205. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/install-from-path-bypasses-policy-and-pin-checks.md +0 -0
  206. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/install-resolves-skill-dependencies.md +0 -0
  207. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/install-scope-user-or-project.md +0 -0
  208. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/installed-skill-trust-audit.md +0 -0
  209. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
  210. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
  211. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/journal-rotation-race-and-handle-leak.md +0 -0
  212. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
  213. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/license-compliance-scanning.md +0 -0
  214. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
  215. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/lint-tap-misscopes-rule-workflow-entries.md +0 -0
  216. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
  217. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
  218. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/lock-invariant-cannot-parse-extras-pins.md +0 -0
  219. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
  220. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
  221. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
  222. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/main-has-no-branch-protection.md +0 -0
  223. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/main-ruleset-ref-pattern-has-literal-quotes.md +0 -0
  224. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
  225. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
  226. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/markdownlint-lints-the-fuzz-corpus.md +0 -0
  227. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/mcp-aware-skills.md +0 -0
  228. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
  229. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
  230. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
  231. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/mcp-search-before-reinventing.md +0 -0
  232. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
  233. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
  234. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/merge-queue-would-deadlock-most-required-checks.md +0 -0
  235. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
  236. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/mutation-gate-was-the-whole-critical-path.md +0 -0
  237. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
  238. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
  239. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
  240. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/mypy-strict-mode-for-commands.md +0 -0
  241. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/negative-limit-inverts-log-pulse-output.md +0 -0
  242. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/onboard-overwrites-generated-files-without-confirm.md +0 -0
  243. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
  244. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
  245. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
  246. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
  247. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/path-traversal-unsanitized-rule-workflow-name.md +0 -0
  248. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
  249. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/pin-the-lint-toolchain.md +0 -0
  250. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/post-deploy-always-defeated-by-skipped-setup.md +0 -0
  251. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
  252. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
  253. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/project-scope-across-every-command.md +0 -0
  254. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/project-scope-symlink-escape-on-write.md +0 -0
  255. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
  256. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
  257. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
  258. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
  259. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
  260. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/publish-gate-ignores-pip-audit-and-metadata.md +0 -0
  261. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/publish-trigger-was-reachable-from-a-fork.md +0 -0
  262. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/pytest-tmpdir-cve-blocked-by-py39-floor.md +0 -0
  263. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
  264. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
  265. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
  266. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
  267. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/rel-time-tests-race-the-wall-clock.md +0 -0
  268. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/required-checks-can-declare-a-check-that-deadlocks-prs.md +0 -0
  269. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/required-checks-config-drift.md +0 -0
  270. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
  271. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
  272. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/roadmap-html-goes-stale-on-every-rebase.md +0 -0
  273. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
  274. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/ruff-016-widens-the-default-rule-set.md +0 -0
  275. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
  276. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
  277. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
  278. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
  279. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
  280. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/sbom-release-event-never-fires.md +0 -0
  281. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
  282. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/scorecard-findings-triage.md +0 -0
  283. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
  284. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
  285. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
  286. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
  287. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/self-update-broken-for-pip-pipx-installs.md +0 -0
  288. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/serve-py-traversal-guards-untested.md +0 -0
  289. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
  290. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
  291. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
  292. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
  293. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
  294. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
  295. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/structured-json-log-output-mode.md +0 -0
  296. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
  297. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
  298. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/sync-deletes-unowned-broken-symlinks.md +0 -0
  299. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
  300. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
  301. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/typo-detection-codespell.md +0 -0
  302. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
  303. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
  304. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/uninstall-has-no-confirmation-prompt.md +0 -0
  305. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
  306. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/update-diff-before-apply.md +0 -0
  307. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
  308. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/update-reinstall-widens-agent-scope.md +0 -0
  309. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
  310. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
  311. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
  312. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/wire-bdd-suite-into-ci.md +0 -0
  313. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
  314. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
  315. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
  316. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap/items/workspace-scope-install.md +0 -0
  317. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/docs/roadmap.html +0 -0
  318. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/eslint.config.mjs +0 -0
  319. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/examples/README.md +0 -0
  320. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/examples/adapt-demo.sh +0 -0
  321. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/examples/boost-run-prototype.sh +0 -0
  322. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/index.html +0 -0
  323. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/noxfile.py +0 -0
  324. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/requirements/coverage-tools.in +0 -0
  325. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/requirements/coverage-tools.txt +0 -0
  326. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/requirements/lint-tools.in +0 -0
  327. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/requirements/lint-tools.txt +0 -0
  328. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/requirements/mutation-tools.in +0 -0
  329. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/requirements/mutation-tools.txt +0 -0
  330. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/requirements/test-tools.in +0 -0
  331. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/requirements/test-tools.txt +0 -0
  332. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/a11y_check.py +0 -0
  333. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/bench_cli.sh +0 -0
  334. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/build_command_reference.py +0 -0
  335. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/build_registries.py +0 -0
  336. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/build_roadmap.py +0 -0
  337. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/check_anchors.py +0 -0
  338. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/check_required_checks.py +0 -0
  339. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/ensure_eval_corpus.sh +0 -0
  340. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/eval_explain.py +0 -0
  341. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/eval_recommend.py +0 -0
  342. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/eval_retrieval.py +0 -0
  343. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/eval_stats_summary.py +0 -0
  344. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/import_budget.py +0 -0
  345. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/lock_toolchain.py +0 -0
  346. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/mutation_gate.py +0 -0
  347. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/mutation_shards.py +0 -0
  348. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/mutation_weights.json +0 -0
  349. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/perf_gate.py +0 -0
  350. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/post_deploy_smoke.py +0 -0
  351. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/scripts/release_preflight.py +0 -0
  352. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/setup.cfg +0 -0
  353. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/sonar-project.properties +0 -0
  354. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/style/README.md +0 -0
  355. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/style/boost.css +0 -0
  356. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/style/boost.js +0 -0
  357. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/style/demo.html +0 -0
  358. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/bdd/features/adapt.feature +0 -0
  359. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/bdd/features/browse.feature +0 -0
  360. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/bdd/features/count.feature +0 -0
  361. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/bdd/features/discover.feature +0 -0
  362. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/bdd/features/doctor.feature +0 -0
  363. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/bdd/features/environment.py +0 -0
  364. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/bdd/features/explain.feature +0 -0
  365. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/bdd/features/index.feature +0 -0
  366. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/bdd/features/install.feature +0 -0
  367. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/bdd/features/list.feature +0 -0
  368. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/bdd/features/mcp.feature +0 -0
  369. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/bdd/features/search.feature +0 -0
  370. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/bdd/features/steps/cli_steps.py +0 -0
  371. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/bdd/features/steps/discovery_steps.py +0 -0
  372. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/bdd/features/steps/mcp_steps.py +0 -0
  373. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/bdd/features/steps/quality_steps.py +0 -0
  374. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/conftest.py +0 -0
  375. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/eval/baseline.json +0 -0
  376. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/eval/explain.jsonl +0 -0
  377. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/eval/golden.jsonl +0 -0
  378. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/eval/recommend.jsonl +0 -0
  379. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/eval/taps.txt +0 -0
  380. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_capabilities_policy.py +0 -0
  381. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_cli_adapt.py +0 -0
  382. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_cli_bmad.py +0 -0
  383. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_cli_configuration.py +0 -0
  384. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_cli_hooks.py +0 -0
  385. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_cli_info.py +0 -0
  386. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_cli_intelligence.py +0 -0
  387. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_cli_pkg.py +0 -0
  388. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_cli_quality.py +0 -0
  389. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_cli_taps.py +0 -0
  390. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_cli_team.py +0 -0
  391. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_everyday_loop.py +0 -0
  392. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_integrity_enforce.py +0 -0
  393. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_property_parsers.py +0 -0
  394. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_run.py +0 -0
  395. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_tap_signing.py +0 -0
  396. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/functional/test_workspace_scope.py +0 -0
  397. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/README.md +0 -0
  398. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/frontmatter/01-typical.md +0 -0
  399. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/frontmatter/02-lossy-version.md +0 -0
  400. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/frontmatter/03-lossy-numbers.md +0 -0
  401. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/frontmatter/04-lists.md +0 -0
  402. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/frontmatter/05-nested.md +0 -0
  403. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/frontmatter/06-empty-block.md +0 -0
  404. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/frontmatter/07-unterminated.md +0 -0
  405. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/frontmatter/08-none.md +0 -0
  406. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/frontmatter/09-unbalanced-quote.md +0 -0
  407. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/frontmatter/10-keywords.md +0 -0
  408. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/frontmatter/11-crlf.md +0 -0
  409. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/frontmatter/12-bom.md +0 -0
  410. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/registry/01-shorthand.txt +0 -0
  411. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/registry/02-https.txt +0 -0
  412. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/registry/03-ssh.txt +0 -0
  413. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/registry/04-traversal.txt +0 -0
  414. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/registry/05-empty.txt +0 -0
  415. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/registry/06-space.txt +0 -0
  416. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/registry/07-slash.txt +0 -0
  417. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/corpus/registry/08-bare-host.txt +0 -0
  418. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/fuzz_frontmatter.py +0 -0
  419. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/fuzz/fuzz_registry.py +0 -0
  420. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/make_fixture.py +0 -0
  421. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/perf/test_benchmarks.py +0 -0
  422. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/smoke.sh +0 -0
  423. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_a11y_check.py +0 -0
  424. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_adapters.py +0 -0
  425. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_adapters_multi.py +0 -0
  426. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_adapters_runner.py +0 -0
  427. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_agents.py +0 -0
  428. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_ai.py +0 -0
  429. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_capabilities.py +0 -0
  430. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_catalog.py +0 -0
  431. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_check_anchors.py +0 -0
  432. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_claude_settings.py +0 -0
  433. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_cliparse.py +0 -0
  434. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_command_reference_fresh.py +0 -0
  435. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_community_health_files.py +0 -0
  436. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_config.py +0 -0
  437. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_dense.py +0 -0
  438. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_dense_fallback.py +0 -0
  439. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_dependabot_config.py +0 -0
  440. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_docs_pages_linked.py +0 -0
  441. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_docsite_chrome.py +0 -0
  442. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_ed25519.py +0 -0
  443. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_embed.py +0 -0
  444. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_errors_and_cli_table.py +0 -0
  445. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_eval_stats_summary.py +0 -0
  446. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_faithfulness.py +0 -0
  447. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_frontmatter.py +0 -0
  448. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_fuzz_targets.py +0 -0
  449. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_gitleaks_config.py +0 -0
  450. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_gitutil.py +0 -0
  451. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_imperative.py +0 -0
  452. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_import_budget.py +0 -0
  453. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_injectscan.py +0 -0
  454. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_integrity.py +0 -0
  455. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_journal.py +0 -0
  456. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_lockfile.py +0 -0
  457. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_logs.py +0 -0
  458. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_marketing_counts.py +0 -0
  459. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_mcp.py +0 -0
  460. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_mcpdecl.py +0 -0
  461. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_minisign.py +0 -0
  462. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_mutation_hardening.py +0 -0
  463. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_mutation_shards.py +0 -0
  464. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_mutmut_source_paths.py +0 -0
  465. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_nethttp.py +0 -0
  466. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_output.py +0 -0
  467. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_paths.py +0 -0
  468. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_perf_gate.py +0 -0
  469. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_pkg_confusions.py +0 -0
  470. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_pkg_injection.py +0 -0
  471. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_pkg_secrets.py +0 -0
  472. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_policy.py +0 -0
  473. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_post_deploy_smoke.py +0 -0
  474. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_projectlock.py +0 -0
  475. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_provenance.py +0 -0
  476. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_rag.py +0 -0
  477. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_registries_fresh.py +0 -0
  478. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_registry.py +0 -0
  479. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_release_preflight.py +0 -0
  480. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_required_checks.py +0 -0
  481. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_resolve.py +0 -0
  482. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_roadmap_fresh.py +0 -0
  483. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_rules.py +0 -0
  484. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_scopes.py +0 -0
  485. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_secretscan.py +0 -0
  486. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_selfupdate.py +0 -0
  487. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_serve.py +0 -0
  488. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_spin.py +0 -0
  489. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_stackprobe.py +0 -0
  490. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_staleness.py +0 -0
  491. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_store.py +0 -0
  492. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_token_parity.py +0 -0
  493. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_toolchain_lock.py +0 -0
  494. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_trustaudit.py +0 -0
  495. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_typosquat.py +0 -0
  496. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_updatediff.py +0 -0
  497. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_util.py +0 -0
  498. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_version.py +0 -0
  499. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_workflow_timeouts.py +0 -0
  500. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/unit/test_workflows.py +0 -0
  501. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/visual/a11y_check.mjs +0 -0
  502. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/visual/console_check.mjs +0 -0
  503. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/visual/package.json +0 -0
  504. {boost_skill_cli-1.0.265 → boost_skill_cli-1.0.267}/tests/visual/visual_check.mjs +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.265
3
+ Version: 1.0.267
4
4
  Summary: boost — Homebrew for AI coding skills
5
5
  Author: Jonathan Reyes
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '1.0.265'
22
- __version_tuple__ = version_tuple = (1, 0, 265)
21
+ __version__ = version = '1.0.267'
22
+ __version_tuple__ = version_tuple = (1, 0, 267)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -16,6 +16,7 @@ import threading
16
16
  import time
17
17
  import urllib.parse
18
18
  from pathlib import Path
19
+ from typing import Any, Dict, List
19
20
 
20
21
  from .. import cliparse, spin
21
22
  from ..core import (
@@ -217,7 +218,8 @@ def cmd_index(argv):
217
218
  if not shutil.which("gh"):
218
219
  raise BoostError("the GitHub CLI (gh) is required to build the index",
219
220
  hint="brew install gh && gh auth login")
220
- items, total = [], 0
221
+ items: List[dict] = []
222
+ total = 0
221
223
  pages = min((max(1, args.limit) + 99) // 100, 10) # code search caps at 1000
222
224
  for page in range(1, pages + 1):
223
225
  spin.progress(page, pages, "searching GitHub for SKILL.md")
@@ -399,7 +401,7 @@ def cmd_recommend(argv):
399
401
  raise BoostError("no skills in any tap to recommend from",
400
402
  hint="add registries with `boost tap --defaults`")
401
403
  stack = detect_stack(target)
402
- agg = {}
404
+ agg: Dict[str, Dict[str, Any]] = {}
403
405
  for kw in stack["keywords"]:
404
406
  for e, s in catalog.search(kw, entries):
405
407
  rec = agg.setdefault(e["name"], {"entry": e, "score": 0,
@@ -420,10 +422,15 @@ def cmd_recommend(argv):
420
422
  if stack["frameworks"]:
421
423
  line += " · frameworks: " + ", ".join(stack["frameworks"])
422
424
  out.info(out.role("%s (%s)" % (line, _tilde(target)), "muted"))
423
- shown = ranked[:args.limit]
425
+ shown: List[Dict[str, Any]] = ranked[:args.limit]
424
426
  if not shown:
425
- shown = [{"entry": e, "score": 0, "because": {"curated"}}
426
- for e in entries if e.get("curated")][:args.limit]
427
+ # Annotated rather than inlined: an unannotated literal of mixed value
428
+ # types infers dict[str, object], which then makes every r["entry"][…]
429
+ # read below an error about indexing `object`.
430
+ curated: List[Dict[str, Any]] = [
431
+ {"entry": e, "score": 0, "because": {"curated"}}
432
+ for e in entries if e.get("curated")]
433
+ shown = curated[:args.limit]
427
434
  if not shown:
428
435
  out.info("no recommendations for this stack — try `boost search <keyword>`")
429
436
  return 0
@@ -680,7 +687,7 @@ def _browse_tui(curses, entries):
680
687
  """Run the curses UI. Returns the list of entries picked for install
681
688
  (one or more, via multi-select), or None if the user quit without picking.
682
689
  """
683
- state = {"picks": None}
690
+ state: Dict[str, Any] = {"picks": None}
684
691
  categories = _tap_categories()
685
692
  desc_cache: dict = {}
686
693
  loading: set = set()
@@ -889,7 +896,7 @@ def cmd_trending(argv):
889
896
  out.truncate(e["description"], descw))
890
897
  for e in sorted(curated, key=operator.itemgetter("name"))[:args.limit]])
891
898
  return 0
892
- agg = {}
899
+ agg: Dict[str, Any] = {}
893
900
  for ev in evs: # most-recent-first, so first ts per subject is the latest
894
901
  name = ev.get("subject") or "?"
895
902
  rec = agg.setdefault(name, {"count": 0, "last": ev.get("ts", "")})
@@ -951,7 +958,7 @@ def cmd_stats(argv):
951
958
  out.kv("sha256", str(lock.get("sha256", ""))[:12])
952
959
  if size is not None:
953
960
  out.kv("size", util.human_size(size))
954
- else:
961
+ elif cat: # no lock means the guard above found a catalog entry
955
962
  out.kv("version", cat["version"])
956
963
  out.kv("tap", cat["tap"])
957
964
  out.kv("description", cat["description"])
@@ -14,6 +14,7 @@ import sys
14
14
  import textwrap
15
15
  import webbrowser
16
16
  from pathlib import Path
17
+ from typing import Dict, List
17
18
 
18
19
  from .. import cliparse
19
20
  from ..core import (
@@ -126,8 +127,8 @@ def _kind_table(heading, items, extra=None):
126
127
  ``(column, key)`` pair for a per-kind column (e.g. a workflow's slot); the
127
128
  count line reuses the heading's trailing noun (`installed rules` -> `rule`)."""
128
129
  out.heading(heading)
129
- headers = ("NAME", "VERSION", "TAP", "AGENTS")
130
- rows = []
130
+ headers: tuple = ("NAME", "VERSION", "TAP", "AGENTS") # `extra` adds a 5th
131
+ rows: List[tuple] = [] # 4 columns, or 5 when `extra` adds one
131
132
  for name in sorted(items):
132
133
  e = items[name]
133
134
  row = [name, e.get("version", "?"), e.get("tap", "?"),
@@ -179,7 +180,7 @@ def cmd_list(argv):
179
180
  return 0
180
181
  if skills:
181
182
  out.heading("installed skills")
182
- rows = []
183
+ rows: List[tuple] = [] # 5 columns here, 4 for project skills below
183
184
  for name in sorted(skills):
184
185
  e = skills[name]
185
186
  # Aurora-tinted flags — now that table() aligns by visible width,
@@ -227,7 +228,8 @@ def cmd_info(argv):
227
228
  if lock:
228
229
  matches = catalog.find(name)
229
230
  same_tap = [e for e in matches if e["tap"] == lock.get("tap")]
230
- cat = (same_tap or matches or [None])[0]
231
+ candidates = same_tap or matches
232
+ cat = candidates[0] if candidates else None
231
233
  else:
232
234
  cat = catalog.resolve_one(name) # raises if unknown anywhere
233
235
 
@@ -245,7 +247,7 @@ def cmd_info(argv):
245
247
  except BoostError:
246
248
  skill_dir = None
247
249
  desc = str((cat or {}).get("description") or "")
248
- meta = {}
250
+ meta: dict = {}
249
251
  skill_text = ""
250
252
  if skill_dir and (skill_dir / "SKILL.md").exists():
251
253
  skill_text = _read(skill_dir / "SKILL.md")
@@ -308,11 +310,11 @@ def cmd_info(argv):
308
310
  out.kv("latest", out.role(latest, "warn", bold=True)
309
311
  + out.role(" (update available)", "muted"))
310
312
  else:
311
- out.kv("latest", str(cat.get("version", "?")))
312
- out.kv("tap", (lock or cat).get("tap", "?"))
313
+ out.kv("latest", str((cat or {}).get("version", "?")))
314
+ out.kv("tap", (lock or cat or {}).get("tap", "?"))
313
315
  if lock and sdir.is_dir():
314
316
  out.kv("store", _tilde(sdir))
315
- src = lock.get("source_dir") if lock else cat.get("rel_dir")
317
+ src = lock.get("source_dir") if lock else (cat or {}).get("rel_dir")
316
318
  if src:
317
319
  out.kv("source", _tilde(src))
318
320
  if lock:
@@ -343,7 +345,9 @@ def cmd_info(argv):
343
345
  # A skill that needs an MCP server is useless without it, so this belongs
344
346
  # next to capabilities: both answer "what does this expect of my setup?"
345
347
  out.kv("mcp servers", ", ".join(r["name"] for r in mcp_servers))
346
- if score is not None:
348
+ # All three are set together under `if skill_dir` above; naming that here
349
+ # states the invariant instead of leaving it for a reader to reconstruct.
350
+ if score is not None and size is not None and files is not None:
347
351
  out.kv("quality", "%d/100" % score)
348
352
  out.kv("size", util.human_size(size))
349
353
  out.kv("files", str(files))
@@ -715,7 +719,9 @@ def cmd_deps(argv):
715
719
  out.info(" conflicts: %s %s" % (c_name, state))
716
720
  return 1 if problems else 0
717
721
 
718
- unmet, pairs, seen = [], [], set()
722
+ unmet: List[dict] = []
723
+ pairs: List[list] = [] # JSON-dumped, so lists rather than tuples
724
+ seen: set = set()
719
725
  for name in sorted(inst):
720
726
  meta = _skill_meta(name) or {}
721
727
  unmet.extend(
@@ -769,7 +775,7 @@ def cmd_tag(argv):
769
775
  mods = operands[1:]
770
776
 
771
777
  if args.list_all:
772
- mapping = {}
778
+ mapping: Dict[str, List[str]] = {}
773
779
  for name, e in sorted(lockfile.installed().items()):
774
780
  for t in e.get("tags") or []:
775
781
  mapping.setdefault(t, []).append(name)
@@ -15,7 +15,7 @@ from contextlib import suppress
15
15
  from datetime import datetime, timedelta, timezone
16
16
  from itertools import starmap
17
17
  from pathlib import Path
18
- from typing import List, Optional, Tuple
18
+ from typing import Any, Dict, List, Optional, Tuple
19
19
 
20
20
  from .. import cliparse
21
21
  from ..core import (
@@ -431,7 +431,7 @@ def cmd_lint(argv):
431
431
  out.info("nothing to lint")
432
432
  return 0
433
433
 
434
- results = []
434
+ results: List[Dict[str, Any]] = []
435
435
  for name, sdir in targets:
436
436
  score, notes = util.score_skill(sdir)
437
437
  meta, _ = _read_skill(sdir)
@@ -679,8 +679,8 @@ def cmd_conflict(argv):
679
679
  args = ap.parse_args(argv)
680
680
 
681
681
  installed = _iter_installed()
682
- rules = [] # (skill, line, polarity, stem set)
683
- declared = []
682
+ rules: List[Tuple[str, str, str, set]] = [] # skill, line, polarity, stems
683
+ declared: List[Tuple[str, str]] = [] # skill, conflicting skill
684
684
  installed_names = {n for n, _e in installed}
685
685
  for name, _entry in installed:
686
686
  meta, body = _read_skill(store.skill_store_dir(name))
@@ -705,12 +705,16 @@ def cmd_conflict(argv):
705
705
  if stem:
706
706
  rules.append((name, raw.strip(), polarity, stem))
707
707
 
708
- pairs, seen = [], set()
708
+ pairs: List[Dict[str, str]] = []
709
+ seen: set = set() # holds both key shapes below, declared and heuristic
709
710
  for da, db in declared:
710
- key = (*tuple(sorted((da, db))), "declared")
711
- if key in seen:
711
+ # Two different key SHAPES share `seen` — a flat triple here, a pair of
712
+ # (skill, line) pairs below. Distinct names because reusing one made the
713
+ # second `sorted()` type-check against the first one's element type.
714
+ dkey = (*tuple(sorted((da, db))), "declared")
715
+ if dkey in seen:
712
716
  continue
713
- seen.add(key)
717
+ seen.add(dkey)
714
718
  pairs.append({"kind": "declared", "a": da, "b": db,
715
719
  "a_line": "frontmatter declares conflicts: %s" % db,
716
720
  "b_line": ""})
@@ -720,10 +724,10 @@ def cmd_conflict(argv):
720
724
  continue
721
725
  small = min(len(a_stem), len(b_stem))
722
726
  if small and len(a_stem & b_stem) / small >= _CONFLICT_OVERLAP:
723
- key = tuple(sorted(((a_skill, a_line), (b_skill, b_line))))
724
- if key in seen:
727
+ hkey = tuple(sorted(((a_skill, a_line), (b_skill, b_line))))
728
+ if hkey in seen:
725
729
  continue
726
- seen.add(key)
730
+ seen.add(hkey)
727
731
  pairs.append({"kind": "heuristic", "a": a_skill, "b": b_skill,
728
732
  "a_line": a_line, "b_line": b_line})
729
733
 
@@ -12,6 +12,7 @@ import json
12
12
  import re
13
13
  import time
14
14
  from contextlib import suppress
15
+ from typing import Any, Dict, List
15
16
 
16
17
  from .. import cliparse
17
18
  from ..core import (
@@ -299,7 +300,7 @@ def cmd_verify(argv):
299
300
  hint="see what is with `boost list`")
300
301
  user_names = [n for n in (args.names or []) if n in lockfile.installed()]
301
302
 
302
- results = []
303
+ results: List[Dict[str, Any]] = []
303
304
  for name, entry in _iter_installed(user_names or (None if not args.names else [])):
304
305
  missing_fields = [f for f in ("version", "tap", "sha256", "installed_at")
305
306
  if not entry.get(f)]
@@ -381,13 +382,13 @@ def cmd_quarantine(argv):
381
382
 
382
383
  if args.list_mode:
383
384
  rows = []
384
- for name, entry in _iter_installed():
385
- if not entry.get("quarantined"):
385
+ for name, rec in _iter_installed():
386
+ if not rec.get("quarantined"):
386
387
  continue
387
388
  evs = journal.events(action="quarantine", subject=name)
388
389
  since = util.rel_time(evs[0].get("ts", "")) if evs else "?"
389
- rows.append((name, entry.get("version", "?"),
390
- entry.get("tap", "?"), since))
390
+ rows.append((name, rec.get("version", "?"),
391
+ rec.get("tap", "?"), since))
391
392
  if not rows:
392
393
  out.info("no skills in quarantine")
393
394
  return 0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.265
3
+ Version: 1.0.267
4
4
  Summary: boost — Homebrew for AI coding skills
5
5
  Author: Jonathan Reyes
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -333,6 +333,7 @@ scripts/build_command_reference.py
333
333
  scripts/build_registries.py
334
334
  scripts/build_roadmap.py
335
335
  scripts/check_anchors.py
336
+ scripts/check_licenses.py
336
337
  scripts/check_required_checks.py
337
338
  scripts/ensure_eval_corpus.sh
338
339
  scripts/eval_explain.py
@@ -426,6 +427,7 @@ tests/unit/test_ai.py
426
427
  tests/unit/test_capabilities.py
427
428
  tests/unit/test_catalog.py
428
429
  tests/unit/test_check_anchors.py
430
+ tests/unit/test_check_licenses.py
429
431
  tests/unit/test_claude_settings.py
430
432
  tests/unit/test_cliparse.py
431
433
  tests/unit/test_command_reference_fresh.py
@@ -177,6 +177,15 @@ files = ["boost_cli"]
177
177
  module = "boost_cli._version"
178
178
  ignore_missing_imports = true
179
179
 
180
+ # Every cmd_* function takes a bare `argv`, and mypy's default mode skips the
181
+ # BODY of any function with an untyped parameter — so the required "zero mypy
182
+ # errors" gate was checking almost none of the CLI's dispatch logic. This turns
183
+ # body checking on for the command layer without demanding annotated signatures
184
+ # (76 of them), which would be churn for no extra checking.
185
+ [[tool.mypy.overrides]]
186
+ module = "boost_cli.commands.*"
187
+ check_untyped_defs = true
188
+
180
189
  [tool.pytest.ini_options]
181
190
  testpaths = ["tests"]
182
191
  addopts = "-q -p no:cacheprovider"
@@ -15,3 +15,7 @@ twine
15
15
  check-wheel-contents
16
16
  pyroma
17
17
  pip-audit
18
+ # SPDX license compliance of a resolved closure (licenses.yml). Pinned for the
19
+ # same reason as the rest: a verdict that changes on an upstream release of the
20
+ # scanner is a verdict about the scanner, not about the dependencies.
21
+ pip-licenses
@@ -483,6 +483,10 @@ pip-audit==2.10.1 \
483
483
  --hash=sha256:1eb4565d19ebe5d48996f4b770b4d2b32887e12cb12cfa637f1a064011b55ffc \
484
484
  --hash=sha256:99ef3f600a317c1945f1e89e227ef26e1c2d618429b8bd3fa6f4f7c440c4611a
485
485
  # via -r requirements/release-tools.in
486
+ pip-licenses==5.5.5 \
487
+ --hash=sha256:60750c006adf7a0910347b726e8ee9fee3bc8d2e7c8307a5c4ec0776c8e2a276 \
488
+ --hash=sha256:f4c4c6d9e6a03612cf59f29f19dc8ab54904d82e055b8e191498f2279a224e14
489
+ # via -r requirements/release-tools.in
486
490
  pip-requirements-parser==32.0.1 \
487
491
  --hash=sha256:4659bc2a667783e7a15d190f6fccf8b2486685b6dba4c19c3876314769c57526 \
488
492
  --hash=sha256:b4fa3a7a0be38243123cf9d1f3518da10c51bdb165a2b2985566247f9155a7d3
@@ -491,6 +495,10 @@ platformdirs==4.11.0 \
491
495
  --hash=sha256:0555d18370482847566ffabcaa53ad7c6c1c29f195989ae1ed634a05f76ea1e0 \
492
496
  --hash=sha256:360ccded2b7fce0af0ff80cc8f5942a1c5d99b0e856033acb030bfc634709e74
493
497
  # via pip-audit
498
+ prettytable==3.18.0 \
499
+ --hash=sha256:439217116152244369caf3d9f1caf2f9fe29b03bd79e88d2928c8e718c95d680 \
500
+ --hash=sha256:b3346e0e6f79180833aebaac088ae926340586cf6d7d991b9eb125b65f72313a
501
+ # via pip-licenses
494
502
  py-serializable==2.1.0 \
495
503
  --hash=sha256:9d5db56154a867a9b897c0163b33a793c804c80cee984116d02d49e4578fc103 \
496
504
  --hash=sha256:b56d5d686b5a03ba4f4db5e769dc32336e142fc3bd4d68a8c25579ebb0a67304
@@ -767,6 +775,10 @@ urllib3==2.7.0 \
767
775
  # id
768
776
  # requests
769
777
  # twine
778
+ wcwidth==0.8.2 \
779
+ --hash=sha256:91fbef97204b96a3d4d421609b80340b760cf33e26da123ff243d76b1fda8dda \
780
+ --hash=sha256:d63947694a0539a1d51e01eda7caf800c291020e6cdd7e28ad7b14dd33ad4f85
781
+ # via prettytable
770
782
  wheel-filename==1.4.2 \
771
783
  --hash=sha256:3fa599046443d4ca830d06e3d180cd0a675d5871af0a68daa5623318bb4d17e3 \
772
784
  --hash=sha256:87891c465dcbb40b40394a906f01a93214bdd51aa5d25e3a9a59cae62bc298fd
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env python3
2
+ """Fail when a resolved dependency's licence is incompatible with GPL-3.0.
3
+
4
+ `pip-audit` gates known CVEs; nothing gated licence *terms*. boost's shipped
5
+ runtime is stdlib-only, so the exposure is entirely in the opt-in extras —
6
+ `[eval]` alone resolves to 94 packages, including the pinned langchain stack —
7
+ and none of them had ever been checked against the project's own GPL-3.0.
8
+
9
+ Reads ``pip-licenses --format=json`` (stdin, or a path) rather than shelling out,
10
+ so the check is a pure function of its input and can be unit-tested without a
11
+ resolved environment.
12
+
13
+ Why not ``pip-licenses --fail-on``: it compares the declared licence string
14
+ exactly, and that string is not a well-formed identifier. Real values observed
15
+ in boost's own `[eval]` closure:
16
+
17
+ ragas -> "UNKNOWN" (no licence metadata at all)
18
+ tiktoken -> "MIT License\\n\\nCopyright (c) 2022 OpenAI, …" (the whole text)
19
+ sqlite-vec -> "MIT License, Apache License, Version 2.0" (two, comma-joined)
20
+
21
+ so matching is done here by regex over the whole field instead.
22
+
23
+ Usage:
24
+ pip-licenses --format=json | python3 scripts/check_licenses.py
25
+ python3 scripts/check_licenses.py licenses.json
26
+ """
27
+ from __future__ import annotations
28
+
29
+ import json
30
+ import re
31
+ import sys
32
+ from typing import List, Tuple
33
+
34
+ # (pattern, why). Matched case-insensitively against the whole declared licence
35
+ # string. Deliberately short: the aim is high-confidence incompatibility, not a
36
+ # taxonomy. LGPL, MPL and EPL are all fine to *consume* from a GPL-3.0 project
37
+ # and are not listed.
38
+ DENIED: Tuple[Tuple[str, str], ...] = (
39
+ (r"affero|\bagpl\b",
40
+ "AGPL adds network-use copyleft that GPL-3.0 does not carry"),
41
+ # GPLv2-*only* cannot be combined with GPL-3.0. "v2 or later" / "GPLv2+"
42
+ # can (it permits taking v3), so both spellings are excluded explicitly.
43
+ (r"gplv2(?!\+)|gpl-2\.0(?!-or-later)|general public license v2 \(",
44
+ "GPLv2-only is incompatible with GPL-3.0"),
45
+ (r"proprietary|all rights reserved|\bsspl\b|commons clause|\bbusl\b",
46
+ "not an open-source licence"),
47
+ )
48
+
49
+ # Packages whose *metadata* omits a licence even though the project has one.
50
+ # Each needs the upstream licence named, so the exception is auditable rather
51
+ # than a silence. Anything undeclared and unlisted fails.
52
+ UNDECLARED_OK = {
53
+ # https://github.com/explodinggradients/ragas — Apache-2.0 in the repo;
54
+ # the published wheel carries no License field or classifier.
55
+ "ragas": "Apache-2.0 upstream; wheel metadata omits it",
56
+ }
57
+
58
+ _UNDECLARED = re.compile(r"^\s*(unknown|none|)\s*$", re.IGNORECASE)
59
+
60
+
61
+ def is_undeclared(licence: str) -> bool:
62
+ """True when the package declared no licence at all."""
63
+ return bool(_UNDECLARED.match(licence or ""))
64
+
65
+
66
+ def violations(rows: List[dict]) -> List[str]:
67
+ """Human-readable problems in a ``pip-licenses --format=json`` payload."""
68
+ problems = []
69
+ for row in rows:
70
+ name = str(row.get("Name", "?"))
71
+ licence = str(row.get("License", ""))
72
+ if is_undeclared(licence):
73
+ if name.lower() not in UNDECLARED_OK:
74
+ problems.append(
75
+ "%s declares no licence — add it to UNDECLARED_OK with the "
76
+ "upstream licence, or drop the dependency" % name)
77
+ continue
78
+ for pattern, why in DENIED:
79
+ if re.search(pattern, licence, re.IGNORECASE):
80
+ problems.append("%s: %s (%s)" % (
81
+ name, why, licence.splitlines()[0][:60]))
82
+ break
83
+ return problems
84
+
85
+
86
+ def main(argv: List[str]) -> int:
87
+ raw = (open(argv[0], encoding="utf-8").read() if argv
88
+ else sys.stdin.read())
89
+ try:
90
+ rows = json.loads(raw)
91
+ except ValueError as e:
92
+ print("::error::could not parse pip-licenses JSON: %s" % e)
93
+ return 2
94
+ if not isinstance(rows, list) or not rows:
95
+ # An empty scan is not a pass: it means the environment was never
96
+ # populated, which is how a licence gate quietly stops gating.
97
+ print("::error::no packages in the licence report — nothing was scanned")
98
+ return 2
99
+
100
+ problems = violations(rows)
101
+ for p in problems:
102
+ print("::error::%s" % p)
103
+ print("checked %d package(s): %d problem(s)" % (len(rows), len(problems)))
104
+ return 1 if problems else 0
105
+
106
+
107
+ if __name__ == "__main__":
108
+ sys.exit(main(sys.argv[1:]))
@@ -986,6 +986,17 @@ class TestStats:
986
986
  assert "Sync commits and PRs to Jira tickets" in r.out
987
987
  assert "0 installs · 0 updates · 0 uninstalls" in r.out
988
988
 
989
+ def test_installed_but_no_longer_in_any_tap(self, boost, installed):
990
+ # The asymmetric case: `lock` exists, `cat` is None. cmd_stats guards
991
+ # "neither" and then relies on that guard two screens later — enabling
992
+ # check_untyped_defs on the command layer is what surfaced the reliance,
993
+ # so it gets a test rather than an implicit invariant.
994
+ boost("untap", "fixture-tap", "--force")
995
+ r = boost("stats", "brainstorming")
996
+ assert "1.4.0" in r.out # version from the lock
997
+ assert "not installed" not in r.out
998
+ assert "0 installs" in r.out or "installs" in r.out
999
+
989
1000
  def test_unknown(self, boost, tapped):
990
1001
  r = boost("stats", "nope", expect=1)
991
1002
  assert "no skill named 'nope' installed or in any tap" in r.err
@@ -0,0 +1,163 @@
1
+ """Unit tests: scripts/check_licenses.py — the SPDX compatibility gate.
2
+
3
+ Driven against the licence strings dependencies *actually* publish, not against
4
+ tidy identifiers. Every awkward value below was observed in boost's own
5
+ resolved closures, which is the whole reason the check matches by regex instead
6
+ of using ``pip-licenses --fail-on``.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import importlib.util
11
+ import json
12
+ from pathlib import Path
13
+
14
+ import pytest
15
+
16
+ SCRIPT = Path(__file__).resolve().parents[2] / "scripts" / "check_licenses.py"
17
+
18
+ # Verbatim from `pip-licenses --format=json` over `pip install .[eval]`.
19
+ TIKTOKEN = ("MIT License\n\nCopyright (c) 2022 OpenAI, Shantanu Jain\n\n"
20
+ "Permission is hereby granted, free of charge, …")
21
+ SQLITE_VEC = "MIT License, Apache License, Version 2.0"
22
+
23
+
24
+ @pytest.fixture(scope="module")
25
+ def mod():
26
+ spec = importlib.util.spec_from_file_location("check_licenses", SCRIPT)
27
+ m = importlib.util.module_from_spec(spec)
28
+ assert spec.loader is not None
29
+ spec.loader.exec_module(m)
30
+ return m
31
+
32
+
33
+ def rows(*pairs):
34
+ return [{"Name": n, "Version": "1.0", "License": lic} for n, lic in pairs]
35
+
36
+
37
+ class TestPermissiveLicencesPass:
38
+ @pytest.mark.parametrize("licence", [
39
+ "MIT", "MIT License", "BSD License", "BSD-3-Clause", "Apache-2.0",
40
+ "Apache Software License", "Python Software Foundation License",
41
+ "PSF-2.0", "MIT-CMU", "Apache-2.0 OR BSD-2-Clause",
42
+ "BSD-3-Clause AND 0BSD AND MIT AND Zlib AND CC0-1.0",
43
+ "MPL-2.0 AND (Apache-2.0 OR MIT)",
44
+ "Mozilla Public License 2.0 (MPL 2.0)",
45
+ SQLITE_VEC, TIKTOKEN,
46
+ ])
47
+ def test_no_violation(self, mod, licence):
48
+ assert mod.violations(rows(("pkg", licence))) == []
49
+
50
+ def test_lgpl_and_mpl_are_fine_to_consume(self, mod):
51
+ # Weak copyleft is not a problem for a GPL-3.0 project, and banning it
52
+ # would fail builds for no reason.
53
+ assert mod.violations(rows(
54
+ ("a", "GNU Lesser General Public License v3 (LGPLv3)"),
55
+ ("b", "GNU Lesser General Public License v2 or later (LGPLv2+)"),
56
+ ("c", "Mozilla Public License 2.0 (MPL 2.0)"),
57
+ ("d", "Eclipse Public License 2.0"))) == []
58
+
59
+ def test_gplv3_and_gplv2_or_later_pass(self, mod):
60
+ # GPL-3.0 is the project's own licence; "v2 or later" permits taking
61
+ # v3, so both combine cleanly. Only v2-*only* does not.
62
+ assert mod.violations(rows(
63
+ ("a", "GNU General Public License v3 (GPLv3)"),
64
+ ("b", "GNU General Public License v2 or later (GPLv2+)"),
65
+ ("c", "GPL-2.0-or-later"))) == []
66
+
67
+
68
+ class TestIncompatibleLicencesFail:
69
+ @pytest.mark.parametrize("licence", [
70
+ "GNU Affero General Public License v3",
71
+ "AGPL-3.0", "AGPL-3.0-only", "agpl-3.0-or-later",
72
+ ])
73
+ def test_agpl(self, mod, licence):
74
+ [problem] = mod.violations(rows(("pkg", licence)))
75
+ assert "network-use copyleft" in problem
76
+ assert problem.startswith("pkg: ")
77
+
78
+ @pytest.mark.parametrize("licence", [
79
+ "GNU General Public License v2 (GPLv2)", "GPL-2.0", "GPL-2.0-only",
80
+ ])
81
+ def test_gplv2_only(self, mod, licence):
82
+ [problem] = mod.violations(rows(("pkg", licence)))
83
+ assert "GPLv2-only" in problem
84
+
85
+ @pytest.mark.parametrize("licence", [
86
+ "Other/Proprietary License", "Proprietary", "All Rights Reserved",
87
+ "SSPL-1.0", "BUSL-1.1", "MIT with Commons Clause",
88
+ ])
89
+ def test_non_open_source(self, mod, licence):
90
+ [problem] = mod.violations(rows(("pkg", licence)))
91
+ assert "not an open-source licence" in problem
92
+
93
+ def test_a_multi_line_licence_reports_only_its_first_line(self, mod):
94
+ # A whole licence text in the failure message would bury the finding.
95
+ [problem] = mod.violations(rows(
96
+ ("pkg", "Other/Proprietary License\n\nblah\n" * 40)))
97
+ assert "\n" not in problem
98
+ assert len(problem) < 200
99
+
100
+ def test_every_offender_is_reported_not_just_the_first(self, mod):
101
+ problems = mod.violations(rows(("a", "AGPL-3.0"), ("b", "MIT"),
102
+ ("c", "Other/Proprietary License")))
103
+ assert len(problems) == 2
104
+ assert problems[0].startswith("a: ") and problems[1].startswith("c: ")
105
+
106
+ def test_a_package_is_reported_once_even_if_it_trips_twice(self, mod):
107
+ [problem] = mod.violations(rows(("pkg", "AGPL-3.0 AND Proprietary")))
108
+ assert problem.startswith("pkg: ")
109
+
110
+
111
+ class TestUndeclaredLicences:
112
+ @pytest.mark.parametrize("licence", ["UNKNOWN", "unknown", "", " ", "None"])
113
+ def test_recognised_as_undeclared(self, mod, licence):
114
+ assert mod.is_undeclared(licence) is True
115
+
116
+ @pytest.mark.parametrize("licence", ["MIT", "Unknown Software License"])
117
+ def test_not_undeclared(self, mod, licence):
118
+ assert mod.is_undeclared(licence) is False
119
+
120
+ def test_an_undeclared_package_fails_by_default(self, mod):
121
+ [problem] = mod.violations(rows(("mystery", "UNKNOWN")))
122
+ assert "declares no licence" in problem
123
+
124
+ def test_the_documented_exception_passes(self, mod):
125
+ # ragas is Apache-2.0 upstream; its wheel carries no License field.
126
+ assert mod.violations(rows(("ragas", "UNKNOWN"))) == []
127
+ assert "ragas" in mod.UNDECLARED_OK
128
+
129
+ def test_every_exception_names_the_upstream_licence(self, mod):
130
+ # An allowlist entry with no reason is indistinguishable from silence.
131
+ for pkg, reason in mod.UNDECLARED_OK.items():
132
+ assert reason.strip(), pkg
133
+ assert pkg == pkg.lower(), "keys are matched lowercased"
134
+
135
+
136
+ class TestMain:
137
+ def test_a_clean_report_exits_zero(self, mod, tmp_path, capsys):
138
+ p = tmp_path / "l.json"
139
+ p.write_text(json.dumps(rows(("a", "MIT"))), encoding="utf-8")
140
+ assert mod.main([str(p)]) == 0
141
+ assert "1 package(s): 0 problem(s)" in capsys.readouterr().out
142
+
143
+ def test_a_violation_exits_one_with_an_annotation(self, mod, tmp_path,
144
+ capsys):
145
+ p = tmp_path / "l.json"
146
+ p.write_text(json.dumps(rows(("a", "AGPL-3.0"))), encoding="utf-8")
147
+ assert mod.main([str(p)]) == 1
148
+ assert "::error::a: AGPL" in capsys.readouterr().out
149
+
150
+ def test_an_empty_report_is_a_failure_not_a_pass(self, mod, tmp_path,
151
+ capsys):
152
+ # This is how a licence gate quietly stops gating: the environment was
153
+ # never populated, every package passes, the step goes green.
154
+ p = tmp_path / "l.json"
155
+ p.write_text("[]", encoding="utf-8")
156
+ assert mod.main([str(p)]) == 2
157
+ assert "nothing was scanned" in capsys.readouterr().out
158
+
159
+ def test_unparseable_input_is_a_failure(self, mod, tmp_path, capsys):
160
+ p = tmp_path / "l.json"
161
+ p.write_text("not json", encoding="utf-8")
162
+ assert mod.main([str(p)]) == 2
163
+ assert "could not parse" in capsys.readouterr().out