boost-skill-cli 1.0.206__tar.gz → 1.0.208__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 (397) hide show
  1. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/.vale/styles/config/vocabularies/boost/accept.txt +1 -0
  2. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/CONTRIBUTING.md +23 -2
  3. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/Makefile +11 -2
  4. {boost_skill_cli-1.0.206/boost_skill_cli.egg-info → boost_skill_cli-1.0.208}/PKG-INFO +1 -1
  5. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/_version.py +2 -2
  6. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/commands/info.py +6 -0
  7. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/commands/pkg.py +69 -0
  8. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/commands/quality.py +4 -1
  9. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/commands/safety.py +158 -2
  10. boost_skill_cli-1.0.208/boost_cli/core/mcpdecl.py +193 -0
  11. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/store.py +29 -0
  12. boost_skill_cli-1.0.208/boost_cli/core/trustaudit.py +224 -0
  13. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208/boost_skill_cli.egg-info}/PKG-INFO +1 -1
  14. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_skill_cli.egg-info/SOURCES.txt +15 -0
  15. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/commands.html +8 -6
  16. boost_skill_cli-1.0.208/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +31 -0
  17. boost_skill_cli-1.0.208/docs/roadmap/items/installed-skill-trust-audit.md +29 -0
  18. boost_skill_cli-1.0.208/docs/roadmap/items/mcp-aware-skills.md +32 -0
  19. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap.html +48 -26
  20. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/noxfile.py +15 -4
  21. boost_skill_cli-1.0.208/requirements/coverage-tools.in +11 -0
  22. boost_skill_cli-1.0.208/requirements/coverage-tools.txt +344 -0
  23. boost_skill_cli-1.0.206/requirements/lint-tools.txt → boost_skill_cli-1.0.208/requirements/lint-tools.in +12 -8
  24. boost_skill_cli-1.0.208/requirements/lint-tools.txt +593 -0
  25. boost_skill_cli-1.0.208/requirements/mutation-tools.in +16 -0
  26. boost_skill_cli-1.0.208/requirements/mutation-tools.txt +567 -0
  27. boost_skill_cli-1.0.208/requirements/release-tools.in +17 -0
  28. boost_skill_cli-1.0.208/requirements/release-tools.txt +773 -0
  29. boost_skill_cli-1.0.208/requirements/test-tools.in +16 -0
  30. boost_skill_cli-1.0.208/requirements/test-tools.txt +391 -0
  31. boost_skill_cli-1.0.208/scripts/lock_toolchain.py +153 -0
  32. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/setup.cfg +2 -0
  33. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_cli_pkg.py +151 -0
  34. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_cli_quality.py +65 -0
  35. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/smoke.sh +8 -0
  36. boost_skill_cli-1.0.208/tests/unit/test_mcpdecl.py +355 -0
  37. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_output.py +30 -0
  38. boost_skill_cli-1.0.208/tests/unit/test_toolchain_lock.py +137 -0
  39. boost_skill_cli-1.0.208/tests/unit/test_trustaudit.py +369 -0
  40. boost_skill_cli-1.0.206/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -20
  41. boost_skill_cli-1.0.206/docs/roadmap/items/installed-skill-trust-audit.md +0 -25
  42. boost_skill_cli-1.0.206/docs/roadmap/items/mcp-aware-skills.md +0 -25
  43. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/.gitattributes +0 -0
  44. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/.gitignore +0 -0
  45. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/.gitleaks.toml +0 -0
  46. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/.htmlvalidate.json +0 -0
  47. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/.lighthouserc.json +0 -0
  48. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/.lycheeignore +0 -0
  49. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/.markdownlint-cli2.jsonc +0 -0
  50. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/.pre-commit-config.yaml +0 -0
  51. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/.stylelintrc.json +0 -0
  52. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/.vale/styles/boost/Terminology.yml +0 -0
  53. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/.vale.ini +0 -0
  54. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/CLAUDE.md +0 -0
  55. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/LICENSE +0 -0
  56. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/MANIFEST.in +0 -0
  57. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/README.md +0 -0
  58. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/SECURITY.md +0 -0
  59. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost +0 -0
  60. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/__init__.py +0 -0
  61. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/__main__.py +0 -0
  62. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/cli.py +0 -0
  63. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/cliparse.py +0 -0
  64. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/commands/__init__.py +0 -0
  65. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/commands/_common.py +0 -0
  66. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/commands/bmad.py +0 -0
  67. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/commands/configuration.py +0 -0
  68. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/commands/discovery.py +0 -0
  69. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/commands/hooks.py +0 -0
  70. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/commands/intelligence.py +0 -0
  71. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/commands/run.py +0 -0
  72. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/commands/taps.py +0 -0
  73. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/commands/team.py +0 -0
  74. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/__init__.py +0 -0
  75. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/adapters.py +0 -0
  76. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/agents.py +0 -0
  77. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/ai.py +0 -0
  78. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/capabilities.py +0 -0
  79. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/catalog.py +0 -0
  80. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/claude_settings.py +0 -0
  81. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/config.py +0 -0
  82. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/dense.py +0 -0
  83. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/ed25519.py +0 -0
  84. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/embed.py +0 -0
  85. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/faithfulness.py +0 -0
  86. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/frontmatter.py +0 -0
  87. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/gitutil.py +0 -0
  88. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/imperative.py +0 -0
  89. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/injectscan.py +0 -0
  90. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/integrity.py +0 -0
  91. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/journal.py +0 -0
  92. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/lockfile.py +0 -0
  93. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/logs.py +0 -0
  94. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/mcp.py +0 -0
  95. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/minisign.py +0 -0
  96. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/nethttp.py +0 -0
  97. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/output.py +0 -0
  98. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/paths.py +0 -0
  99. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/policy.py +0 -0
  100. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/projectlock.py +0 -0
  101. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/provenance.py +0 -0
  102. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/rag.py +0 -0
  103. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/registry.py +0 -0
  104. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/resolve.py +0 -0
  105. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/rules.py +0 -0
  106. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/scopes.py +0 -0
  107. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/secretscan.py +0 -0
  108. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/serve.py +0 -0
  109. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/stackprobe.py +0 -0
  110. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/staleness.py +0 -0
  111. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/typosquat.py +0 -0
  112. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/updatediff.py +0 -0
  113. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/util.py +0 -0
  114. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/core/workflows.py +0 -0
  115. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/data/registries.json +0 -0
  116. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/errors.py +0 -0
  117. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_cli/spin.py +0 -0
  118. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
  119. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_skill_cli.egg-info/entry_points.txt +0 -0
  120. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_skill_cli.egg-info/requires.txt +0 -0
  121. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/boost_skill_cli.egg-info/top_level.txt +0 -0
  122. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/.claude/settings.local.json +0 -0
  123. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/DEBUGGING.md +0 -0
  124. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/adapters.html +0 -0
  125. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/demo.gif +0 -0
  126. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/demo.tape +0 -0
  127. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/design-roadmap.html +0 -0
  128. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/eval.html +0 -0
  129. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/index.html +0 -0
  130. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/mcp-hub.html +0 -0
  131. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/rag-architecture.md +0 -0
  132. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D01.md +0 -0
  133. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D02.md +0 -0
  134. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D03.md +0 -0
  135. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D04.md +0 -0
  136. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D05.md +0 -0
  137. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D06.md +0 -0
  138. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D07.md +0 -0
  139. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D08.md +0 -0
  140. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D09.md +0 -0
  141. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D10.md +0 -0
  142. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D11.md +0 -0
  143. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D12.md +0 -0
  144. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D13.md +0 -0
  145. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D14.md +0 -0
  146. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D15.md +0 -0
  147. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D16.md +0 -0
  148. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D17.md +0 -0
  149. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D18.md +0 -0
  150. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D19.md +0 -0
  151. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D20.md +0 -0
  152. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D21.md +0 -0
  153. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D22.md +0 -0
  154. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D23.md +0 -0
  155. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D24.md +0 -0
  156. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D25.md +0 -0
  157. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D26.md +0 -0
  158. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
  159. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
  160. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
  161. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
  162. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/boost-run-live-agents.md +0 -0
  163. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
  164. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
  165. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
  166. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
  167. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
  168. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
  169. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
  170. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/command-reference-docs-site.md +0 -0
  171. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
  172. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
  173. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
  174. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
  175. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
  176. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
  177. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/docsite-chrome-and-content-audit.md +0 -0
  178. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
  179. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
  180. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
  181. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
  182. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
  183. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
  184. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
  185. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
  186. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
  187. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/framework-adapter-multi-agent.md +0 -0
  188. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
  189. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
  190. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
  191. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
  192. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/html-validation-html-validate.md +0 -0
  193. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/install-resolves-skill-dependencies.md +0 -0
  194. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/install-scope-user-or-project.md +0 -0
  195. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
  196. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
  197. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
  198. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
  199. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
  200. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
  201. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
  202. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
  203. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
  204. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
  205. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
  206. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
  207. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
  208. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
  209. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/mcp-search-before-reinventing.md +0 -0
  210. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
  211. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
  212. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
  213. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
  214. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
  215. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
  216. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
  217. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
  218. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
  219. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
  220. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
  221. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/pin-the-lint-toolchain.md +0 -0
  222. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
  223. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
  224. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/project-scope-across-every-command.md +0 -0
  225. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/project-scope-symlink-escape-on-write.md +0 -0
  226. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
  227. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
  228. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
  229. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
  230. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
  231. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
  232. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
  233. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
  234. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
  235. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
  236. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
  237. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
  238. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
  239. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
  240. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
  241. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
  242. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
  243. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
  244. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
  245. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
  246. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
  247. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
  248. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
  249. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
  250. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
  251. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
  252. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
  253. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
  254. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
  255. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
  256. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
  257. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
  258. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/typo-detection-codespell.md +0 -0
  259. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
  260. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
  261. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
  262. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/update-diff-before-apply.md +0 -0
  263. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
  264. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
  265. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
  266. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
  267. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
  268. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
  269. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
  270. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/docs/roadmap/items/workspace-scope-install.md +0 -0
  271. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/eslint.config.mjs +0 -0
  272. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/examples/README.md +0 -0
  273. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/examples/adapt-demo.sh +0 -0
  274. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/examples/boost-run-prototype.sh +0 -0
  275. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/index.html +0 -0
  276. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/pyproject.toml +0 -0
  277. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/scripts/bench_cli.sh +0 -0
  278. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/scripts/build_command_reference.py +0 -0
  279. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/scripts/build_registries.py +0 -0
  280. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/scripts/build_roadmap.py +0 -0
  281. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/scripts/check_anchors.py +0 -0
  282. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/scripts/ensure_eval_corpus.sh +0 -0
  283. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/scripts/eval_explain.py +0 -0
  284. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/scripts/eval_recommend.py +0 -0
  285. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/scripts/eval_retrieval.py +0 -0
  286. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/scripts/eval_stats_summary.py +0 -0
  287. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/scripts/import_budget.py +0 -0
  288. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/scripts/mutation_gate.py +0 -0
  289. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/scripts/perf_gate.py +0 -0
  290. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/style/README.md +0 -0
  291. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/style/boost.css +0 -0
  292. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/style/boost.js +0 -0
  293. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/style/demo.html +0 -0
  294. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/bdd/features/adapt.feature +0 -0
  295. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/bdd/features/browse.feature +0 -0
  296. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/bdd/features/count.feature +0 -0
  297. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/bdd/features/discover.feature +0 -0
  298. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/bdd/features/doctor.feature +0 -0
  299. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/bdd/features/environment.py +0 -0
  300. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/bdd/features/explain.feature +0 -0
  301. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/bdd/features/index.feature +0 -0
  302. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/bdd/features/install.feature +0 -0
  303. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/bdd/features/list.feature +0 -0
  304. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/bdd/features/mcp.feature +0 -0
  305. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/bdd/features/search.feature +0 -0
  306. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/bdd/features/steps/cli_steps.py +0 -0
  307. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/bdd/features/steps/discovery_steps.py +0 -0
  308. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/bdd/features/steps/mcp_steps.py +0 -0
  309. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/bdd/features/steps/quality_steps.py +0 -0
  310. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/conftest.py +0 -0
  311. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/eval/baseline.json +0 -0
  312. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/eval/explain.jsonl +0 -0
  313. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/eval/golden.jsonl +0 -0
  314. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/eval/recommend.jsonl +0 -0
  315. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/eval/taps.txt +0 -0
  316. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_capabilities_policy.py +0 -0
  317. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_cli_adapt.py +0 -0
  318. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_cli_bmad.py +0 -0
  319. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_cli_configuration.py +0 -0
  320. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_cli_discovery.py +0 -0
  321. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_cli_hooks.py +0 -0
  322. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_cli_info.py +0 -0
  323. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_cli_intelligence.py +0 -0
  324. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_cli_taps.py +0 -0
  325. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_cli_team.py +0 -0
  326. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_everyday_loop.py +0 -0
  327. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_integrity_enforce.py +0 -0
  328. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_property_parsers.py +0 -0
  329. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_run.py +0 -0
  330. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_tap_signing.py +0 -0
  331. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/functional/test_workspace_scope.py +0 -0
  332. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/make_fixture.py +0 -0
  333. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/perf/test_benchmarks.py +0 -0
  334. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_adapters.py +0 -0
  335. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_adapters_multi.py +0 -0
  336. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_adapters_runner.py +0 -0
  337. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_agents.py +0 -0
  338. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_ai.py +0 -0
  339. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_capabilities.py +0 -0
  340. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_catalog.py +0 -0
  341. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_check_anchors.py +0 -0
  342. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_claude_settings.py +0 -0
  343. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_cliparse.py +0 -0
  344. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_command_reference_fresh.py +0 -0
  345. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_config.py +0 -0
  346. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_dense.py +0 -0
  347. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_dense_fallback.py +0 -0
  348. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_docs_pages_linked.py +0 -0
  349. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_docsite_chrome.py +0 -0
  350. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_ed25519.py +0 -0
  351. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_embed.py +0 -0
  352. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_errors_and_cli_table.py +0 -0
  353. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_eval_stats_summary.py +0 -0
  354. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_faithfulness.py +0 -0
  355. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_frontmatter.py +0 -0
  356. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_gitleaks_config.py +0 -0
  357. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_gitutil.py +0 -0
  358. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_imperative.py +0 -0
  359. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_import_budget.py +0 -0
  360. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_injectscan.py +0 -0
  361. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_integrity.py +0 -0
  362. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_journal.py +0 -0
  363. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_lockfile.py +0 -0
  364. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_logs.py +0 -0
  365. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_mcp.py +0 -0
  366. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_minisign.py +0 -0
  367. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_mutation_hardening.py +0 -0
  368. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_nethttp.py +0 -0
  369. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_paths.py +0 -0
  370. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_perf_gate.py +0 -0
  371. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_pkg_confusions.py +0 -0
  372. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_pkg_injection.py +0 -0
  373. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_pkg_secrets.py +0 -0
  374. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_policy.py +0 -0
  375. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_projectlock.py +0 -0
  376. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_provenance.py +0 -0
  377. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_rag.py +0 -0
  378. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_registries_fresh.py +0 -0
  379. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_registry.py +0 -0
  380. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_resolve.py +0 -0
  381. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_roadmap_fresh.py +0 -0
  382. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_rules.py +0 -0
  383. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_scopes.py +0 -0
  384. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_secretscan.py +0 -0
  385. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_serve.py +0 -0
  386. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_spin.py +0 -0
  387. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_stackprobe.py +0 -0
  388. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_staleness.py +0 -0
  389. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_store.py +0 -0
  390. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_token_parity.py +0 -0
  391. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_typosquat.py +0 -0
  392. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_updatediff.py +0 -0
  393. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_util.py +0 -0
  394. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_version.py +0 -0
  395. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/unit/test_workflows.py +0 -0
  396. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/visual/package.json +0 -0
  397. {boost_skill_cli-1.0.206 → boost_skill_cli-1.0.208}/tests/visual/visual_check.mjs +0 -0
