boost-skill-cli 1.0.230__tar.gz → 1.0.232__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 (485) hide show
  1. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/PKG-INFO +1 -1
  2. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/_version.py +2 -2
  3. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/configuration.py +44 -4
  4. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/pkg.py +8 -0
  5. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/catalog.py +9 -2
  6. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/registry.py +17 -3
  7. boost_skill_cli-1.0.232/boost_cli/core/selfupdate.py +138 -0
  8. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/store.py +65 -5
  9. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_skill_cli.egg-info/PKG-INFO +1 -1
  10. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_skill_cli.egg-info/SOURCES.txt +2 -0
  11. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/commands.html +7 -3
  12. boost_skill_cli-1.0.232/docs/roadmap/items/ambiguous-tap-short-name-resolution.md +23 -0
  13. boost_skill_cli-1.0.232/docs/roadmap/items/self-update-broken-for-pip-pipx-installs.md +31 -0
  14. boost_skill_cli-1.0.232/docs/roadmap/items/sync-deletes-unowned-broken-symlinks.md +35 -0
  15. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap.html +29 -6
  16. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_configuration.py +114 -6
  17. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_pkg.py +19 -0
  18. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_catalog.py +24 -0
  19. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_registry.py +41 -0
  20. boost_skill_cli-1.0.232/tests/unit/test_selfupdate.py +265 -0
  21. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_store.py +91 -0
  22. boost_skill_cli-1.0.230/docs/roadmap/items/ambiguous-tap-short-name-resolution.md +0 -22
  23. boost_skill_cli-1.0.230/docs/roadmap/items/self-update-broken-for-pip-pipx-installs.md +0 -22
  24. boost_skill_cli-1.0.230/docs/roadmap/items/sync-deletes-unowned-broken-symlinks.md +0 -22
  25. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.gitattributes +0 -0
  26. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.gitignore +0 -0
  27. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.gitleaks.toml +0 -0
  28. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.htmlvalidate.json +0 -0
  29. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.lighthouserc.json +0 -0
  30. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.lycheeignore +0 -0
  31. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.markdownlint-cli2.jsonc +0 -0
  32. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.pre-commit-config.yaml +0 -0
  33. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.stylelintrc.json +0 -0
  34. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.vale/styles/boost/Terminology.yml +0 -0
  35. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.vale/styles/config/vocabularies/boost/accept.txt +0 -0
  36. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.vale.ini +0 -0
  37. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/CLAUDE.md +0 -0
  38. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/CONTRIBUTING.md +0 -0
  39. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/LICENSE +0 -0
  40. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/MANIFEST.in +0 -0
  41. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/Makefile +0 -0
  42. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/README.md +0 -0
  43. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/SECURITY.md +0 -0
  44. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost +0 -0
  45. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/__init__.py +0 -0
  46. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/__main__.py +0 -0
  47. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/cli.py +0 -0
  48. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/cliparse.py +0 -0
  49. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/__init__.py +0 -0
  50. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/_common.py +0 -0
  51. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/bmad.py +0 -0
  52. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/discovery.py +0 -0
  53. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/hooks.py +0 -0
  54. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/info.py +0 -0
  55. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/intelligence.py +0 -0
  56. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/quality.py +0 -0
  57. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/run.py +0 -0
  58. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/safety.py +0 -0
  59. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/taps.py +0 -0
  60. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/team.py +0 -0
  61. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/__init__.py +0 -0
  62. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/adapters.py +0 -0
  63. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/agents.py +0 -0
  64. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/ai.py +0 -0
  65. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/capabilities.py +0 -0
  66. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/claude_settings.py +0 -0
  67. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/config.py +0 -0
  68. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/dense.py +0 -0
  69. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/ed25519.py +0 -0
  70. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/embed.py +0 -0
  71. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/faithfulness.py +0 -0
  72. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/frontmatter.py +0 -0
  73. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/gitutil.py +0 -0
  74. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/imperative.py +0 -0
  75. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/injectscan.py +0 -0
  76. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/integrity.py +0 -0
  77. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/journal.py +0 -0
  78. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/lockfile.py +0 -0
  79. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/logs.py +0 -0
  80. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/mcp.py +0 -0
  81. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/mcpdecl.py +0 -0
  82. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/minisign.py +0 -0
  83. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/nethttp.py +0 -0
  84. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/output.py +0 -0
  85. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/paths.py +0 -0
  86. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/policy.py +0 -0
  87. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/projectlock.py +0 -0
  88. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/provenance.py +0 -0
  89. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/rag.py +0 -0
  90. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/resolve.py +0 -0
  91. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/rules.py +0 -0
  92. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/scopes.py +0 -0
  93. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/secretscan.py +0 -0
  94. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/serve.py +0 -0
  95. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/stackprobe.py +0 -0
  96. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/staleness.py +0 -0
  97. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/trustaudit.py +0 -0
  98. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/typosquat.py +0 -0
  99. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/updatediff.py +0 -0
  100. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/util.py +0 -0
  101. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/workflows.py +0 -0
  102. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/data/registries.json +0 -0
  103. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/errors.py +0 -0
  104. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/spin.py +0 -0
  105. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
  106. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_skill_cli.egg-info/entry_points.txt +0 -0
  107. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_skill_cli.egg-info/requires.txt +0 -0
  108. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_skill_cli.egg-info/top_level.txt +0 -0
  109. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/codecov.yml +0 -0
  110. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/.claude/settings.local.json +0 -0
  111. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/DEBUGGING.md +0 -0
  112. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/adapters.html +0 -0
  113. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/gifs/distill.gif +0 -0
  114. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/gifs/doctor.gif +0 -0
  115. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/gifs/explain.gif +0 -0
  116. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/gifs/hooks.gif +0 -0
  117. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/gifs/install.gif +0 -0
  118. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/gifs/pulse.gif +0 -0
  119. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/gifs/search.gif +0 -0
  120. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/gifs/tap.gif +0 -0
  121. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/tapes/distill.tape +0 -0
  122. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/tapes/doctor.tape +0 -0
  123. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/tapes/explain.tape +0 -0
  124. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/tapes/hooks.tape +0 -0
  125. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/tapes/install.tape +0 -0
  126. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/tapes/pulse.tape +0 -0
  127. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/tapes/search.tape +0 -0
  128. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/tapes/tap.tape +0 -0
  129. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel.html +0 -0
  130. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/demo.gif +0 -0
  131. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/demo.tape +0 -0
  132. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/design-roadmap.html +0 -0
  133. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/eval.html +0 -0
  134. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/index.html +0 -0
  135. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/mcp-hub.html +0 -0
  136. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/rag-architecture.md +0 -0
  137. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D01.md +0 -0
  138. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D02.md +0 -0
  139. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D03.md +0 -0
  140. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D04.md +0 -0
  141. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D05.md +0 -0
  142. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D06.md +0 -0
  143. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D07.md +0 -0
  144. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D08.md +0 -0
  145. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D09.md +0 -0
  146. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D10.md +0 -0
  147. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D11.md +0 -0
  148. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D12.md +0 -0
  149. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D13.md +0 -0
  150. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D14.md +0 -0
  151. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D15.md +0 -0
  152. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D16.md +0 -0
  153. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D17.md +0 -0
  154. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D18.md +0 -0
  155. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D19.md +0 -0
  156. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D20.md +0 -0
  157. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D21.md +0 -0
  158. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D22.md +0 -0
  159. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D23.md +0 -0
  160. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D24.md +0 -0
  161. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D25.md +0 -0
  162. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D26.md +0 -0
  163. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
  164. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/ai-bridge-silent-failure-logging.md +0 -0
  165. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
  166. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
  167. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
  168. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/boost-run-live-agents.md +0 -0
  169. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
  170. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
  171. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
  172. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
  173. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
  174. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
  175. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/ci-job-timeout-minutes.md +0 -0
  176. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
  177. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/command-carousel-page.md +0 -0
  178. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/command-reference-docs-site.md +0 -0
  179. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
  180. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
  181. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
  182. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
  183. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/crash-listing-branch-untested.md +0 -0
  184. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
  185. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/dense-search-fallback-and-stale-tap-pruning.md +0 -0
  186. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/dependabot-missing-pip-ecosystem.md +0 -0
  187. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
  188. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/docsite-chrome-and-content-audit.md +0 -0
  189. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
  190. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
  191. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
  192. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
  193. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
  194. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
  195. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
  196. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
  197. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
  198. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/framework-adapter-multi-agent.md +0 -0
  199. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
  200. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
  201. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/github-community-health-files.md +0 -0
  202. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
  203. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
  204. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
  205. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/html-validation-html-validate.md +0 -0
  206. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/install-from-path-bypasses-policy-and-pin-checks.md +0 -0
  207. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/install-resolves-skill-dependencies.md +0 -0
  208. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/install-scope-user-or-project.md +0 -0
  209. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/installed-skill-trust-audit.md +0 -0
  210. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
  211. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
  212. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/journal-rotation-race-and-handle-leak.md +0 -0
  213. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
  214. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/license-compliance-scanning.md +0 -0
  215. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
  216. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/lint-tap-misscopes-rule-workflow-entries.md +0 -0
  217. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
  218. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
  219. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/lock-invariant-cannot-parse-extras-pins.md +0 -0
  220. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
  221. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
  222. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
  223. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/main-has-no-branch-protection.md +0 -0
  224. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
  225. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
  226. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mcp-aware-skills.md +0 -0
  227. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
  228. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
  229. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
  230. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mcp-search-before-reinventing.md +0 -0
  231. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
  232. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
  233. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
  234. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
  235. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
  236. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
  237. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mypy-strict-mode-for-commands.md +0 -0
  238. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/negative-limit-inverts-log-pulse-output.md +0 -0
  239. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/onboard-overwrites-generated-files-without-confirm.md +0 -0
  240. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
  241. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
  242. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
  243. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
  244. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/path-traversal-unsanitized-rule-workflow-name.md +0 -0
  245. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
  246. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/pin-the-lint-toolchain.md +0 -0
  247. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
  248. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
  249. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/project-scope-across-every-command.md +0 -0
  250. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/project-scope-symlink-escape-on-write.md +0 -0
  251. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
  252. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
  253. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
  254. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
  255. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
  256. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/publish-gate-ignores-pip-audit-and-metadata.md +0 -0
  257. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/pytest-tmpdir-cve-blocked-by-py39-floor.md +0 -0
  258. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
  259. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
  260. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
  261. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
  262. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/rel-time-tests-race-the-wall-clock.md +0 -0
  263. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/required-checks-can-declare-a-check-that-deadlocks-prs.md +0 -0
  264. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/required-checks-config-drift.md +0 -0
  265. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
  266. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
  267. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
  268. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/ruff-016-widens-the-default-rule-set.md +0 -0
  269. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
  270. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
  271. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
  272. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
  273. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
  274. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
  275. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/scorecard-findings-triage.md +0 -0
  276. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
  277. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
  278. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
  279. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
  280. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/serve-py-traversal-guards-untested.md +0 -0
  281. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
  282. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
  283. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
  284. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
  285. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
  286. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
  287. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/structured-json-log-output-mode.md +0 -0
  288. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
  289. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
  290. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
  291. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
  292. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/typo-detection-codespell.md +0 -0
  293. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
  294. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
  295. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/uninstall-has-no-confirmation-prompt.md +0 -0
  296. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
  297. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/update-diff-before-apply.md +0 -0
  298. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
  299. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/update-reinstall-widens-agent-scope.md +0 -0
  300. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
  301. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
  302. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
  303. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/wire-bdd-suite-into-ci.md +0 -0
  304. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
  305. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
  306. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
  307. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/workspace-scope-install.md +0 -0
  308. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/eslint.config.mjs +0 -0
  309. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/examples/README.md +0 -0
  310. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/examples/adapt-demo.sh +0 -0
  311. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/examples/boost-run-prototype.sh +0 -0
  312. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/index.html +0 -0
  313. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/noxfile.py +0 -0
  314. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/pyproject.toml +0 -0
  315. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/coverage-tools.in +0 -0
  316. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/coverage-tools.txt +0 -0
  317. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/lint-tools.in +0 -0
  318. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/lint-tools.txt +0 -0
  319. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/mutation-tools.in +0 -0
  320. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/mutation-tools.txt +0 -0
  321. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/release-tools.in +0 -0
  322. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/release-tools.txt +0 -0
  323. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/test-tools.in +0 -0
  324. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/test-tools.txt +0 -0
  325. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/a11y_check.py +0 -0
  326. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/bench_cli.sh +0 -0
  327. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/build_command_reference.py +0 -0
  328. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/build_registries.py +0 -0
  329. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/build_roadmap.py +0 -0
  330. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/check_anchors.py +0 -0
  331. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/check_required_checks.py +0 -0
  332. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/ensure_eval_corpus.sh +0 -0
  333. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/eval_explain.py +0 -0
  334. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/eval_recommend.py +0 -0
  335. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/eval_retrieval.py +0 -0
  336. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/eval_stats_summary.py +0 -0
  337. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/import_budget.py +0 -0
  338. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/lock_toolchain.py +0 -0
  339. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/mutation_gate.py +0 -0
  340. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/perf_gate.py +0 -0
  341. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/post_deploy_smoke.py +0 -0
  342. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/release_preflight.py +0 -0
  343. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/setup.cfg +0 -0
  344. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/sonar-project.properties +0 -0
  345. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/style/README.md +0 -0
  346. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/style/boost.css +0 -0
  347. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/style/boost.js +0 -0
  348. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/style/demo.html +0 -0
  349. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/adapt.feature +0 -0
  350. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/browse.feature +0 -0
  351. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/count.feature +0 -0
  352. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/discover.feature +0 -0
  353. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/doctor.feature +0 -0
  354. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/environment.py +0 -0
  355. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/explain.feature +0 -0
  356. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/index.feature +0 -0
  357. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/install.feature +0 -0
  358. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/list.feature +0 -0
  359. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/mcp.feature +0 -0
  360. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/search.feature +0 -0
  361. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/steps/cli_steps.py +0 -0
  362. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/steps/discovery_steps.py +0 -0
  363. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/steps/mcp_steps.py +0 -0
  364. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/steps/quality_steps.py +0 -0
  365. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/conftest.py +0 -0
  366. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/eval/baseline.json +0 -0
  367. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/eval/explain.jsonl +0 -0
  368. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/eval/golden.jsonl +0 -0
  369. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/eval/recommend.jsonl +0 -0
  370. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/eval/taps.txt +0 -0
  371. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_capabilities_policy.py +0 -0
  372. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_adapt.py +0 -0
  373. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_bmad.py +0 -0
  374. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_discovery.py +0 -0
  375. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_hooks.py +0 -0
  376. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_info.py +0 -0
  377. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_intelligence.py +0 -0
  378. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_quality.py +0 -0
  379. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_taps.py +0 -0
  380. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_team.py +0 -0
  381. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_everyday_loop.py +0 -0
  382. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_integrity_enforce.py +0 -0
  383. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_property_parsers.py +0 -0
  384. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_run.py +0 -0
  385. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_tap_signing.py +0 -0
  386. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_workspace_scope.py +0 -0
  387. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/README.md +0 -0
  388. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/01-typical.md +0 -0
  389. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/02-lossy-version.md +0 -0
  390. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/03-lossy-numbers.md +0 -0
  391. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/04-lists.md +0 -0
  392. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/05-nested.md +0 -0
  393. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/06-empty-block.md +0 -0
  394. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/07-unterminated.md +0 -0
  395. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/08-none.md +0 -0
  396. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/09-unbalanced-quote.md +0 -0
  397. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/10-keywords.md +0 -0
  398. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/11-crlf.md +0 -0
  399. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/12-bom.md +0 -0
  400. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/registry/01-shorthand.txt +0 -0
  401. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/registry/02-https.txt +0 -0
  402. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/registry/03-ssh.txt +0 -0
  403. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/registry/04-traversal.txt +0 -0
  404. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/registry/05-empty.txt +0 -0
  405. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/registry/06-space.txt +0 -0
  406. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/registry/07-slash.txt +0 -0
  407. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/registry/08-bare-host.txt +0 -0
  408. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/fuzz_frontmatter.py +0 -0
  409. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/fuzz_registry.py +0 -0
  410. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/make_fixture.py +0 -0
  411. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/perf/test_benchmarks.py +0 -0
  412. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/smoke.sh +0 -0
  413. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_a11y_check.py +0 -0
  414. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_adapters.py +0 -0
  415. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_adapters_multi.py +0 -0
  416. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_adapters_runner.py +0 -0
  417. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_agents.py +0 -0
  418. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_ai.py +0 -0
  419. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_capabilities.py +0 -0
  420. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_check_anchors.py +0 -0
  421. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_claude_settings.py +0 -0
  422. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_cliparse.py +0 -0
  423. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_command_reference_fresh.py +0 -0
  424. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_config.py +0 -0
  425. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_dense.py +0 -0
  426. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_dense_fallback.py +0 -0
  427. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_docs_pages_linked.py +0 -0
  428. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_docsite_chrome.py +0 -0
  429. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_ed25519.py +0 -0
  430. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_embed.py +0 -0
  431. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_errors_and_cli_table.py +0 -0
  432. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_eval_stats_summary.py +0 -0
  433. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_faithfulness.py +0 -0
  434. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_frontmatter.py +0 -0
  435. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_fuzz_targets.py +0 -0
  436. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_gitleaks_config.py +0 -0
  437. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_gitutil.py +0 -0
  438. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_imperative.py +0 -0
  439. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_import_budget.py +0 -0
  440. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_injectscan.py +0 -0
  441. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_integrity.py +0 -0
  442. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_journal.py +0 -0
  443. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_lockfile.py +0 -0
  444. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_logs.py +0 -0
  445. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_marketing_counts.py +0 -0
  446. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_mcp.py +0 -0
  447. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_mcpdecl.py +0 -0
  448. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_minisign.py +0 -0
  449. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_mutation_hardening.py +0 -0
  450. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_nethttp.py +0 -0
  451. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_output.py +0 -0
  452. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_paths.py +0 -0
  453. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_perf_gate.py +0 -0
  454. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_pkg_confusions.py +0 -0
  455. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_pkg_injection.py +0 -0
  456. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_pkg_secrets.py +0 -0
  457. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_policy.py +0 -0
  458. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_post_deploy_smoke.py +0 -0
  459. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_projectlock.py +0 -0
  460. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_provenance.py +0 -0
  461. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_rag.py +0 -0
  462. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_registries_fresh.py +0 -0
  463. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_release_preflight.py +0 -0
  464. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_required_checks.py +0 -0
  465. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_resolve.py +0 -0
  466. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_roadmap_fresh.py +0 -0
  467. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_rules.py +0 -0
  468. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_scopes.py +0 -0
  469. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_secretscan.py +0 -0
  470. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_serve.py +0 -0
  471. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_spin.py +0 -0
  472. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_stackprobe.py +0 -0
  473. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_staleness.py +0 -0
  474. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_token_parity.py +0 -0
  475. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_toolchain_lock.py +0 -0
  476. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_trustaudit.py +0 -0
  477. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_typosquat.py +0 -0
  478. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_updatediff.py +0 -0
  479. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_util.py +0 -0
  480. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_version.py +0 -0
  481. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_workflows.py +0 -0
  482. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/visual/a11y_check.mjs +0 -0
  483. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/visual/console_check.mjs +0 -0
  484. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/visual/package.json +0 -0
  485. {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/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.230
3
+ Version: 1.0.232
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.230'
22
- __version_tuple__ = version_tuple = (1, 0, 230)
21
+ __version__ = version = '1.0.232'
22
+ __version_tuple__ = version_tuple = (1, 0, 232)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -26,6 +26,7 @@ from ..core import (
26
26
  policy,
27
27
  rag,
28
28
  registry,
29
+ selfupdate,
29
30
  serve,
30
31
  store,
31
32
  util,
@@ -119,10 +120,14 @@ def cmd_clean(argv) -> int:
119
120
  adir = spec["dir"]
120
121
  if not adir.is_dir():
121
122
  continue
123
+ # Same ownership rule as `boost sync`: a broken symlink is only ours to
124
+ # remove if it pointed into the canonical store. A user's own dangling
125
+ # link in ~/.claude/skills is not boost's to clean up.
122
126
  items.extend(
123
127
  (link, "broken symlink", 0)
124
128
  for link in sorted(adir.iterdir())
125
129
  if link.is_symlink() and not link.exists()
130
+ and store.points_into_store(link)
126
131
  )
127
132
 
128
133
  configured = {t.safe_name for t in registry.list_taps()}
@@ -1000,12 +1005,47 @@ def cmd_self_update(argv) -> int:
1000
1005
  p = cliparse.parser(
1001
1006
  prog="boost self-update",
1002
1007
  description="Update boost itself to the latest version")
1003
- p.parse_args(argv)
1008
+ p.add_argument("--dry-run", action="store_true",
1009
+ help="show how boost would update itself, change nothing")
1010
+ args = p.parse_args(argv)
1011
+
1012
+ method = selfupdate.detect()
1013
+ if method != selfupdate.GIT:
1014
+ return _self_update_package(method, dry_run=args.dry_run)
1015
+ return _self_update_git(dry_run=args.dry_run)
1016
+
1017
+
1018
+ def _self_update_package(method: str, dry_run: bool) -> int:
1019
+ """Upgrade a pip / pipx / uv-tool install by driving its own manager."""
1020
+ old = __version__
1021
+ cmd = selfupdate.upgrade_command(method) # errors if the manager is gone
1022
+ if dry_run:
1023
+ out.info("installed with: %s" % method)
1024
+ out.info("would run: %s" % " ".join(cmd))
1025
+ return 0
1026
+ out.info("updating via %s: %s" % (method, " ".join(cmd)))
1027
+ selfupdate.run_upgrade(cmd)
1028
+ # This process imported its version before the upgrade, so ask a fresh one.
1029
+ new = selfupdate.observed_version()
1030
+ journal.log("self-update", new or old, previous=old, method=method)
1031
+ if new and new != old:
1032
+ out.ok("boost v%s → v%s" % (old, new))
1033
+ elif new:
1034
+ out.ok("already up to date (v%s)" % new)
1035
+ else:
1036
+ # The upgrade succeeded but we never saw a version — say exactly that
1037
+ # rather than claim one.
1038
+ out.ok("upgraded via %s; run `boost --version` to confirm" % method)
1039
+ return 0
1040
+
1004
1041
 
1042
+ def _self_update_git(dry_run: bool) -> int:
1043
+ """Fast-forward the source checkout boost is running from."""
1005
1044
  root = paths.repo_root()
1006
- if not gitutil.is_repo(root):
1007
- raise BoostError("boost is not running from a git checkout",
1008
- hint="git clone the boost repo and symlink bin")
1045
+ if dry_run:
1046
+ out.info("installed with: git checkout (%s)" % _tilde(root))
1047
+ out.info("would run: git -C %s pull --ff-only" % root)
1048
+ return 0
1009
1049
  old = __version__
1010
1050
  before = gitutil.head_commit(root)
1011
1051
  gitutil.run(["-C", str(root), "pull", "--ff-only"], timeout=120)
@@ -864,6 +864,14 @@ def _bundle_install(file: Optional[str]) -> int:
864
864
  % (sname, (" in tap %s" % tapq) if tapq else ""))
865
865
  failed += 1
866
866
  continue
867
+ if len({e["tap"] for e in matches}) > 1:
868
+ # A Boostfile is meant to be reproducible, so guessing which tap
869
+ # `skills:brainstorming` meant is the one thing this must not do.
870
+ out.warn("%s is ambiguous — in %s; qualify it as owner/repo:%s"
871
+ % (sname, ", ".join(sorted({e["tap"] for e in matches})),
872
+ sname))
873
+ failed += 1
874
+ continue
867
875
  entry = matches[0]
868
876
  if sver and str(entry.get("version")) != sver:
869
877
  out.warn("%s: Boostfile wants @%s, tap has %s — installing that"
@@ -248,8 +248,15 @@ def find(name: str, tap: Optional[str] = None) -> List[dict]:
248
248
  tap, name = name.rsplit(":", 1)
249
249
  matches = [e for e in all_entries() if e["name"] == name]
250
250
  if tap:
251
- matches = [e for e in matches
252
- if tap in (e["tap"], e["tap"].split("/")[-1])]
251
+ # Same tiering as registry.get: a qualified owner/repo beats a bare
252
+ # repo tail, so `angular/skills:x` never picks up `microsoft/skills:x`.
253
+ # Without this the two resolvers disagreed — `boost untap skills`
254
+ # errored on the ambiguity while `boost bundle apply` with
255
+ # `skills:brainstorming` silently took matches[0] from whichever tap
256
+ # sorted first.
257
+ exact = [e for e in matches if e["tap"] == tap]
258
+ matches = exact or [e for e in matches
259
+ if e["tap"].split("/")[-1] == tap]
253
260
  return matches
254
261
 
255
262
 
@@ -80,12 +80,26 @@ def list_taps() -> List[Tap]:
80
80
  def get(name: str) -> Tap:
81
81
  """Look up a tap by name, safe_name, or bare repo name.
82
82
 
83
+ Tiered so a qualified name always beats a short one: exact ``owner/repo``
84
+ first, then ``safe_name``, then the bare repo tail. Within a tier a name
85
+ that matches more than one tap is an error rather than a guess — with
86
+ ``angular/skills`` and ``microsoft/skills`` both tapped, ``boost untap
87
+ skills`` used to act on whichever came first in config.json, which for a
88
+ destructive command is the wrong answer half the time.
89
+
83
90
  Raises BoostError (with a did-you-mean hint) if none match.
84
91
  """
85
92
  taps = list_taps()
86
- for t in taps:
87
- if name in (t.name, t.safe_name, t.name.split("/")[-1]):
88
- return t
93
+ for key in (lambda t: t.name, lambda t: t.safe_name,
94
+ lambda t: t.name.split("/")[-1]):
95
+ hits = [t for t in taps if key(t) == name]
96
+ if len(hits) == 1:
97
+ return hits[0]
98
+ if len(hits) > 1:
99
+ raise BoostError(
100
+ "%r is ambiguous — it matches %d taps: %s"
101
+ % (name, len(hits), ", ".join(sorted(t.name for t in hits))),
102
+ hint="use the full owner/repo name")
89
103
  close = difflib.get_close_matches(name, [t.name for t in taps], n=1)
90
104
  raise BoostError("no such tap: %s" % name,
91
105
  hint=("did you mean %s?" % close[0]) if close
@@ -0,0 +1,138 @@
1
+ """How this boost was installed, and the command that upgrades it in place.
2
+
3
+ `boost self-update` assumed a git checkout and told everyone else to abandon
4
+ their install method — but the documented way in is `pipx install
5
+ boost-skill-cli` or `pip install boost-skill-cli`, where the package lives in
6
+ site-packages and there is nothing to `git pull`. This resolves the install
7
+ method from evidence on disk and hands the command layer the exact argv that
8
+ upgrades *this* copy.
9
+ """
10
+ from __future__ import annotations
11
+
12
+ import re
13
+ import shutil
14
+ import subprocess
15
+ import sys
16
+ from pathlib import Path
17
+ from typing import List, Optional
18
+
19
+ from ..errors import BoostError
20
+ from . import gitutil, paths
21
+
22
+ DIST = "boost-skill-cli"
23
+
24
+ GIT = "git"
25
+ PIPX = "pipx"
26
+ UV_TOOL = "uv-tool"
27
+ PIP = "pip"
28
+ UNKNOWN = "unknown"
29
+
30
+ # `boost --version` prints "boost <version>"; anything else means we did not
31
+ # actually observe a version and must not report one.
32
+ _VERSION_LINE = re.compile(r"^boost\s+(\S+)$", re.MULTILINE)
33
+
34
+
35
+ def installed_version() -> Optional[str]:
36
+ """Version recorded in installed package metadata, or None.
37
+
38
+ None is the useful answer, not a failure: it means no Python package
39
+ manager has a record of this boost, so none of them can upgrade it.
40
+ """
41
+ try:
42
+ from importlib.metadata import version
43
+ return version(DIST)
44
+ except Exception:
45
+ return None
46
+
47
+
48
+ def detect(root: Optional[Path] = None, prefix: Optional[Path] = None,
49
+ metadata_version=None) -> str:
50
+ """Resolve how this boost was installed.
51
+
52
+ Order matters. A source checkout wins first — that includes `pip install
53
+ -e .`, where the package metadata exists too but `git pull` is what the
54
+ user means. Then the two managers that own a private venv and leave a
55
+ receipt inside it. Then plain pip, but only if pip actually has a record
56
+ of the distribution: telling someone to `pip install --upgrade` a boost
57
+ that pip never installed sends them chasing a package that isn't there.
58
+ """
59
+ root = paths.repo_root() if root is None else Path(root)
60
+ if gitutil.is_repo(root):
61
+ return GIT
62
+ prefix = Path(sys.prefix) if prefix is None else Path(prefix)
63
+ if (prefix / "pipx_metadata.json").is_file():
64
+ return PIPX
65
+ if (prefix / "uv-receipt.toml").is_file():
66
+ return UV_TOOL
67
+ # Resolved here, not as a default argument: a default binds the function
68
+ # object once at import, which silently defeats every attempt to swap it —
69
+ # including a test's, which is how a test of the "nothing installed this"
70
+ # branch ended up running a real `pip install` against PyPI.
71
+ lookup = installed_version if metadata_version is None else metadata_version
72
+ return PIP if lookup() else UNKNOWN
73
+
74
+
75
+ def _require(tool: str) -> str:
76
+ """Absolute path to `tool`, or a BoostError naming what is missing.
77
+
78
+ Falling back to another manager here would upgrade a different copy of
79
+ boost — or none at all — while reporting success.
80
+ """
81
+ found = shutil.which(tool)
82
+ if not found:
83
+ raise BoostError(
84
+ "boost was installed with %s, but %s is not on PATH" % (tool, tool),
85
+ hint="install %s, or upgrade manually with `%s upgrade %s`"
86
+ % (tool, tool, DIST))
87
+ return found
88
+
89
+
90
+ def upgrade_command(method: str) -> List[str]:
91
+ """The argv that upgrades boost for `method`."""
92
+ if method == PIPX:
93
+ return [_require("pipx"), "upgrade", DIST]
94
+ if method == UV_TOOL:
95
+ return [_require("uv"), "tool", "upgrade", DIST]
96
+ if method == PIP:
97
+ # sys.executable, never a bare `pip`: the pip first on PATH can belong
98
+ # to a different interpreter than the one running boost, and upgrading
99
+ # that one leaves this install exactly where it was while printing
100
+ # every sign of success.
101
+ return [sys.executable, "-m", "pip", "install", "--upgrade", DIST]
102
+ raise BoostError(
103
+ "cannot work out how boost was installed, so it cannot update itself",
104
+ hint="upgrade with your package manager, e.g. `pipx upgrade %s`" % DIST)
105
+
106
+
107
+ def run_upgrade(cmd: List[str], timeout: float = 300.0):
108
+ """Run the upgrade, raising BoostError with the manager's own last words."""
109
+ try:
110
+ proc = subprocess.run(cmd, capture_output=True, text=True,
111
+ timeout=timeout)
112
+ except (OSError, subprocess.SubprocessError) as err:
113
+ raise BoostError("could not run %s" % " ".join(cmd),
114
+ hint=str(err)) from err
115
+ if proc.returncode != 0:
116
+ detail = ((proc.stderr or "") + (proc.stdout or "")).strip().splitlines()
117
+ raise BoostError(
118
+ "upgrade failed (%s exited %d)" % (Path(cmd[0]).name, proc.returncode),
119
+ hint=detail[-1] if detail else "re-run the command by hand to see why")
120
+ return proc
121
+
122
+
123
+ def observed_version(timeout: float = 30.0) -> Optional[str]:
124
+ """Ask a freshly-spawned boost what version it is now, or None.
125
+
126
+ This process imported its own version before the upgrade ran, so it cannot
127
+ answer the question. None means "we did not see one" — better to say
128
+ nothing than to report a version we never observed.
129
+ """
130
+ try:
131
+ proc = subprocess.run([str(paths.launcher()), "--version"],
132
+ capture_output=True, text=True, timeout=timeout)
133
+ except (OSError, subprocess.SubprocessError):
134
+ return None
135
+ if proc.returncode != 0:
136
+ return None
137
+ match = _VERSION_LINE.search(proc.stdout or "")
138
+ return match.group(1) if match else None
@@ -810,6 +810,65 @@ def uninstall(name: str) -> dict:
810
810
  return {"name": name, "unlinked": removed_links, "entry": entry}
811
811
 
812
812
 
813
+ def strip_extended_prefix(text: str) -> str:
814
+ """Drop Windows' ``\\\\?\\`` extended-length prefix from a raw path string.
815
+
816
+ Since 3.8, `os.readlink()` on Windows returns the reparse point's
817
+ substitution path, which typically carries that prefix — so boost's own
818
+ link into the store reads back as
819
+ ``\\\\?\\C:\\Users\\...\\.agents\\skills\\x``. Compared by path components
820
+ that is a *different drive* from ``C:\\Users\\...``, and every Windows leg
821
+ of the matrix went red on exactly this. The check it replaced was a
822
+ substring test, which the prefix sailed straight through; comparing
823
+ properly is what exposed it.
824
+ """
825
+ if text.startswith("\\\\?\\UNC\\"):
826
+ return "\\\\" + text[len("\\\\?\\UNC\\"):]
827
+ if text.startswith("\\\\?\\"):
828
+ return text[len("\\\\?\\"):]
829
+ return text
830
+
831
+
832
+ def normalize_link_target(path: Path) -> str:
833
+ """A comparable string form of a `readlink()` result.
834
+
835
+ Normalizes separators and case as well as the prefix: Windows paths
836
+ compare case-insensitively, and POSIX `normcase` is a no-op.
837
+ """
838
+ return os.path.normcase(os.path.normpath(strip_extended_prefix(str(path))))
839
+
840
+
841
+ def points_into_store(link: Path) -> bool:
842
+ """True if `link`'s target lands inside boost's canonical store.
843
+
844
+ Reads the raw `readlink()` target rather than `resolve()`, because the
845
+ links this has to judge are usually broken — `resolve()` cannot tell us
846
+ where a dangling link was aiming. A relative target is resolved against
847
+ the link's own directory, and containment is decided by `commonpath`
848
+ (the same guard `scopes.contains` uses): a substring test on the store
849
+ path also matches siblings like `~/.agents/skills-backup`, which boost
850
+ does not own either.
851
+
852
+ Everything boost deletes under an agent's skills dir is gated on this.
853
+ A user's own broken symlink sitting in `~/.claude/skills` is not ours.
854
+ Fails closed — an unreadable link is not boost's to delete.
855
+ """
856
+ try:
857
+ target = link.readlink()
858
+ except OSError:
859
+ return False
860
+ if not target.is_absolute():
861
+ target = link.parent / target
862
+ target_s = normalize_link_target(target)
863
+ root_s = normalize_link_target(paths.store_dir())
864
+ try:
865
+ # ValueError for paths with no common root — on Windows, two different
866
+ # drives — which means "outside", not "crash out of the delete guard".
867
+ return os.path.commonpath([target_s, root_s]) == root_s
868
+ except ValueError:
869
+ return False
870
+
871
+
813
872
  def sync_plan() -> Dict[str, list]:
814
873
  """Compare lock file <-> store <-> agent symlinks.
815
874
 
@@ -843,11 +902,12 @@ def sync_plan() -> Dict[str, list]:
843
902
  if not adir.is_dir():
844
903
  continue
845
904
  for link in adir.iterdir():
846
- if link.is_symlink():
847
- points_into_store = str(paths.store_dir()) in str(
848
- link.resolve() if link.exists() else link.readlink())
849
- if not link.exists() or (points_into_store and link.name not in lock):
850
- plan["stale_links"].append(str(link))
905
+ # Ownership first, for broken links too: the old test short-circuited
906
+ # on `not link.exists()`, so any dangling symlink a user happened to
907
+ # keep in ~/.claude/skills was swept up by `boost sync`.
908
+ if (link.is_symlink() and points_into_store(link)
909
+ and (not link.exists() or link.name not in lock)):
910
+ plan["stale_links"].append(str(link))
851
911
  # Rules/workflows don't live in the store — they materialize into agent dirs.
852
912
  # A materialization whose file (or CLAUDE.md block) is gone can be repaired
853
913
  # by re-materializing from the tap, same as a missing skill store dir.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.230
3
+ Version: 1.0.232
4
4
  Summary: boost — Homebrew for AI coding skills
5
5
  Author: Jonathan Reyes
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -81,6 +81,7 @@ boost_cli/core/resolve.py
81
81
  boost_cli/core/rules.py
82
82
  boost_cli/core/scopes.py
83
83
  boost_cli/core/secretscan.py
84
+ boost_cli/core/selfupdate.py
84
85
  boost_cli/core/serve.py
85
86
  boost_cli/core/stackprobe.py
86
87
  boost_cli/core/staleness.py
@@ -460,6 +461,7 @@ tests/unit/test_roadmap_fresh.py
460
461
  tests/unit/test_rules.py
461
462
  tests/unit/test_scopes.py
462
463
  tests/unit/test_secretscan.py
464
+ tests/unit/test_selfupdate.py
463
465
  tests/unit/test_serve.py
464
466
  tests/unit/test_spin.py
465
467
  tests/unit/test_stackprobe.py
@@ -188,7 +188,7 @@
188
188
  <a class="cmd-link" href="#cmd-mcp" data-search="mcp register boost as an mcp server for claude code --stdio {register,unregister}">mcp</a>
189
189
  <a class="cmd-link" href="#cmd-hooks" data-search="hooks manage claude code hooks (scope-aware) in settings.json -c, --command command -n, --name name -s, --scope {global,project} -m, --matcher matcher --timeout timeout {add,remove,list} event">hooks</a>
190
190
  <a class="cmd-link" href="#cmd-bmad" data-search="bmad install &amp; manage the bmad method (scope-aware, toggleable) -s, --scope {project,global} --modules modules -y, --yes --startup {install,init,startup,orient,uninstall,disable,enable,doctor,status} value">bmad</a>
191
- <a class="cmd-link" href="#cmd-self-update" data-search="self-update update boost itself to the latest version ">self-update</a>
191
+ <a class="cmd-link" href="#cmd-self-update" data-search="self-update update boost itself to the latest version --dry-run">self-update</a>
192
192
  </div>
193
193
  <div class="group" data-group="team">
194
194
  <div class="group-h">Team &amp; sharing</div>
@@ -1083,10 +1083,14 @@
1083
1083
  <div class="arg"><code>--startup</code><span>enable the startup toggle right after install</span></div>
1084
1084
  </div>
1085
1085
  </section>
1086
- <section class="cmd" id="cmd-self-update" data-search="self-update update boost itself to the latest version ">
1086
+ <section class="cmd" id="cmd-self-update" data-search="self-update update boost itself to the latest version --dry-run">
1087
1087
  <h3><span class="cname">self-update</span><span class="gtag">cfg</span></h3>
1088
1088
  <p class="summary">Update boost itself to the latest version</p>
1089
- <pre class="syn">boost self-update</pre>
1089
+ <pre class="syn">boost self-update [--dry-run]</pre>
1090
+ <div class="args-h">Options</div>
1091
+ <div class="args">
1092
+ <div class="arg"><code>--dry-run</code><span>show how boost would update itself, change nothing</span></div>
1093
+ </div>
1090
1094
  </section>
1091
1095
  <h2 class="group-h" id="grp-team">Team &amp; sharing</h2>
1092
1096
  <section class="cmd" id="cmd-cohort" data-search="cohort controlled skill rollouts &amp; team a/b testing --skills skills --percent percent --json {list,create,delete,status,apply} name">
@@ -0,0 +1,23 @@
1
+ ---
2
+ id: ambiguous-tap-short-name-resolution
3
+ board: code
4
+ section: internals
5
+ status: shipped
6
+ category: Bug
7
+ complexity: S
8
+ impact: High
9
+ wow: 3
10
+ note:
11
+ order: 28
12
+ owner: loop/tap-name-ambiguity
13
+ pr:
14
+ title: Ambiguous tap short-name resolution silently picks the wrong tap
15
+ ---
16
+ <code>registry.get(name)</code> matches on full name, safe-name, or trailing path segment and returns
17
+ the <em>first</em> hit with no ambiguity check — unlike <code>catalog.resolve_one</code>, which
18
+ explicitly errors on a multi-tap ambiguous match. Three of the five default taps end in
19
+ <code>/skills</code>, so after <code>boost tap --defaults</code>, <code>boost untap skills</code> or
20
+ <code>boost update skills</code> silently resolves to whichever tap sorts first and the others
21
+ become unreachable by short name. Raise on an ambiguous short-name match, mirroring
22
+ <code>resolve_one</code>.
23
+ <b>Shipped.</b> <code>registry.get()</code> is now tiered — exact <code>owner/repo</code>, then <code>safe_name</code>, then the bare repo tail — and refuses a short name that matches more than one tap instead of taking the first. Two corrections while fixing it: there is no <i>sort</i>, the winner was whichever came first in <code>config.json</code>; and the fix was <b>half a fix</b> as originally scoped. <code>catalog.find()</code> carried an independent, untiered <code>tap in (e["tap"], tail)</code> membership test, so with both taps configured <code>angular/skills:brainstorming</code> also matched <code>microsoft/skills</code>, and <code>boost bundle apply</code> took <code>matches[0]</code> — silently installing from the wrong tap, verbatim the defect this item exists to fix. Fixing only <code>registry.get</code> would have left the CLI self-contradictory: <code>boost untap skills</code> erroring while a Boostfile silently guessed. Both resolvers are tiered now and <code>bundle apply</code> refuses an ambiguous entry rather than picking one.
@@ -0,0 +1,31 @@
1
+ ---
2
+ id: self-update-broken-for-pip-pipx-installs
3
+ board: code
4
+ section: compat
5
+ status: shipped
6
+ category: Bug
7
+ complexity: M
8
+ impact: High
9
+ wow: 3
10
+ note:
11
+ order: 10
12
+ owner: loop/self-update
13
+ pr: 272
14
+ title: <code>self-update</code> is non-functional for pip/pipx installs
15
+ ---
16
+ <code>boost self-update</code> only works when boost runs from a git checkout: <code>paths.repo_root()</code>
17
+ resolves inside <code>site-packages</code> for a pip/pipx install, <code>gitutil.is_repo()</code> is
18
+ False, and <code>cmd_self_update</code> raises "boost is not running from a git checkout" with a hint
19
+ to clone the repo — telling a normal PyPI user to abandon their install method. Detect the install
20
+ method and shell out to <code>pip install --upgrade boost-skill-cli</code> /
21
+ <code>pipx upgrade boost-skill-cli</code>, falling back to the git-pull path only for source
22
+ checkouts. Shipped as <code>core/selfupdate.py</code>: detection reads evidence on disk —
23
+ <code>.git</code>, then <code>pipx_metadata.json</code> or <code>uv-receipt.toml</code> in
24
+ <code>sys.prefix</code>, then installed package metadata — and a <code>--dry-run</code> flag
25
+ prints the exact command without running it. Two details carry the weight: the pip branch
26
+ invokes <code>sys.executable -m pip</code>, never a bare <code>pip</code>, because the pip
27
+ first on PATH can belong to another interpreter and would upgrade a different copy while
28
+ reporting success; and an install nothing has a record of reports that plainly instead of
29
+ guessing pip. The new version is read from a freshly spawned <code>boost --version</code>,
30
+ since the running process imported its own version before the upgrade — if that probe says
31
+ nothing, neither does boost.
@@ -0,0 +1,35 @@
1
+ ---
2
+ id: sync-deletes-unowned-broken-symlinks
3
+ board: code
4
+ section: internals
5
+ status: shipped
6
+ category: Bug
7
+ complexity: S
8
+ impact: Med
9
+ wow: 2
10
+ note:
11
+ order: 29
12
+ owner: loop/sync-symlink-ownership
13
+ pr: 273
14
+ title: <code>sync --apply</code> deletes any broken symlink, not just boost's own
15
+ ---
16
+ <code>sync_plan</code> flags every broken symlink under an enabled agent dir as stale regardless of
17
+ whether it points into boost's store — the <code>points_into_store</code> check only runs on the
18
+ live-link branch — and <code>sync_apply</code> unconditionally unlinks everything in
19
+ <code>stale_links</code>. A user's own unrelated broken symlink sitting in
20
+ <code>~/.claude/skills</code> gets deleted by <code>boost sync --apply</code> with no ownership
21
+ check. Only treat a broken symlink as boost-managed if its raw <code>readlink()</code> target
22
+ resolves under the store dir. Shipped as <code>store.points_into_store()</code>, applied to
23
+ broken and live links alike. Two things turned up while fixing it. <code>boost clean</code>
24
+ carried the identical overreach — it unlinked every broken symlink under an agent dir with no
25
+ ownership test at all — so it now shares the same helper; fixing only <code>sync</code> would
26
+ have left boost contradicting itself. And the original check was a substring test
27
+ (<code>str(store_dir) in str(target)</code>), which also matches siblings like
28
+ <code>~/.agents/skills-backup</code>; the comparison is component-wise now, and a relative
29
+ <code>readlink()</code> target is resolved against the link's own directory before it is judged.
30
+ Comparing properly is what exposed a Windows bug the sloppy check had been hiding: since 3.8
31
+ <code>os.readlink()</code> there returns the reparse point's substitution path, which carries the
32
+ <code>\\?\</code> extended-length prefix, so boost's own link reads back as a
33
+ <em>different drive</em> and stopped matching the store at all. Every Windows leg of the matrix
34
+ went red on it. The prefix is stripped before comparison, and the behaviour is pinned on every
35
+ platform via <code>ntpath</code>, which imports fine on POSIX.
@@ -948,7 +948,7 @@ chunks instead cost ~70%.</p>
948
948
  </article>
949
949
 
950
950
  <article class="cap rcard" id="ambiguous-tap-short-name-resolution">
951
- <div class="head"><span class="pill planned">Planned</span><span class="cat">Bug</span></div>
951
+ <div class="head"><span class="pill shipped">Shipped</span><span class="cat">Bug</span></div>
952
952
  <h3>Ambiguous tap short-name resolution silently picks the wrong tap</h3>
953
953
  <p><code>registry.get(name)</code> matches on full name, safe-name, or trailing path segment and returns
954
954
  the <em>first</em> hit with no ambiguity check — unlike <code>catalog.resolve_one</code>, which
@@ -956,7 +956,8 @@ explicitly errors on a multi-tap ambiguous match. Three of the five default taps
956
956
  <code>/skills</code>, so after <code>boost tap --defaults</code>, <code>boost untap skills</code> or
957
957
  <code>boost update skills</code> silently resolves to whichever tap sorts first and the others
958
958
  become unreachable by short name. Raise on an ambiguous short-name match, mirroring
959
- <code>resolve_one</code>.</p>
959
+ <code>resolve_one</code>.
960
+ <b>Shipped.</b> <code>registry.get()</code> is now tiered — exact <code>owner/repo</code>, then <code>safe_name</code>, then the bare repo tail — and refuses a short name that matches more than one tap instead of taking the first. Two corrections while fixing it: there is no <i>sort</i>, the winner was whichever came first in <code>config.json</code>; and the fix was <b>half a fix</b> as originally scoped. <code>catalog.find()</code> carried an independent, untiered <code>tap in (e["tap"], tail)</code> membership test, so with both taps configured <code>angular/skills:brainstorming</code> also matched <code>microsoft/skills</code>, and <code>boost bundle apply</code> took <code>matches[0]</code> — silently installing from the wrong tap, verbatim the defect this item exists to fix. Fixing only <code>registry.get</code> would have left the CLI self-contradictory: <code>boost untap skills</code> erroring while a Boostfile silently guessed. Both resolvers are tiered now and <code>bundle apply</code> refuses an ambiguous entry rather than picking one.</p>
960
961
  <div class="meta">
961
962
  <span class="m">Complexity <b>S</b></span>
962
963
  <span class="m hi">Impact <b>High</b></span>
@@ -965,7 +966,7 @@ become unreachable by short name. Raise on an ambiguous short-name match, mirror
965
966
  </article>
966
967
 
967
968
  <article class="cap rcard" id="sync-deletes-unowned-broken-symlinks">
968
- <div class="head"><span class="pill planned">Planned</span><span class="cat">Bug</span></div>
969
+ <div class="head"><span class="pill shipped">Shipped</span><span class="cat">Bug</span></div>
969
970
  <h3><code>sync --apply</code> deletes any broken symlink, not just boost's own</h3>
970
971
  <p><code>sync_plan</code> flags every broken symlink under an enabled agent dir as stale regardless of
971
972
  whether it points into boost's store — the <code>points_into_store</code> check only runs on the
@@ -973,7 +974,20 @@ live-link branch — and <code>sync_apply</code> unconditionally unlinks everyth
973
974
  <code>stale_links</code>. A user's own unrelated broken symlink sitting in
974
975
  <code>~/.claude/skills</code> gets deleted by <code>boost sync --apply</code> with no ownership
975
976
  check. Only treat a broken symlink as boost-managed if its raw <code>readlink()</code> target
976
- resolves under the store dir.</p>
977
+ resolves under the store dir. Shipped as <code>store.points_into_store()</code>, applied to
978
+ broken and live links alike. Two things turned up while fixing it. <code>boost clean</code>
979
+ carried the identical overreach — it unlinked every broken symlink under an agent dir with no
980
+ ownership test at all — so it now shares the same helper; fixing only <code>sync</code> would
981
+ have left boost contradicting itself. And the original check was a substring test
982
+ (<code>str(store_dir) in str(target)</code>), which also matches siblings like
983
+ <code>~/.agents/skills-backup</code>; the comparison is component-wise now, and a relative
984
+ <code>readlink()</code> target is resolved against the link's own directory before it is judged.
985
+ Comparing properly is what exposed a Windows bug the sloppy check had been hiding: since 3.8
986
+ <code>os.readlink()</code> there returns the reparse point's substitution path, which carries the
987
+ <code>\\?\</code> extended-length prefix, so boost's own link reads back as a
988
+ <em>different drive</em> and stopped matching the store at all. Every Windows leg of the matrix
989
+ went red on it. The prefix is stripped before comparison, and the behaviour is pinned on every
990
+ platform via <code>ntpath</code>, which imports fine on POSIX.</p>
977
991
  <div class="meta">
978
992
  <span class="m">Complexity <b>S</b></span>
979
993
  <span class="m">Impact <b>Med</b></span>
@@ -2814,7 +2828,7 @@ same nav and footer as every other page.</p>
2814
2828
  </article>
2815
2829
 
2816
2830
  <article class="cap rcard" id="self-update-broken-for-pip-pipx-installs">
2817
- <div class="head"><span class="pill planned">Planned</span><span class="cat">Bug</span></div>
2831
+ <div class="head"><span class="pill shipped">Shipped</span><span class="cat">Bug</span></div>
2818
2832
  <h3><code>self-update</code> is non-functional for pip/pipx installs</h3>
2819
2833
  <p><code>boost self-update</code> only works when boost runs from a git checkout: <code>paths.repo_root()</code>
2820
2834
  resolves inside <code>site-packages</code> for a pip/pipx install, <code>gitutil.is_repo()</code> is
@@ -2822,7 +2836,16 @@ False, and <code>cmd_self_update</code> raises "boost is not running from a git
2822
2836
  to clone the repo — telling a normal PyPI user to abandon their install method. Detect the install
2823
2837
  method and shell out to <code>pip install --upgrade boost-skill-cli</code> /
2824
2838
  <code>pipx upgrade boost-skill-cli</code>, falling back to the git-pull path only for source
2825
- checkouts.</p>
2839
+ checkouts. Shipped as <code>core/selfupdate.py</code>: detection reads evidence on disk —
2840
+ <code>.git</code>, then <code>pipx_metadata.json</code> or <code>uv-receipt.toml</code> in
2841
+ <code>sys.prefix</code>, then installed package metadata — and a <code>--dry-run</code> flag
2842
+ prints the exact command without running it. Two details carry the weight: the pip branch
2843
+ invokes <code>sys.executable -m pip</code>, never a bare <code>pip</code>, because the pip
2844
+ first on PATH can belong to another interpreter and would upgrade a different copy while
2845
+ reporting success; and an install nothing has a record of reports that plainly instead of
2846
+ guessing pip. The new version is read from a freshly spawned <code>boost --version</code>,
2847
+ since the running process imported its own version before the upgrade — if that probe says
2848
+ nothing, neither does boost.</p>
2826
2849
  <div class="meta">
2827
2850
  <span class="m">Complexity <b>M</b></span>
2828
2851
  <span class="m hi">Impact <b>High</b></span>