@@ -56,6 +56,7 @@ tempdir
56
56
  toggleable
57
57
  Tokenization
58
58
  tokenization
59
+ toolchain
59
60
  toolkits
60
61
  traceback
61
62
  tracebacks
@@ -7,12 +7,31 @@ so contributing is mostly about keeping the quality gates green.
7
7
 
8
8
  ```bash
9
9
  git clone https://github.com/jonnyeclectic/boost && cd boost
10
- make venv # pytest, coverage, mutmut, ruff, mypy — runtime stays stdlib-only
10
+ make venv # every gate tool, hash-pinned — runtime stays stdlib-only
11
11
  ```
12
12
 
13
13
  Every test runs against a throwaway `$HOME`, so nothing touches your real
14
14
  agent configs.
15
15
 
16
+ ### The toolchain is hash-pinned
17
+
18
+ `make venv` and every CI job install from the generated
19
+ [`requirements/*.txt`](requirements/), which pin an exact version **and every
20
+ artifact's sha256** for the full transitive closure — pip enforces those hashes,
21
+ so a yanked or tampered dependency fails the install instead of silently
22
+ changing a build. Your venv and the CI runner get identical bytes.
23
+
24
+ To change a tool, edit the `.in` file and regenerate:
25
+
26
+ ```bash
27
+ python3 scripts/lock_toolchain.py # rewrite the .txt files
28
+ python3 scripts/lock_toolchain.py --upgrade # re-resolve to newest allowed
29
+ python3 scripts/lock_toolchain.py --check # what `make lint` runs
30
+ ```
31
+
32
+ Commit both the `.in` and the regenerated `.txt`; a stale lock fails `make lint`.
33
+ Regenerating needs `uv` (installed by `make venv`); *installing* never does.
34
+
16
35
  ### Reproduce the whole gate — `nox`
17
36
 
18
37
  [`noxfile.py`](noxfile.py) runs the exact gate the CI jobs run, in isolated
@@ -50,7 +69,7 @@ auto-fixes straight back onto the branch.
50
69
  |---|---|
51
70
  | `make test` | unit + functional suites, **≥80% line coverage** |
52
71
  | `make patch-coverage` | changed-line coverage vs `main`, **≥80% of the diff** (PRs) |
53
- | `bash tests/smoke.sh` | 152 end-to-end checks through the real `./boost` shim |
72
+ | `bash tests/smoke.sh` | 170 end-to-end checks through the real `./boost` shim |
54
73
  | `make mutation` | mutmut over `boost_cli/core`, **≥80% mutants killed** |
55
74
  | `ruff check boost_cli tests` | lint, zero findings |
56
75
  | `mypy` | type check, zero errors |
@@ -58,6 +77,8 @@ auto-fixes straight back onto the branch.
58
77
  | `lint-imports` | layering: `core/` imports no `commands/`/`cli`; CLI depends inward |
59
78
  | `vulture` | dead-code radar: no unused imports / unreachable code (confidence ≥80) |
60
79
  | `xenon` | complexity ratchet: aggregate cyclomatic complexity can't regress (avg ≤B) |
80
+ | `refurb boost_cli` | modernization smells the ruff families miss, zero findings |
81
+ | `scripts/lock_toolchain.py --check` | the hash-pinned toolchain matches its `.in` declarations |
61
82
 
62
83
  ## Ground rules
63
84
 
@@ -12,10 +12,18 @@ EVAL_HOME := $(CURDIR)/.eval-home
12
12
 
13
13
  .PHONY: venv test unit functional smoke coverage patch-coverage mutation lint check demo clean-test eval eval-ai eval-rec eval-stats eval-explain audit dist-check bdd bench bench-cli
14
14
 
15
+ # Every tool comes from a hash-pinned requirements/*.txt — the same files CI
16
+ # installs (see scripts/lock_toolchain.py). pip enforces the hashes, so a dev
17
+ # venv and a CI runner resolve to identical bytes. mutation-tools.txt is a
18
+ # superset of test-tools.txt, so installing it alone covers both; the two are
19
+ # never layered because pip enforces hashes across the whole resolution.
15
20
  venv:
16
21
  python3 -m venv $(VENV)
17
- $(VENV)/bin/pip -q install pytest pytest-cov coverage mutmut hypothesis diff-cover
18
- $(VENV)/bin/pip -q install -r requirements/lint-tools.txt # pinned; CI installs the same set
22
+ $(VENV)/bin/pip -q install -r requirements/mutation-tools.txt
23
+ $(VENV)/bin/pip -q install -r requirements/coverage-tools.txt
24
+ $(VENV)/bin/pip -q install -r requirements/lint-tools.txt
25
+ $(VENV)/bin/pip -q install -r requirements/release-tools.txt
26
+ $(VENV)/bin/pip -q install uv # regenerates the locks; not itself locked
19
27
 
20
28
  unit:
21
29
  $(PYTEST) tests/unit -q
@@ -57,6 +65,7 @@ lint:
57
65
  $(PY) scripts/build_registries.py --check
58
66
  $(PY) scripts/build_roadmap.py --check
59
67
  $(PY) scripts/build_command_reference.py --check
68
+ $(PY) scripts/lock_toolchain.py --check
60
69
  $(PY) scripts/import_budget.py
61
70
  $(PY) scripts/perf_gate.py
62
71
  $(PY) scripts/check_anchors.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.206
3
+ Version: 1.0.208
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.206'
22
- __version_tuple__ = version_tuple = (1, 0, 206)
21
+ __version__ = version = '1.0.208'
22
+ __version_tuple__ = version_tuple = (1, 0, 208)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -239,6 +239,7 @@ def cmd_info(argv):
239
239
  declared_caps = sorted(capabilities.declared(meta))
240
240
  detected_extra = sorted(capabilities.detect(skill_text)
241
241
  - set(declared_caps)) if skill_text else []
242
+ mcp_servers = store.declared_mcp_servers(skill_dir) if skill_dir else []
242
243
  score = size = files = None
243
244
  if skill_dir:
244
245
  score, _notes = util.score_skill(skill_dir)
@@ -249,6 +250,7 @@ def cmd_info(argv):
249
250
  "name": name, "description": desc,
250
251
  "installed": lock, "project": plock,
251
252
  "capabilities": declared_caps, "detected_capabilities": detected_extra,
253
+ "mcp_servers": [r["name"] for r in mcp_servers],
252
254
  "latest": (cat or {}).get("version"),
253
255
  "tap": (lock or plock or cat or {}).get("tap"),
254
256
  "store": str(sdir) if lock and sdir.is_dir() else None,
@@ -322,6 +324,10 @@ def cmd_info(argv):
322
324
  # under-declaration signal a reviewer wants to see.
323
325
  out.kv("detected", out.role(", ".join(detected_extra) + " (not declared)",
324
326
  "warn"))
327
+ if mcp_servers:
328
+ # A skill that needs an MCP server is useless without it, so this belongs
329
+ # next to capabilities: both answer "what does this expect of my setup?"
330
+ out.kv("mcp servers", ", ".join(r["name"] for r in mcp_servers))
325
331
  if score is not None:
326
332
  out.kv("quality", "%d/100" % score)
327
333
  out.kv("size", util.human_size(size))
@@ -109,6 +109,67 @@ def _warn_secrets(res: store.InstallResult) -> None:
109
109
  out.warn(" L%d [%s] %s" % (f.line, f.severity, f.description))
110
110
 
111
111
 
112
+ def _offer_mcp(res: store.InstallResult) -> None:
113
+ """Surface the MCP servers a just-installed skill needs, and offer to wire them.
114
+
115
+ A skill that only works paired with an MCP server used to install "cleanly"
116
+ and then fail in the agent for a reason nothing surfaced. Now the requirement
117
+ is stated at install time, and boost offers to run the registration for the
118
+ servers that came with a runnable spec.
119
+
120
+ Advisory, never fatal: a declined prompt, a missing ``claude`` CLI or a failed
121
+ registration all leave the skill installed. Suppressed entirely by
122
+ ``--no-mcp``, which sets ``BOOST_NO_MCP_OFFER``.
123
+ """
124
+ rows = res.mcp_servers
125
+ if not rows or os.environ.get("BOOST_NO_MCP_OFFER"):
126
+ return
127
+ from ..core import mcpdecl
128
+ out.info("")
129
+ out.warn("%s needs %s to work:" % (res.name, _plural(len(rows), "MCP server")))
130
+ for row in rows:
131
+ how = ("`%s`" % row["spec"]["command"] if row["spec"]
132
+ and row["spec"].get("command") else "no command declared")
133
+ out.info(" %s %s" % (out.c(row["name"], out.BOLD),
134
+ out.role(how, "muted")))
135
+ wirable = mcpdecl.registrable(rows)
136
+ if not wirable:
137
+ # Name-only declarations: boost will not invent a command line.
138
+ out.dim(" install these yourself, then `boost mcp register`")
139
+ return
140
+ if not out.confirm("register %s with Claude Code now?"
141
+ % _plural(len(wirable), "server"), default=False):
142
+ out.dim(" skipped — `claude mcp add …` when you're ready")
143
+ return
144
+ for row in wirable:
145
+ _register_mcp_server(row["name"], row["spec"])
146
+
147
+
148
+ def _register_mcp_server(name: str, spec: dict) -> None:
149
+ """Run one `claude mcp add` for a skill-declared server. Never raises."""
150
+ import subprocess
151
+ from ..core import mcpdecl
152
+ argv = mcpdecl.register_argv(name, spec)
153
+ if not shutil.which("claude"):
154
+ out.warn("`claude` CLI not found — run this yourself:")
155
+ out.info(" " + " ".join(argv))
156
+ return
157
+ try:
158
+ proc = subprocess.run(argv, capture_output=True, text=True, timeout=60)
159
+ except (OSError, subprocess.TimeoutExpired) as e:
160
+ out.warn("could not register %s: %s" % (name, e))
161
+ out.info(" run it yourself: " + " ".join(argv))
162
+ return
163
+ if proc.returncode != 0:
164
+ tail = (proc.stderr or "").strip().splitlines()
165
+ out.warn("could not register %s: %s"
166
+ % (name, tail[-1] if tail else "unknown error"))
167
+ out.info(" run it yourself: " + " ".join(argv))
168
+ return
169
+ out.ok("registered MCP server %s" % name)
170
+ journal.log("mcp-register", name)
171
+
172
+
112
173
  def _report_result(res: store.InstallResult) -> None:
113
174
  """The canonical three-line install report."""
114
175
  if res.kind in ("rule", "workflow"):
@@ -141,6 +202,7 @@ def _report_result(res: store.InstallResult) -> None:
141
202
  out.ok("lock updated (.skill-lock.json)")
142
203
  _warn_injection(res)
143
204
  _warn_secrets(res)
205
+ _offer_mcp(res)
144
206
 
145
207
 
146
208
  def _boostfile_text(skills: Dict[str, dict], via: str = "boost bundle dump") -> str:
@@ -238,8 +300,15 @@ def cmd_install(argv: List[str]) -> int:
238
300
  help="show what would happen without changing anything")
239
301
  ap.add_argument("--no-deps", action="store_true",
240
302
  help="install only the named skills, not their `requires:`")
303
+ ap.add_argument("--no-mcp", action="store_true",
304
+ help="don't offer to register MCP servers a skill declares")
241
305
  args = ap.parse_args(argv)
242
306
  args.scope = args.scope or scopes.SCOPE_USER
307
+ if args.no_mcp:
308
+ # An env flag rather than threading a parameter through _report_result's
309
+ # eight call sites: the offer is a leaf-level side effect, and this keeps
310
+ # every other install path (update, reinstall, team, MCP tool) unchanged.
311
+ os.environ["BOOST_NO_MCP_OFFER"] = "1"
243
312
  only = _check_agents(args.agent)
244
313
  multi = len(args.names) > 1
245
314
  entries, failed = [], 0
@@ -848,7 +848,10 @@ def cmd_health(argv):
848
848
  _PROVENANCE_STYLE = {
849
849
  provenance.VERIFIED: "success",
850
850
  provenance.UNTRUSTED: "warn",
851
- provenance.INVALID: "err",
851
+ # "danger", not "err": out.role() looks the name up in output.ROLES, which
852
+ # has no "err" key — so an invalid tap signature raised KeyError on any
853
+ # color terminal. The suite never caught it because conftest sets NO_COLOR.
854
+ provenance.INVALID: "danger",
852
855
  provenance.UNSIGNED: "muted",
853
856
  }
854
857
 
@@ -10,11 +10,13 @@ from __future__ import annotations
10
10
 
11
11
  import json
12
12
  import re
13
+ import time
14
+ from contextlib import suppress
13
15
 
14
16
  from .. import cliparse
15
- from ..core import integrity, journal, lockfile
17
+ from ..core import catalog, frontmatter, gitutil, integrity, journal, lockfile
16
18
  from ..core import output as out
17
- from ..core import policy, store, util
19
+ from ..core import policy, provenance, registry, staleness, store, trustaudit, util
18
20
  from ..errors import BoostError
19
21
  from ._common import _iter_installed, _s
20
22
 
@@ -42,8 +44,14 @@ def cmd_audit(argv):
42
44
  prog="boost audit",
43
45
  description="Check installed skills against a safety blocklist")
44
46
  ap.add_argument("--json", action="store_true")
47
+ ap.add_argument("--skills", action="store_true",
48
+ help="trust/staleness report for installed skills instead "
49
+ "of the content scan")
45
50
  args = ap.parse_args(argv)
46
51
 
52
+ if args.skills:
53
+ return _trust_audit(args.json)
54
+
47
55
  pol = policy.load()
48
56
  installed = _iter_installed()
49
57
  findings: dict = {}
@@ -110,6 +118,154 @@ def cmd_audit(argv):
110
118
  return 1 if counts["HIGH"] or counts["MED"] else 0
111
119
 
112
120
 
121
+ # --- audit --skills: trust & staleness across the whole installed set ------
122
+ #
123
+ # The signals already existed, one per command: `trust` reports tap signing,
124
+ # `outdated` reports drift vs the tap, `deps` shows the conflicts: graph. This
125
+ # gathers all three over the installed set and hands the decision to
126
+ # core/trustaudit.py, which is where every branch of it is unit-tested.
127
+
128
+ _TRUST_ROLE = {trustaudit.HIGH: "danger", trustaudit.MED: "warn",
129
+ trustaudit.LOW: "muted"}
130
+
131
+
132
+ def _tap_age_days(tap):
133
+ """Days since a tap clone's last commit, or ``None`` when unknowable."""
134
+ try:
135
+ proc = gitutil.run(["-C", str(tap.path), "log", "-1", "--format=%ct"],
136
+ check=False)
137
+ except BoostError:
138
+ return None
139
+ if proc.returncode != 0 or not proc.stdout.strip():
140
+ return None
141
+ try:
142
+ committed = int(proc.stdout.strip())
143
+ except ValueError:
144
+ return None
145
+ return max(0, int((time.time() - committed) // 86400))
146
+
147
+
148
+ def _tap_signals(tap_name, cache):
149
+ """``(provenance status, age in days, HEAD commit)`` for a tap, memoized.
150
+
151
+ A tap boost cannot read — unknown name, never cloned — yields
152
+ ``(None, None, "")``, which ``trustaudit`` renders as "signature cannot be
153
+ checked" rather than silently passing.
154
+ """
155
+ if tap_name not in cache:
156
+ try:
157
+ tap = registry.get(tap_name)
158
+ except BoostError:
159
+ cache[tap_name] = (None, None, "")
160
+ else:
161
+ cache[tap_name] = ((provenance.verify_dir(tap.path).status,
162
+ _tap_age_days(tap), gitutil.head_commit(tap.path))
163
+ if tap.is_cloned else (None, None, ""))
164
+ return cache[tap_name]
165
+
166
+
167
+ def _upstream_reason(name, lk, tap_name, head):
168
+ """``staleness.upstream_reason`` for one installed skill, or ``None``.
169
+
170
+ Same signal-gathering order as ``cmd_outdated`` so the two commands can
171
+ never disagree about whether a skill is behind its tap.
172
+ """
173
+ matches = [e for e in catalog.find(name) if e["tap"] == tap_name]
174
+ if not matches:
175
+ return None
176
+ entry = matches[0]
177
+ latest = str(entry.get("version") or "0.0.0")
178
+ installed_v = str(lk.get("version") or "0.0.0")
179
+ src_sha = None
180
+ if not util.semver_gt(latest, installed_v) and head and head != lk.get("commit"):
181
+ try:
182
+ src_sha = util.sha256_dir(store.source_dir_for(entry))
183
+ except BoostError:
184
+ return None # source checkout is gone; `verify` owns that finding
185
+ return staleness.upstream_reason(installed_v, latest, lk.get("commit", ""),
186
+ head, lk.get("sha256", ""), src_sha)
187
+
188
+
189
+ def _installed_conflicts(names):
190
+ """A ``conflicts_of`` callable reading each installed skill's own copy.
191
+
192
+ Reads the store copy rather than the catalog on purpose: the audit is about
193
+ what is *installed*, which can be an older revision than the tap now
194
+ advertises.
195
+ """
196
+ cache: dict = {}
197
+
198
+ def conflicts_of(name):
199
+ if name not in cache:
200
+ meta: dict = {}
201
+ # unreadable store copy: `verify` owns that finding, not this
202
+ with suppress(OSError, BoostError):
203
+ text = (store.skill_store_dir(name) / "SKILL.md").read_text(
204
+ encoding="utf-8", errors="replace")
205
+ meta, _body = frontmatter.parse(text)
206
+ cache[name] = trustaudit.relation_list(meta, "conflicts")
207
+ return cache[name]
208
+
209
+ return conflicts_of
210
+
211
+
212
+ def _trust_audit(as_json: bool) -> int:
213
+ """`boost audit --skills` — one trust-health answer for the installed set."""
214
+ installed = dict(_iter_installed())
215
+ peers: dict = {}
216
+ for name, peer in trustaudit.conflict_pairs(list(installed),
217
+ _installed_conflicts(installed)):
218
+ peers.setdefault(name, []).append(peer)
219
+
220
+ taps: dict = {}
221
+ findings: dict = {}
222
+ for name, lk in sorted(installed.items()):
223
+ tap_name = str(lk.get("tap") or "local")
224
+ is_local = tap_name == "local"
225
+ status, age, head = ((None, None, "") if is_local
226
+ else _tap_signals(tap_name, taps))
227
+ rows = trustaudit.skill_findings(
228
+ is_local=is_local, provenance_status=status, tap_age_days=age,
229
+ upstream_reason=(None if is_local
230
+ else _upstream_reason(name, lk, tap_name, head)),
231
+ conflicts_with=peers.get(name, ()))
232
+ if rows:
233
+ findings[name] = rows
234
+
235
+ counts = trustaudit.count_severities(findings)
236
+ rc = trustaudit.exit_code(counts)
237
+ if as_json:
238
+ print(json.dumps({"skills_scanned": len(installed),
239
+ "findings": findings, "counts": counts}, indent=2))
240
+ return rc
241
+ return _render_trust_audit(installed, findings, counts, rc)
242
+
243
+
244
+ def _render_trust_audit(installed, findings, counts, rc: int) -> int:
245
+ """Human rendering for `boost audit --skills`."""
246
+ total = len(installed)
247
+ out.heading("trust audit — %d skill%s" % (total, _s(total)))
248
+ if not total:
249
+ out.info("nothing installed yet — `boost install <skill>` to start")
250
+ return rc
251
+ if not findings:
252
+ out.ok("all %d installed skill%s signed, current and conflict-free"
253
+ % (total, _s(total)))
254
+ return rc
255
+ for name in sorted(findings):
256
+ print(" " + out.c(name, out.BOLD))
257
+ for f in findings[name]:
258
+ print(" %s %s %s"
259
+ % (out.role(f["severity"].ljust(4), _TRUST_ROLE[f["severity"]]),
260
+ f["label"], out.role(f["detail"], "muted")))
261
+ print()
262
+ out.verdict(trustaudit.is_healthy(counts),
263
+ "%d high · %d medium · %d low across %d of %d skill%s"
264
+ % (counts[trustaudit.HIGH], counts[trustaudit.MED],
265
+ counts[trustaudit.LOW], len(findings), total, _s(total)))
266
+ return rc
267
+
268
+
113
269
  def cmd_verify(argv):
114
270
  ap = cliparse.parser(
115
271
  prog="boost verify",
@@ -0,0 +1,193 @@
1
+ """What MCP servers does a skill need, and how do we wire them?
2
+
3
+ Mining boost's catalog surfaces a recurring shape: skills that only work paired
4
+ with a Model Context Protocol server (``manage-mcp-servers``, ``mcp-builder``,
5
+ ``mcp-integration`` and dozens more). boost already *is* an MCP server and
6
+ registers itself with ``boost mcp register`` — but a skill had no way to say
7
+ "I need server Y," so installing one left the user to discover that by hand.
8
+
9
+ Two declaration forms, both deliberately **flat**:
10
+
11
+ * ``mcp: github, playwright`` in SKILL.md frontmatter (a comma string or a YAML
12
+ block list) — just the names, reusing the exact contract ``requires:`` and
13
+ ``conflicts:`` already use.
14
+ * a bundled ``.mcp.json`` in the skill directory — the standard MCP shape
15
+ (``{"mcpServers": {name: {command, args, env}}}``), carrying full specs.
16
+
17
+ Why flat, and not the nested ``mcp:`` mapping the roadmap card sketched:
18
+ :mod:`boost_cli.core.frontmatter` is a stdlib-only YAML *subset* with no nested
19
+ mapping support, and it does not fail loudly on one — it hoists the inner keys to
20
+ top level and clobbers their siblings. A nested block parses to
21
+ ``{'mcp': '', 'servers': [...], 'command': 'npx'}``, silently corrupting the
22
+ entry's metadata. Teaching the parser nested mappings would change the shape of
23
+ every catalog entry's ``meta`` (and every consumer of it), so the declaration
24
+ meets the parser where it already works and the full specs live in the standard
25
+ sidecar file that needs no parser at all.
26
+
27
+ Everything here is pure and I/O-free, like :mod:`boost_cli.core.resolve` and
28
+ :mod:`boost_cli.core.staleness`: callers read the files and pass text in, so
29
+ every branch of the *decision* is unit-testable and reachable by the mutation
30
+ gate.
31
+ """
32
+ from __future__ import annotations
33
+
34
+ import json
35
+ from typing import Dict, List, Optional, Tuple
36
+
37
+ # The frontmatter key a skill uses to name the servers it needs.
38
+ DECL_KEY = "mcp"
39
+
40
+ # The sidecar file a skill bundles to carry full server specs. Standard MCP
41
+ # filename and shape, so an author can lift the file straight from a server's
42
+ # own README.
43
+ SIDECAR = ".mcp.json"
44
+
45
+ # Top-level key inside .mcp.json, per the MCP config convention.
46
+ SERVERS_KEY = "mcpServers"
47
+
48
+ # Ownership tag written alongside a server boost registered, mirroring
49
+ # claude_settings.MARKER. Without it an uninstall could not tell a
50
+ # boost-registered server from one the user configured by hand, so it would
51
+ # either strip the user's config or leak boost's.
52
+ MARKER_KEY = "x-boost-skill"
53
+
54
+
55
+ def declared_names(meta: Optional[dict]) -> List[str]:
56
+ """Server names a skill's frontmatter declares, de-duped, order preserved.
57
+
58
+ Accepts a YAML list or a comma-separated string and drops blanks — the same
59
+ contract ``requires:``/``conflicts:`` use, so an author who knows one knows
60
+ this one. A missing/empty/``False`` value means "declares nothing".
61
+ """
62
+ val = (meta or {}).get(DECL_KEY)
63
+ if val in (None, "", False):
64
+ return []
65
+ raw = ([str(x) for x in val] if isinstance(val, list)
66
+ else str(val).split(","))
67
+ out: List[str] = []
68
+ for item in raw:
69
+ name = item.strip()
70
+ if name and name not in out:
71
+ out.append(name)
72
+ return out
73
+
74
+
75
+ def parse_sidecar(text: Optional[str]) -> Dict[str, dict]:
76
+ """``{name: spec}`` from a bundled ``.mcp.json``'s text.
77
+
78
+ Tolerant by design: unreadable JSON, a non-object document, a missing or
79
+ non-object ``mcpServers`` key, and non-object individual specs all read as
80
+ "no specs". A malformed sidecar must never make an otherwise-fine install
81
+ fail — the skill still works, the user just does not get the wiring offer.
82
+ """
83
+ if not text:
84
+ return {}
85
+ try:
86
+ doc = json.loads(text)
87
+ except (ValueError, TypeError):
88
+ return {}
89
+ if not isinstance(doc, dict):
90
+ return {}
91
+ servers = doc.get(SERVERS_KEY)
92
+ if not isinstance(servers, dict):
93
+ return {}
94
+ return {str(k): v for k, v in servers.items()
95
+ if k and isinstance(v, dict)}
96
+
97
+
98
+ def servers_for(meta: Optional[dict], sidecar_text: Optional[str] = None,
99
+ ) -> List[dict]:
100
+ """Every MCP server a skill needs, as ``{"name", "spec", "source"}`` rows.
101
+
102
+ Merges the two declaration forms. A name in *both* uses the sidecar's spec —
103
+ the frontmatter only names a server, so a bundled spec is strictly more
104
+ information. ``spec`` is ``None`` for a name-only declaration, which the
105
+ caller renders as "you need this, here is no command to run it" rather than
106
+ offering a registration it cannot perform.
107
+
108
+ ``source`` is ``"sidecar"`` or ``"frontmatter"``, so output can tell the user
109
+ where a requirement came from when the two disagree. Rows are sorted by name
110
+ for deterministic output.
111
+ """
112
+ specs = parse_sidecar(sidecar_text)
113
+ rows: Dict[str, dict] = {
114
+ name: {"name": name, "spec": spec, "source": "sidecar"}
115
+ for name, spec in specs.items()}
116
+ for name in declared_names(meta):
117
+ if name not in rows:
118
+ rows[name] = {"name": name, "spec": None, "source": "frontmatter"}
119
+ return [rows[k] for k in sorted(rows)]
120
+
121
+
122
+ def registrable(rows) -> List[dict]:
123
+ """The rows boost can actually wire up — those carrying a runnable spec.
124
+
125
+ A spec is runnable when it names a ``command``. Anything else (a name-only
126
+ frontmatter declaration, or a sidecar entry describing a remote/URL server
127
+ boost has no launcher for) is reported to the user but never auto-registered:
128
+ boost will not invent a command line on an author's behalf.
129
+ """
130
+ return [r for r in rows
131
+ if isinstance(r.get("spec"), dict)
132
+ and str(r["spec"].get("command") or "").strip()]
133
+
134
+
135
+ def register_argv(name: str, spec: dict, *, scope: str = "user") -> List[str]:
136
+ """The ``claude mcp add`` argv that registers one declared server.
137
+
138
+ Mirrors ``cmd_mcp``'s invariant exactly: the server **name** precedes every
139
+ ``-e`` flag, and a bare ``--`` separates boost's flags from the server's own
140
+ command and arguments. Getting that order wrong makes the CLI read the
141
+ command as another flag value, which is why it is pinned by a test.
142
+ """
143
+ argv = ["claude", "mcp", "add", name, "--scope", scope]
144
+ env = spec.get("env")
145
+ if isinstance(env, dict):
146
+ for key in sorted(env):
147
+ argv += ["-e", "%s=%s" % (key, env[key])]
148
+ argv.extend(("--", str(spec["command"])))
149
+ args = spec.get("args")
150
+ if isinstance(args, list):
151
+ argv += [str(a) for a in args]
152
+ return argv
153
+
154
+
155
+ def merge_into(existing: Optional[dict], rows, skill: str) -> Tuple[dict, List[str]]:
156
+ """Add ``rows``' specs to an ``.mcp.json`` document -> ``(doc, added)``.
157
+
158
+ Returns a **new** document rather than mutating the caller's, and never
159
+ overwrites a server the user already configured: a name already present is
160
+ left exactly as-is and omitted from ``added``. Each entry boost does add
161
+ carries a :data:`MARKER_KEY` naming the skill that asked for it, so a later
162
+ uninstall can remove precisely what boost wrote and nothing else.
163
+ """
164
+ doc = dict(existing) if isinstance(existing, dict) else {}
165
+ servers = dict(doc.get(SERVERS_KEY) or {})
166
+ added: List[str] = []
167
+ for row in registrable(rows):
168
+ name = row["name"]
169
+ if name in servers:
170
+ continue
171
+ entry = dict(row["spec"])
172
+ entry[MARKER_KEY] = skill
173
+ servers[name] = entry
174
+ added.append(name)
175
+ doc[SERVERS_KEY] = servers
176
+ return doc, added
177
+
178
+
179
+ def strip_owned(existing: Optional[dict], skill: str) -> Tuple[dict, List[str]]:
180
+ """Remove the servers boost registered for ``skill`` -> ``(doc, removed)``.
181
+
182
+ Only entries whose :data:`MARKER_KEY` names this skill are removed, so a
183
+ server the user configured by hand — or one another skill still needs —
184
+ survives an uninstall untouched.
185
+ """
186
+ doc = dict(existing) if isinstance(existing, dict) else {}
187
+ servers = dict(doc.get(SERVERS_KEY) or {})
188
+ removed = [name for name, spec in servers.items()
189
+ if isinstance(spec, dict) and spec.get(MARKER_KEY) == skill]
190
+ for name in removed:
191
+ del servers[name]
192
+ doc[SERVERS_KEY] = servers
193
+ return doc, sorted(removed)