boost-skill-cli 1.0.402__tar.gz → 1.0.404__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 (630) hide show
  1. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/PKG-INFO +1 -1
  2. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/_version.py +2 -2
  3. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/pkg.py +19 -1
  4. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/quality.py +131 -13
  5. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_skill_cli.egg-info/PKG-INFO +1 -1
  6. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_skill_cli.egg-info/SOURCES.txt +3 -0
  7. boost_skill_cli-1.0.404/docs/roadmap/items/dry-run-promised-a-link-nobody-makes.md +43 -0
  8. boost_skill_cli-1.0.404/docs/roadmap/items/heal-deleted-links-it-never-made.md +54 -0
  9. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap.html +92 -1
  10. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_pkg.py +37 -4
  11. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_quality.py +39 -0
  12. boost_skill_cli-1.0.404/tests/unit/test_link_ownership.py +108 -0
  13. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.gitattributes +0 -0
  14. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.gitignore +0 -0
  15. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.gitleaks.toml +0 -0
  16. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.htmlvalidate.json +0 -0
  17. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.lighthouserc.json +0 -0
  18. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.lycheeignore +0 -0
  19. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.markdownlint-cli2.jsonc +0 -0
  20. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.pre-commit-config.yaml +0 -0
  21. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.stylelintrc.json +0 -0
  22. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.vale/styles/boost/Terminology.yml +0 -0
  23. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.vale/styles/config/vocabularies/boost/accept.txt +0 -0
  24. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.vale.ini +0 -0
  25. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/CLAUDE.md +0 -0
  26. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/CODE_OF_CONDUCT.md +0 -0
  27. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/CONTRIBUTING.md +0 -0
  28. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/LICENSE +0 -0
  29. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/MANIFEST.in +0 -0
  30. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/Makefile +0 -0
  31. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/README.md +0 -0
  32. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/SECURITY.md +0 -0
  33. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost +0 -0
  34. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/__init__.py +0 -0
  35. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/__main__.py +0 -0
  36. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/cli.py +0 -0
  37. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/cliparse.py +0 -0
  38. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/__init__.py +0 -0
  39. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/_common.py +0 -0
  40. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/bmad.py +0 -0
  41. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/configuration.py +0 -0
  42. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/discovery.py +0 -0
  43. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/hooks.py +0 -0
  44. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/info.py +0 -0
  45. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/intelligence.py +0 -0
  46. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/run.py +0 -0
  47. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/safety.py +0 -0
  48. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/taps.py +0 -0
  49. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/team.py +0 -0
  50. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/__init__.py +0 -0
  51. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/adapters.py +0 -0
  52. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/agents.py +0 -0
  53. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/ai.py +0 -0
  54. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/capabilities.py +0 -0
  55. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/catalog.py +0 -0
  56. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/chat.py +0 -0
  57. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/claude_settings.py +0 -0
  58. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/complete.py +0 -0
  59. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/config.py +0 -0
  60. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/dense.py +0 -0
  61. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/ed25519.py +0 -0
  62. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/embed.py +0 -0
  63. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/faithfulness.py +0 -0
  64. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/frontmatter.py +0 -0
  65. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/gitutil.py +0 -0
  66. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/imperative.py +0 -0
  67. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/injectscan.py +0 -0
  68. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/installscan.py +0 -0
  69. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/integrity.py +0 -0
  70. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/journal.py +0 -0
  71. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/localembed.py +0 -0
  72. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/lockfile.py +0 -0
  73. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/logs.py +0 -0
  74. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/mcp.py +0 -0
  75. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/mcpdecl.py +0 -0
  76. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/mcphost.py +0 -0
  77. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/minisign.py +0 -0
  78. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/nethttp.py +0 -0
  79. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/output.py +0 -0
  80. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/paths.py +0 -0
  81. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/policy.py +0 -0
  82. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/projectlock.py +0 -0
  83. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/provenance.py +0 -0
  84. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/rag.py +0 -0
  85. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/registry.py +0 -0
  86. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/resolve.py +0 -0
  87. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/rules.py +0 -0
  88. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/scopes.py +0 -0
  89. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/secretscan.py +0 -0
  90. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/selfupdate.py +0 -0
  91. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/serve.py +0 -0
  92. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/stackprobe.py +0 -0
  93. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/staleness.py +0 -0
  94. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/store.py +0 -0
  95. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/trustaudit.py +0 -0
  96. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/typosquat.py +0 -0
  97. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/updatediff.py +0 -0
  98. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/util.py +0 -0
  99. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/workflows.py +0 -0
  100. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/data/registries.json +0 -0
  101. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/errors.py +0 -0
  102. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/spin.py +0 -0
  103. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
  104. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_skill_cli.egg-info/entry_points.txt +0 -0
  105. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_skill_cli.egg-info/requires.txt +0 -0
  106. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_skill_cli.egg-info/top_level.txt +0 -0
  107. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/codecov.yml +0 -0
  108. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/.claude/settings.local.json +0 -0
  109. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/DEBUGGING.md +0 -0
  110. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/adapters.html +0 -0
  111. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/architecture/README.md +0 -0
  112. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/architecture/c4-components-core.md +0 -0
  113. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/architecture/c4-containers.md +0 -0
  114. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/architecture/c4-context.md +0 -0
  115. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/architecture/c4-dynamic-install.md +0 -0
  116. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/gifs/distill.gif +0 -0
  117. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/gifs/doctor.gif +0 -0
  118. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/gifs/explain.gif +0 -0
  119. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/gifs/hooks.gif +0 -0
  120. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/gifs/install.gif +0 -0
  121. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/gifs/pulse.gif +0 -0
  122. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/gifs/search.gif +0 -0
  123. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/gifs/tap.gif +0 -0
  124. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/tapes/distill.tape +0 -0
  125. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/tapes/doctor.tape +0 -0
  126. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/tapes/explain.tape +0 -0
  127. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/tapes/hooks.tape +0 -0
  128. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/tapes/install.tape +0 -0
  129. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/tapes/pulse.tape +0 -0
  130. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/tapes/search.tape +0 -0
  131. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/tapes/tap.tape +0 -0
  132. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel.html +0 -0
  133. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/chat.html +0 -0
  134. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/commands.html +0 -0
  135. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/demo-index.json +0 -0
  136. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/demo.gif +0 -0
  137. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/demo.html +0 -0
  138. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/demo.tape +0 -0
  139. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/design-roadmap.html +0 -0
  140. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/eval-latest.json +0 -0
  141. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/eval.html +0 -0
  142. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/index.html +0 -0
  143. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/mcp-hub.html +0 -0
  144. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/rag-architecture.md +0 -0
  145. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D01.md +0 -0
  146. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D02.md +0 -0
  147. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D03.md +0 -0
  148. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D04.md +0 -0
  149. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D05.md +0 -0
  150. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D06.md +0 -0
  151. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D07.md +0 -0
  152. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D08.md +0 -0
  153. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D09.md +0 -0
  154. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D10.md +0 -0
  155. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D11.md +0 -0
  156. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D12.md +0 -0
  157. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D13.md +0 -0
  158. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D14.md +0 -0
  159. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D15.md +0 -0
  160. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D16.md +0 -0
  161. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D17.md +0 -0
  162. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D18.md +0 -0
  163. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D19.md +0 -0
  164. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D20.md +0 -0
  165. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D21.md +0 -0
  166. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D22.md +0 -0
  167. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D23.md +0 -0
  168. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D24.md +0 -0
  169. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D25.md +0 -0
  170. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D26.md +0 -0
  171. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/a11y-sweep-flakes-on-color-contrast.md +0 -0
  172. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
  173. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/actionlint-skips-shellcheck-silently.md +0 -0
  174. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/adapter-conformance-langgraph-leg-never-ran.md +0 -0
  175. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/agents-field-records-the-request-not-the-links.md +0 -0
  176. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/ai-bridge-silent-failure-logging.md +0 -0
  177. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/ambiguous-tap-short-name-resolution.md +0 -0
  178. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
  179. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
  180. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
  181. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/bm25-index-is-one-json-blob.md +0 -0
  182. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/boost-run-live-agents.md +0 -0
  183. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
  184. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
  185. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
  186. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
  187. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
  188. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
  189. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/chat-cites-sources-by-a-number-it-never-prints.md +0 -0
  190. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/chat-command-grounded-conversational-search.md +0 -0
  191. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/ci-job-timeout-minutes.md +0 -0
  192. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/ci-summary-step-fails-itself.md +0 -0
  193. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/ci-time-is-now-runner-queueing.md +0 -0
  194. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
  195. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/code-scanning-rule-can-be-restored.md +0 -0
  196. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/codeql-job-rename-stranded-merge-protection.md +0 -0
  197. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/command-carousel-page.md +0 -0
  198. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/command-reference-docs-site.md +0 -0
  199. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/completions-complete-only-command-names.md +0 -0
  200. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
  201. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
  202. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
  203. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
  204. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/crash-listing-branch-untested.md +0 -0
  205. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
  206. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/demo-cannot-open-its-own-pr.md +0 -0
  207. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/demo-gif-workflow-has-never-succeeded.md +0 -0
  208. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/dense-search-fallback-and-stale-tap-pruning.md +0 -0
  209. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/dependabot-missing-pip-ecosystem.md +0 -0
  210. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/dependabot-regeneration-drops-platform-pins.md +0 -0
  211. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/dependabot-root-pip-entry-duplicates-requirements.md +0 -0
  212. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
  213. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/docsite-chrome-and-content-audit.md +0 -0
  214. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
  215. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
  216. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
  217. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/eval-corpus-cannot-see-real-retrieval.md +0 -0
  218. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/eval-corpus-is-96x-smaller-than-a-real-install.md +0 -0
  219. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/eval-corpus-is-one-strangers-repo.md +0 -0
  220. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/eval-corpus-pins-have-no-refresh-path.md +0 -0
  221. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/eval-corpus-was-not-actually-pinned.md +0 -0
  222. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/eval-deduped-ranked-lists-by-name.md +0 -0
  223. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
  224. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
  225. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
  226. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
  227. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
  228. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
  229. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/framework-adapter-multi-agent.md +0 -0
  230. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
  231. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
  232. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/gemini-cli-agent-target.md +0 -0
  233. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/github-community-health-files.md +0 -0
  234. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
  235. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/golden-set-grades-by-name-not-by-skill.md +0 -0
  236. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
  237. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
  238. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/html-validation-html-validate.md +0 -0
  239. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/info-rejects-the-qualified-name-it-recommends.md +0 -0
  240. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/install-docs-never-mentioned-upgrading.md +0 -0
  241. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/install-from-path-bypasses-policy-and-pin-checks.md +0 -0
  242. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/install-resolves-skill-dependencies.md +0 -0
  243. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/install-scope-user-or-project.md +0 -0
  244. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/installed-skill-trust-audit.md +0 -0
  245. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
  246. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/internal-architecture-diagrams.md +0 -0
  247. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
  248. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/journal-rotation-race-and-handle-leak.md +0 -0
  249. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/keyless-dense-tier-local-static-embeddings.md +0 -0
  250. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/keyless-semantic-search-for-everyone.md +0 -0
  251. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/langchain-integration-explainer-page.md +0 -0
  252. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/langchain-langgraph-langsmith-integration.md +0 -0
  253. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
  254. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/license-compliance-scanning.md +0 -0
  255. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
  256. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/lighthouse-scored-a-page-nobody-is-served.md +0 -0
  257. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/lint-tap-misscopes-rule-workflow-entries.md +0 -0
  258. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
  259. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
  260. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/lock-invariant-cannot-parse-extras-pins.md +0 -0
  261. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
  262. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
  263. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
  264. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/main-has-no-branch-protection.md +0 -0
  265. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/main-ruleset-ref-pattern-has-literal-quotes.md +0 -0
  266. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/make-lint-masks-actionlint-failures.md +0 -0
  267. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
  268. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
  269. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/markdownlint-lints-the-fuzz-corpus.md +0 -0
  270. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-aware-skills.md +0 -0
  271. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-check-skills-before-starting-a-task.md +0 -0
  272. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
  273. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-install-skips-the-injection-scan.md +0 -0
  274. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
  275. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-one-benefit-nameable-task.md +0 -0
  276. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
  277. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-search-before-reinventing.md +0 -0
  278. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-search-cost-was-understated.md +0 -0
  279. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-servers-ignore-install-scope.md +0 -0
  280. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
  281. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
  282. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/merge-queue-would-deadlock-most-required-checks.md +0 -0
  283. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/merged-loop-branches-are-never-pruned.md +0 -0
  284. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
  285. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mutation-gate-was-the-whole-critical-path.md +0 -0
  286. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
  287. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
  288. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
  289. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mutation-shard-floor-is-one-file.md +0 -0
  290. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mypy-strict-mode-for-commands.md +0 -0
  291. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/near-duplicate-items-eat-the-result-slots.md +0 -0
  292. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/negative-limit-inverts-log-pulse-output.md +0 -0
  293. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/onboard-overwrites-generated-files-without-confirm.md +0 -0
  294. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
  295. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/one-commit-can-cut-two-releases.md +0 -0
  296. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/one-dead-tap-broke-every-update.md +0 -0
  297. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
  298. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
  299. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
  300. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/path-traversal-unsanitized-rule-workflow-name.md +0 -0
  301. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/pep585-604-modernization-sweep.md +0 -0
  302. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
  303. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/pin-the-lint-toolchain.md +0 -0
  304. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/post-deploy-always-defeated-by-skipped-setup.md +0 -0
  305. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
  306. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
  307. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/prerequisites-and-semantic-search-setup.md +0 -0
  308. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/project-scope-across-every-command.md +0 -0
  309. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/project-scope-symlink-escape-on-write.md +0 -0
  310. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
  311. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
  312. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
  313. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
  314. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
  315. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/publish-gate-ignores-pip-audit-and-metadata.md +0 -0
  316. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/publish-trigger-was-reachable-from-a-fork.md +0 -0
  317. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/pytest-tmpdir-cve-blocked-by-py39-floor.md +0 -0
  318. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/python-floor-moves-to-312.md +0 -0
  319. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
  320. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
  321. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
  322. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
  323. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/rel-time-tests-race-the-wall-clock.md +0 -0
  324. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/release-verifies-the-wrong-commit.md +0 -0
  325. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/required-checks-can-declare-a-check-that-deadlocks-prs.md +0 -0
  326. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/required-checks-config-drift.md +0 -0
  327. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/resolve-vendored-duplicate-copies.md +0 -0
  328. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
  329. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
  330. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/roadmap-html-goes-stale-on-every-rebase.md +0 -0
  331. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/roadmap-page-weight-grows-without-bound.md +0 -0
  332. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/roadmap-perf-budget-has-no-local-guard.md +0 -0
  333. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
  334. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/ruff-016-widens-the-default-rule-set.md +0 -0
  335. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
  336. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/rules-install-but-cannot-be-governed.md +0 -0
  337. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
  338. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
  339. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
  340. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/sbom-declares-the-wrong-version.md +0 -0
  341. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
  342. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/sbom-release-event-never-fires.md +0 -0
  343. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
  344. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/scheduled-toolchain-lock-regeneration.md +0 -0
  345. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/scorecard-findings-triage.md +0 -0
  346. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/search-never-notices-a-new-tap.md +0 -0
  347. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
  348. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
  349. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
  350. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
  351. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/self-update-broken-for-pip-pipx-installs.md +0 -0
  352. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/serve-py-traversal-guards-untested.md +0 -0
  353. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
  354. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
  355. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
  356. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
  357. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
  358. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
  359. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/structured-json-log-output-mode.md +0 -0
  360. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
  361. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
  362. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/sync-deletes-unowned-broken-symlinks.md +0 -0
  363. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/sync-relinks-into-every-agent-ignoring-scope.md +0 -0
  364. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
  365. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
  366. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/typo-detection-codespell.md +0 -0
  367. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
  368. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
  369. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/uninstall-has-no-confirmation-prompt.md +0 -0
  370. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
  371. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/update-advertises-a-flag-it-rejects.md +0 -0
  372. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/update-diff-before-apply.md +0 -0
  373. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/update-refreshed-rules-without-a-gate.md +0 -0
  374. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
  375. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/update-reinstall-widens-agent-scope.md +0 -0
  376. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
  377. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
  378. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
  379. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/wire-bdd-suite-into-ci.md +0 -0
  380. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
  381. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
  382. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
  383. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/workspace-scope-install.md +0 -0
  384. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/zip-strict-audit.md +0 -0
  385. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/zizmor-pin-is-a-yanked-release.md +0 -0
  386. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/eslint.config.mjs +0 -0
  387. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/README.md +0 -0
  388. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/__init__.py +0 -0
  389. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/baseline.json +0 -0
  390. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/faithfulness.py +0 -0
  391. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/golden_set.json +0 -0
  392. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/make_corpus.py +0 -0
  393. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/make_golden.py +0 -0
  394. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/metrics.py +0 -0
  395. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/run_evals.py +0 -0
  396. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/examples/README.md +0 -0
  397. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/examples/adapt-demo.sh +0 -0
  398. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/examples/boost-run-prototype.sh +0 -0
  399. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/index.html +0 -0
  400. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/noxfile.py +0 -0
  401. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/pyproject.toml +0 -0
  402. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/coverage-tools.in +0 -0
  403. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/coverage-tools.txt +0 -0
  404. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/lint-tools.in +0 -0
  405. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/lint-tools.txt +0 -0
  406. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/mutation-tools.in +0 -0
  407. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/mutation-tools.txt +0 -0
  408. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/platform-pins.lock +0 -0
  409. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/release-tools.in +0 -0
  410. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/release-tools.txt +0 -0
  411. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/test-tools.in +0 -0
  412. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/test-tools.txt +0 -0
  413. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/a11y_check.py +0 -0
  414. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/bench_cli.sh +0 -0
  415. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/build_command_reference.py +0 -0
  416. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/build_demo_index.py +0 -0
  417. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/build_registries.py +0 -0
  418. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/build_roadmap.py +0 -0
  419. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/build_scale_corpus.py +0 -0
  420. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/check_anchors.py +0 -0
  421. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/check_licenses.py +0 -0
  422. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/check_required_checks.py +0 -0
  423. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/ensure_eval_corpus.sh +0 -0
  424. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/eval_corpus.py +0 -0
  425. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/eval_explain.py +0 -0
  426. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/eval_gate.py +0 -0
  427. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/eval_recommend.py +0 -0
  428. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/eval_retrieval.py +0 -0
  429. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/eval_stats_summary.py +0 -0
  430. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/import_budget.py +0 -0
  431. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/lock_toolchain.py +0 -0
  432. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/mutation_gate.py +0 -0
  433. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/mutation_shards.py +0 -0
  434. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/mutation_weights.json +0 -0
  435. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/page_budget.py +0 -0
  436. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/perf_gate.py +0 -0
  437. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/post_deploy_smoke.py +0 -0
  438. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/publish_eval_json.py +0 -0
  439. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/release_guard.py +0 -0
  440. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/release_preflight.py +0 -0
  441. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/serve_docs.py +0 -0
  442. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/setup.cfg +0 -0
  443. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/sonar-project.properties +0 -0
  444. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/style/README.md +0 -0
  445. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/style/boost.css +0 -0
  446. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/style/boost.js +0 -0
  447. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/style/demo.html +0 -0
  448. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/adapt.feature +0 -0
  449. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/browse.feature +0 -0
  450. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/count.feature +0 -0
  451. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/discover.feature +0 -0
  452. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/doctor.feature +0 -0
  453. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/environment.py +0 -0
  454. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/explain.feature +0 -0
  455. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/index.feature +0 -0
  456. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/install.feature +0 -0
  457. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/list.feature +0 -0
  458. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/mcp.feature +0 -0
  459. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/search.feature +0 -0
  460. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/steps/cli_steps.py +0 -0
  461. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/steps/discovery_steps.py +0 -0
  462. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/steps/mcp_steps.py +0 -0
  463. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/steps/quality_steps.py +0 -0
  464. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/conftest.py +0 -0
  465. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/eval/baseline.json +0 -0
  466. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/eval/explain.jsonl +0 -0
  467. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/eval/golden-natural.jsonl +0 -0
  468. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/eval/golden.jsonl +0 -0
  469. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/eval/recommend.jsonl +0 -0
  470. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/eval/taps-scale.txt +0 -0
  471. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/eval/taps.txt +0 -0
  472. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_capabilities_policy.py +0 -0
  473. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_adapt.py +0 -0
  474. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_bmad.py +0 -0
  475. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_chat.py +0 -0
  476. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_configuration.py +0 -0
  477. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_discovery.py +0 -0
  478. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_hooks.py +0 -0
  479. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_info.py +0 -0
  480. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_intelligence.py +0 -0
  481. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_taps.py +0 -0
  482. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_team.py +0 -0
  483. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_everyday_loop.py +0 -0
  484. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_integrity_enforce.py +0 -0
  485. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_property_parsers.py +0 -0
  486. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_run.py +0 -0
  487. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_tap_signing.py +0 -0
  488. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_workspace_scope.py +0 -0
  489. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/README.md +0 -0
  490. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/01-typical.md +0 -0
  491. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/02-lossy-version.md +0 -0
  492. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/03-lossy-numbers.md +0 -0
  493. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/04-lists.md +0 -0
  494. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/05-nested.md +0 -0
  495. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/06-empty-block.md +0 -0
  496. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/07-unterminated.md +0 -0
  497. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/08-none.md +0 -0
  498. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/09-unbalanced-quote.md +0 -0
  499. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/10-keywords.md +0 -0
  500. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/11-crlf.md +0 -0
  501. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/12-bom.md +0 -0
  502. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/registry/01-shorthand.txt +0 -0
  503. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/registry/02-https.txt +0 -0
  504. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/registry/03-ssh.txt +0 -0
  505. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/registry/04-traversal.txt +0 -0
  506. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/registry/05-empty.txt +0 -0
  507. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/registry/06-space.txt +0 -0
  508. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/registry/07-slash.txt +0 -0
  509. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/registry/08-bare-host.txt +0 -0
  510. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/fuzz_frontmatter.py +0 -0
  511. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/fuzz_registry.py +0 -0
  512. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/make_fixture.py +0 -0
  513. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/perf/test_benchmarks.py +0 -0
  514. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/smoke.sh +0 -0
  515. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_a11y_check.py +0 -0
  516. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_adapters.py +0 -0
  517. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_adapters_multi.py +0 -0
  518. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_adapters_runner.py +0 -0
  519. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_agents.py +0 -0
  520. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_ai.py +0 -0
  521. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_capabilities.py +0 -0
  522. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_catalog.py +0 -0
  523. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_chat.py +0 -0
  524. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_check_anchors.py +0 -0
  525. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_check_licenses.py +0 -0
  526. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_claude_settings.py +0 -0
  527. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_cliparse.py +0 -0
  528. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_codeql_analysis_key.py +0 -0
  529. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_command_reference_fresh.py +0 -0
  530. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_community_health_files.py +0 -0
  531. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_complete.py +0 -0
  532. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_config.py +0 -0
  533. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_content_dedupe.py +0 -0
  534. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_dedup_trust.py +0 -0
  535. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_demo_index.py +0 -0
  536. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_dense.py +0 -0
  537. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_dense_fallback.py +0 -0
  538. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_dense_fix_hint.py +0 -0
  539. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_dense_shards.py +0 -0
  540. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_dense_status.py +0 -0
  541. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_dependabot_config.py +0 -0
  542. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_docs_pages_linked.py +0 -0
  543. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_docsite_chrome.py +0 -0
  544. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_ed25519.py +0 -0
  545. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_embed.py +0 -0
  546. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_embed_local.py +0 -0
  547. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_entry_key.py +0 -0
  548. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_errors_and_cli_table.py +0 -0
  549. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_eval_baseline.py +0 -0
  550. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_eval_corpus.py +0 -0
  551. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_eval_faithfulness.py +0 -0
  552. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_eval_gate.py +0 -0
  553. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_eval_grading.py +0 -0
  554. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_eval_metrics.py +0 -0
  555. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_eval_stats_summary.py +0 -0
  556. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_faithfulness.py +0 -0
  557. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_frontmatter.py +0 -0
  558. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_fuzz_targets.py +0 -0
  559. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_gitleaks_config.py +0 -0
  560. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_gitutil.py +0 -0
  561. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_imperative.py +0 -0
  562. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_import_budget.py +0 -0
  563. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_injectscan.py +0 -0
  564. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_installscan.py +0 -0
  565. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_integrity.py +0 -0
  566. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_journal.py +0 -0
  567. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_localembed.py +0 -0
  568. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_localembed_e2e.py +0 -0
  569. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_lockfile.py +0 -0
  570. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_logs.py +0 -0
  571. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_marketing_counts.py +0 -0
  572. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_mcp.py +0 -0
  573. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_mcp_install_scan.py +0 -0
  574. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_mcpdecl.py +0 -0
  575. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_mcphost.py +0 -0
  576. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_minisign.py +0 -0
  577. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_mutation_hardening.py +0 -0
  578. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_mutation_shards.py +0 -0
  579. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_mutation_subfile_shards.py +0 -0
  580. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_mutmut_source_paths.py +0 -0
  581. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_nethttp.py +0 -0
  582. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_output.py +0 -0
  583. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_page_budget.py +0 -0
  584. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_paths.py +0 -0
  585. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_perf_gate.py +0 -0
  586. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_pkg_confusions.py +0 -0
  587. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_pkg_injection.py +0 -0
  588. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_pkg_secrets.py +0 -0
  589. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_platform_pins.py +0 -0
  590. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_policy.py +0 -0
  591. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_post_deploy_smoke.py +0 -0
  592. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_project_mcp_sidecar.py +0 -0
  593. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_projectlock.py +0 -0
  594. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_provenance.py +0 -0
  595. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_rag.py +0 -0
  596. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_rag_fusion.py +0 -0
  597. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_registries_fresh.py +0 -0
  598. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_registry.py +0 -0
  599. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_registry_categories.py +0 -0
  600. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_release_guard.py +0 -0
  601. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_release_preflight.py +0 -0
  602. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_required_checks.py +0 -0
  603. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_resolve.py +0 -0
  604. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_roadmap_fresh.py +0 -0
  605. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_rules.py +0 -0
  606. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_scale_corpus.py +0 -0
  607. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_scopes.py +0 -0
  608. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_secretscan.py +0 -0
  609. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_selfupdate.py +0 -0
  610. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_serve.py +0 -0
  611. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_serve_docs.py +0 -0
  612. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_spin.py +0 -0
  613. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_stackprobe.py +0 -0
  614. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_staleness.py +0 -0
  615. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_store.py +0 -0
  616. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_token_parity.py +0 -0
  617. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_toolchain_lock.py +0 -0
  618. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_trustaudit.py +0 -0
  619. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_typosquat.py +0 -0
  620. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_updatediff.py +0 -0
  621. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_util.py +0 -0
  622. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_version.py +0 -0
  623. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_workflow_concurrency.py +0 -0
  624. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_workflow_timeouts.py +0 -0
  625. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_workflows.py +0 -0
  626. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/visual/a11y_check.mjs +0 -0
  627. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/visual/console_check.mjs +0 -0
  628. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/visual/package-lock.json +0 -0
  629. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/visual/package.json +0 -0
  630. {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/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.402
3
+ Version: 1.0.404
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.402'
22
- __version_tuple__ = version_tuple = (1, 0, 402)
21
+ __version__ = version = '1.0.404'
22
+ __version_tuple__ = version_tuple = (1, 0, 404)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -388,7 +388,18 @@ def cmd_install(argv: List[str]) -> int:
388
388
  multi = multi or len(entries) > 1
389
389
 
390
390
  if args.dry_run:
391
+ # TWO lists, because the three kinds do not reach the same agents.
392
+ # Rules and workflows materialize into every enabled agent's dotdir,
393
+ # Gemini included. A skill is symlinked only into the agents that take
394
+ # links — Gemini reads the canonical store directly and is deliberately
395
+ # never linked (see agents.linking_agents). One list for both is how
396
+ # `--dry-run` came to promise a `~/.gemini/skills` symlink that the real
397
+ # install has never created.
391
398
  targets = [a for a in agents.enabled_agents() if not only or a in only]
399
+ link_targets = [a for a in agents.linking_agents()
400
+ if not only or a in only]
401
+ native_targets = [a for a in agents.native_store_agents()
402
+ if not only or a in only]
392
403
  pbase = scopes.resolve_base(args.scope)
393
404
  if args.scope == scopes.SCOPE_PROJECT and pbase is None:
394
405
  raise BoostError(
@@ -423,7 +434,14 @@ def cmd_install(argv: List[str]) -> int:
423
434
  e["version"], e["tap"]))
424
435
  out.info(" copy %s → %s" % (_tilde(store.source_dir_for(e)),
425
436
  _tilde(store.skill_store_dir(e["name"]))))
426
- out.info(" link → %s" % (" · ".join(targets) or "(no enabled agents)"))
437
+ out.info(" link → %s" % (" · ".join(link_targets)
438
+ or "(no linking agents)"))
439
+ # Mirrors what the real install reports, so a Gemini-only install
440
+ # does not read as reaching no agent at all.
441
+ if native_targets:
442
+ out.info(" available to %s (reads the store directly)"
443
+ % " · ".join(agents.display_name(a)
444
+ for a in native_targets))
427
445
  out.info("dry run — nothing was changed")
428
446
  return 1 if failed else 0
429
447
 
@@ -76,17 +76,120 @@ _STACK_MARKERS = [
76
76
  _tilde = paths.tilde
77
77
 
78
78
 
79
- def _broken_links() -> List[Path]:
80
- """Broken (dangling) symlinks across every enabled agent dir."""
81
- broken: List[Path] = []
82
- for adir in agents.enabled_agents().values():
79
+ def _resolve_as_far_as_it_exists(path: Path) -> Path:
80
+ """Absolute ``path``, symlinks resolved down to its deepest real ancestor.
81
+
82
+ Plain ``resolve()`` is wrong on both sides of this comparison. The link's
83
+ target does not exist — that is what makes the link broken — and the store
84
+ dir does, so resolving only the one that can be resolved compares a real
85
+ path against a nominal one. On macOS that is not hypothetical: ``/tmp`` is
86
+ itself a symlink to ``/private/tmp``, so a genuine boost link read as
87
+ foreign and `heal` declined to repair anything.
88
+ """
89
+ path = Path(os.path.abspath(str(path)))
90
+ tail: List[str] = []
91
+ cur = path
92
+ while cur != cur.parent and not cur.exists():
93
+ tail.append(cur.name)
94
+ cur = cur.parent
95
+ with suppress(OSError):
96
+ cur = cur.resolve()
97
+ return cur.joinpath(*reversed(tail))
98
+
99
+
100
+ def _norm(path: Path) -> str:
101
+ """``path`` as a comparable string, without resolving anything.
102
+
103
+ Strips Windows' extended-length prefix — ``os.readlink`` returns
104
+ ``\\\\?\\C:\\...`` for a link the store created while ``store_dir()`` is
105
+ spelled the ordinary way, so the two name one location with two strings —
106
+ and applies `os.path.normcase`, which folds case on Windows (where the
107
+ filesystem is case-insensitive) and is a no-op on POSIX.
108
+ """
109
+ # Strip BEFORE abspath: on a POSIX host a backslash path is not absolute,
110
+ # so abspath would prepend the cwd and move the prefix out of position —
111
+ # which matters because this must be testable off Windows.
112
+ text = str(path)
113
+ for prefix in ("\\\\?\\UNC\\", "\\\\?\\"):
114
+ if text.startswith(prefix):
115
+ text = text[len(prefix):]
116
+ break
117
+ return os.path.normcase(os.path.abspath(text))
118
+
119
+
120
+ def _within(target: str, parent: str) -> bool:
121
+ """True if normalised ``target`` is ``parent`` or sits under it."""
122
+ return target == parent or target.startswith(parent.rstrip(os.sep) + os.sep)
123
+
124
+
125
+ def _link_key(path: Path) -> str:
126
+ """``path`` resolved, then normalised into a comparable string.
127
+
128
+ Comparing `Path` objects directly is wrong on Windows, in two ways that
129
+ both read as "boost does not own its own link" and left `heal` refusing to
130
+ repair anything at all there:
131
+
132
+ * ``os.readlink`` returns the extended-length form (``\\\\?\\C:\\...``) for
133
+ a link the store created, while ``store_dir()`` is spelled the ordinary
134
+ way — same location, different string.
135
+ * The filesystem is case-insensitive, so ``C:\\Users`` and ``c:\\users``
136
+ are one directory and two unequal `Path`s.
137
+
138
+ `os.path.normcase` is a no-op on POSIX, so this stays exact where case is.
139
+ """
140
+ return _norm(_resolve_as_far_as_it_exists(path))
141
+
142
+
143
+ def _owned_link(link: Path) -> bool:
144
+ """True if ``link`` points into boost's canonical store.
145
+
146
+ Ownership is read off the link itself rather than the lock, so it still
147
+ answers correctly for a skill uninstalled mid-sweep or a lock that has gone
148
+ missing — the two cases where a dangling link is most likely to exist.
149
+ """
150
+ try:
151
+ raw = Path(os.readlink(str(link)))
152
+ except OSError:
153
+ return False
154
+ target = raw if raw.is_absolute() else link.parent / raw
155
+ store = paths.store_dir()
156
+ # Spelled form first. A link boost made carries the store's own path, so
157
+ # this settles the ordinary case without resolving anything — and every
158
+ # platform quirk lives in resolution. Windows alone supplies three: the
159
+ # extended-length prefix, 8.3 short names, and case-insensitivity.
160
+ if _within(_norm(target), _norm(store)):
161
+ return True
162
+ # Resolved form second, for a store genuinely reached through a symlinked
163
+ # parent — macOS `/tmp` -> `/private/tmp` is the case that made this
164
+ # necessary rather than theoretical.
165
+ return _within(_link_key(target), _link_key(store))
166
+
167
+
168
+ def _broken_links() -> Tuple[List[Path], List[Path]]:
169
+ """``(ours, theirs)`` — dangling symlinks in the dirs boost links into.
170
+
171
+ Two things this deliberately does NOT do.
172
+
173
+ **It does not look in a native-store agent's dir.** `linking_agents`, not
174
+ `enabled_agents`: boost never links into `~/.gemini/skills`, so anything
175
+ dangling there belongs to someone else and is none of this command's
176
+ business. The rest of `cmd_heal` already had this right.
177
+
178
+ **It does not report a link boost did not create as ours.** `heal` deletes
179
+ what this returns first, and a broken link is not necessarily garbage — a
180
+ skill on an unmounted volume dangles until the volume comes back. Removing
181
+ a link the user made themselves is not a repair, it is data loss with a
182
+ reassuring name, so those are reported and left alone.
183
+ """
184
+ ours: List[Path] = []
185
+ theirs: List[Path] = []
186
+ for adir in agents.linking_agents().values():
83
187
  if not adir.is_dir():
84
188
  continue
85
- broken.extend(
86
- link for link in sorted(adir.iterdir())
87
- if link.is_symlink() and not link.exists()
88
- )
89
- return broken
189
+ for link in sorted(adir.iterdir()):
190
+ if link.is_symlink() and not link.exists():
191
+ (ours if _owned_link(link) else theirs).append(link)
192
+ return ours, theirs
90
193
 
91
194
 
92
195
  def _read_skill(skill_dir: Path) -> Tuple[dict, str]:
@@ -365,10 +468,18 @@ def cmd_doctor(argv):
365
468
  bad("%d orphaned store dir%s (%s) — run `boost sync`"
366
469
  % (len(orphans), _s(len(orphans)), ", ".join(orphans[:5])))
367
470
 
368
- broken = _broken_links()
471
+ broken, foreign = _broken_links()
369
472
  if broken:
370
473
  bad("%d broken symlink%s in agent dirs — run `boost heal`"
371
474
  % (len(broken), _s(len(broken))))
475
+ if foreign:
476
+ # `out.info`, not `bad`: this does not raise the issue count, because
477
+ # boost will not fix it and `heal` deliberately leaves it — counting it
478
+ # would leave doctor permanently red on something no boost command can
479
+ # clear, which is how a health check stops being read.
480
+ out.info("%d broken symlink%s in agent dirs not created by boost — "
481
+ "left alone; yours to remove or repair"
482
+ % (len(foreign), _s(len(foreign))))
372
483
 
373
484
  for adir in enabled.values():
374
485
  if adir.is_dir() and not os.access(str(adir), os.W_OK):
@@ -691,13 +802,19 @@ def cmd_heal(argv):
691
802
  % (len(missing), "y" if len(missing) == 1 else "ies"))
692
803
  actions.append("mkdir %d" % len(missing))
693
804
 
694
- for link in _broken_links():
805
+ ours, theirs = _broken_links()
806
+ for link in ours:
695
807
  if dry:
696
808
  out.info("would remove broken link %s" % _tilde(link))
697
809
  else:
698
810
  link.unlink()
699
811
  out.ok("removed broken link %s" % _tilde(link))
700
812
  actions.append("unlink %s" % link.name)
813
+ for link in theirs:
814
+ # Named, never touched: it is in a directory boost writes to, so the
815
+ # user should know it is dangling — but boost did not put it there.
816
+ out.warn("broken link %s does not point into %s — left alone"
817
+ % (_tilde(link), _tilde(paths.store_dir())))
701
818
 
702
819
  plan = store.sync_plan()
703
820
  if dry:
@@ -920,8 +1037,9 @@ def cmd_health(argv):
920
1037
  decay_n = sum(1 for r in _decay_rows(Path.cwd()) if r["verdict"] == "decay")
921
1038
  out.kv("decay", "%d candidate%s" % (decay_n, _s(decay_n)))
922
1039
 
923
- broken = _broken_links()
924
- out.kv("broken links", str(len(broken)))
1040
+ broken, foreign = _broken_links()
1041
+ out.kv("broken links", "%d%s" % (
1042
+ len(broken), " (+%d not ours)" % len(foreign) if foreign else ""))
925
1043
 
926
1044
  last_sync = "never"
927
1045
  if cloned and gitutil.has_git():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.402
3
+ Version: 1.0.404
4
4
  Summary: boost — Homebrew for AI coding skills
5
5
  Author: Jonathan Reyes
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -213,6 +213,7 @@ docs/roadmap/items/dependency-cve-gate-pip-audit.md
213
213
  docs/roadmap/items/docsite-chrome-and-content-audit.md
214
214
  docs/roadmap/items/docstring-coverage-interrogate.md
215
215
  docs/roadmap/items/doctor-checks-rules-and-workflows.md
216
+ docs/roadmap/items/dry-run-promised-a-link-nobody-makes.md
216
217
  docs/roadmap/items/end-of-options-guard-on-git-commands.md
217
218
  docs/roadmap/items/eval-corpus-cannot-see-real-retrieval.md
218
219
  docs/roadmap/items/eval-corpus-is-96x-smaller-than-a-real-install.md
@@ -235,6 +236,7 @@ docs/roadmap/items/github-pages-deploy-is-broken-every-push.md
235
236
  docs/roadmap/items/golden-set-grades-by-name-not-by-skill.md
236
237
  docs/roadmap/items/golden-set-statistical-power.md
237
238
  docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md
239
+ docs/roadmap/items/heal-deleted-links-it-never-made.md
238
240
  docs/roadmap/items/html-validation-html-validate.md
239
241
  docs/roadmap/items/info-rejects-the-qualified-name-it-recommends.md
240
242
  docs/roadmap/items/install-docs-never-mentioned-upgrading.md
@@ -560,6 +562,7 @@ tests/unit/test_injectscan.py
560
562
  tests/unit/test_installscan.py
561
563
  tests/unit/test_integrity.py
562
564
  tests/unit/test_journal.py
565
+ tests/unit/test_link_ownership.py
563
566
  tests/unit/test_localembed.py
564
567
  tests/unit/test_localembed_e2e.py
565
568
  tests/unit/test_lockfile.py
@@ -0,0 +1,43 @@
1
+ ---
2
+ id: dry-run-promised-a-link-nobody-makes
3
+ board: code
4
+ section: internals
5
+ status: shipped
6
+ category: Correctness
7
+ complexity: S
8
+ impact: Medium
9
+ wow: 3
10
+ note: the bug was written down in a test comment and pinned as "behaves today"
11
+ order: 100
12
+ owner: fix/dry-run-matches-the-real-install
13
+ pr: 460
14
+ title: install --dry-run predicted an install that never happens
15
+ ---
16
+ <b>A preview has exactly one job, and this one got it wrong by an agent and a verb.</b>
17
+ <code>boost install brainstorming --dry-run</code> reported
18
+ <code>link&nbsp;&rarr;&nbsp;claude-code&nbsp;&middot;&nbsp;windsurf&nbsp;&middot;&nbsp;cursor&nbsp;&middot;&nbsp;gemini</code>.
19
+ The real install reports three agents, plus a separate line saying Gemini reads the store directly
20
+ &mdash; and <code>~/.gemini/skills</code> does not exist afterwards, because boost has never created
21
+ it.
22
+
23
+ <b>One list was doing two jobs.</b> The dry-run block computed a single set of targets from
24
+ <code>agents.enabled_agents()</code> and printed it for both the skill <code>link</code> line and the
25
+ rule/workflow <code>materialize</code> line. For rules and workflows that is right: they really are
26
+ materialised into every enabled agent's dotdir, Gemini included. For a <i>skill</i> it is wrong,
27
+ because Gemini implements the Agent Skills standard and discovers the canonical store itself, so it
28
+ is configured <code>links_skills: false</code> and is deliberately never symlinked. CLAUDE.md is
29
+ explicit &mdash; iterate <code>linking_agents()</code> for anything symlink-shaped.
30
+
31
+ <b>The bug was already written down.</b> The functional test carried a comment saying so:
32
+ "<i>the preview lists every enabled agent, so it still promises a gemini link the real install does
33
+ not make &hellip; Pinned as it behaves today.</i>" Someone found it, understood it, described it
34
+ accurately, and pinned the wrong behaviour rather than fixing it &mdash; which is how a known defect
35
+ acquires a test that defends it.
36
+
37
+ <b>Fixed as a distinction, not a deletion.</b> A skill's preview names the agents that take links and
38
+ adds the same "available to Gemini CLI (reads the store directly)" line the real install prints; a
39
+ rule's preview still names all four, because a rule genuinely reaches all four. A test now compares
40
+ the two runs field by field &mdash; the preview's link list against the real install's &mdash;
41
+ because <code>"a&nbsp;&middot;&nbsp;b&nbsp;&middot;&nbsp;c"</code> contains
42
+ <code>"a&nbsp;&middot;&nbsp;b"</code>, so a substring assertion passes on exactly this bug. It was
43
+ written as a substring first and caught nothing until it was tightened.
@@ -0,0 +1,54 @@
1
+ ---
2
+ id: heal-deleted-links-it-never-made
3
+ board: code
4
+ section: internals
5
+ status: shipped
6
+ category: Safety · Correctness
7
+ complexity: S
8
+ impact: Medium
9
+ wow: 4
10
+ note: a dangling link is not garbage — an unmounted volume comes back, and heal deleted it anyway
11
+ order: 99
12
+ owner: fix/heal-only-removes-links-it-owns
13
+ pr: 459
14
+ title: heal removed symlinks boost never created
15
+ ---
16
+ <b><code>boost heal</code> deleted a symlink boost did not make, does not track, and has no claim
17
+ to.</b> Reproduced against a sandbox: plant
18
+ <code>~/.claude/skills/my-own-skill&nbsp;&rarr;&nbsp;~/elsewhere/my-own-skill</code>, run
19
+ <code>boost heal</code>, and it reports <i>"removed broken link ~/.claude/skills/my-own-skill"</i>.
20
+ Same scenario on the fixed build leaves it exactly where it was.
21
+
22
+ <b>A broken link is not the same as garbage.</b> <code>~/.claude/skills/</code> is the user's own
23
+ directory that boost happens to link into. A dangling entry there can be a skill on an unmounted
24
+ volume, a repo checked out somewhere else for the afternoon, or a link into a detached drive
25
+ &mdash; all of which come back. Removing one is not a repair; it is data loss under a reassuring
26
+ name, from a command whose entire promise is that it is safe to run.
27
+
28
+ <b>Ownership is legible from the link itself.</b> Every link boost creates points into the canonical
29
+ store, <code>~/.agents/skills/&lt;name&gt;</code>. Reading the target beats consulting the lock,
30
+ because the two moments a dangling link is most likely to exist &mdash; a skill uninstalled
31
+ mid-sweep, a lock file that has gone missing &mdash; are exactly the moments the lock cannot answer.
32
+ Links into the store are swept; everything else is <i>named</i> and left alone, because the user
33
+ should still know it is dangling.
34
+
35
+ <b>The scan was also looking somewhere it has no business.</b> <code>_broken_links</code> iterated
36
+ <code>agents.enabled_agents()</code>, which includes Gemini &mdash; and boost never links into
37
+ <code>~/.gemini/skills</code> at all, because Gemini CLI reads the canonical store directly.
38
+ CLAUDE.md states the rule outright: iterate <code>linking_agents()</code> "for anything
39
+ symlink-shaped (link, unlink, stale-link sweeps, coverage counts)". The <i>same function</i> already
40
+ had it right eleven lines further down, where <code>cmd_heal</code> builds its list of missing
41
+ directories and comments on precisely this distinction.
42
+
43
+ <b>A macOS-only trap sat inside the fix.</b> The first attempt compared
44
+ <code>store_dir().resolve()</code> against a normalised link target &mdash; resolving the side that
45
+ exists and not the side that does not. On macOS <code>/tmp</code> is itself a symlink to
46
+ <code>/private/tmp</code>, so a genuine boost link read as foreign and <code>heal</code> declined to
47
+ repair anything at all. Both sides are now resolved down to their deepest real ancestor, which is
48
+ the only comparison that is correct when one path is dangling by definition.
49
+
50
+ <b><code>doctor</code> reports it without going red.</b> A foreign broken link is printed as
51
+ information, not counted as an issue: <code>heal</code> deliberately will not fix it, so counting it
52
+ would leave <code>doctor</code> permanently red on something no boost command can clear &mdash;
53
+ which is how a health check stops being read. Two tests pin the behaviour and both fail with the
54
+ ownership check reverted.
@@ -125,7 +125,7 @@
125
125
  <div class="stat"><b>16</b><span>Shipped</span></div>
126
126
  <div class="stat"><b>1</b><span>Next up</span></div>
127
127
  <div class="stat"><b>8</b><span>Planned</span></div>
128
- <div class="stat"><b>215</b><span>Loop finds</span></div>
128
+ <div class="stat"><b>217</b><span>Loop finds</span></div>
129
129
  <!-- /ROADMAP:stats -->
130
130
  </div>
131
131
  </section>
@@ -3470,6 +3470,97 @@ brake anyone can see, not a policy anyone can set.</p></details>
3470
3470
  <span class="m">install scanned rule content; update did not — and the scanner could not see concealment anyway</span>
3471
3471
  </div>
3472
3472
  </article>
3473
+
3474
+ <article class="cap rcard" id="heal-deleted-links-it-never-made">
3475
+ <div class="head"><span class="pill shipped">Shipped</span><span class="cat">Safety · Correctness</span></div>
3476
+ <h3>heal removed symlinks boost never created</h3>
3477
+ <details class="cardbody"><summary>Write-up</summary>
3478
+ <p><b><code>boost heal</code> deleted a symlink boost did not make, does not track, and has no claim
3479
+ to.</b> Reproduced against a sandbox: plant
3480
+ <code>~/.claude/skills/my-own-skill&nbsp;&rarr;&nbsp;~/elsewhere/my-own-skill</code>, run
3481
+ <code>boost heal</code>, and it reports <i>"removed broken link ~/.claude/skills/my-own-skill"</i>.
3482
+ Same scenario on the fixed build leaves it exactly where it was.
3483
+
3484
+ <b>A broken link is not the same as garbage.</b> <code>~/.claude/skills/</code> is the user's own
3485
+ directory that boost happens to link into. A dangling entry there can be a skill on an unmounted
3486
+ volume, a repo checked out somewhere else for the afternoon, or a link into a detached drive
3487
+ &mdash; all of which come back. Removing one is not a repair; it is data loss under a reassuring
3488
+ name, from a command whose entire promise is that it is safe to run.
3489
+
3490
+ <b>Ownership is legible from the link itself.</b> Every link boost creates points into the canonical
3491
+ store, <code>~/.agents/skills/&lt;name&gt;</code>. Reading the target beats consulting the lock,
3492
+ because the two moments a dangling link is most likely to exist &mdash; a skill uninstalled
3493
+ mid-sweep, a lock file that has gone missing &mdash; are exactly the moments the lock cannot answer.
3494
+ Links into the store are swept; everything else is <i>named</i> and left alone, because the user
3495
+ should still know it is dangling.
3496
+
3497
+ <b>The scan was also looking somewhere it has no business.</b> <code>_broken_links</code> iterated
3498
+ <code>agents.enabled_agents()</code>, which includes Gemini &mdash; and boost never links into
3499
+ <code>~/.gemini/skills</code> at all, because Gemini CLI reads the canonical store directly.
3500
+ CLAUDE.md states the rule outright: iterate <code>linking_agents()</code> "for anything
3501
+ symlink-shaped (link, unlink, stale-link sweeps, coverage counts)". The <i>same function</i> already
3502
+ had it right eleven lines further down, where <code>cmd_heal</code> builds its list of missing
3503
+ directories and comments on precisely this distinction.
3504
+
3505
+ <b>A macOS-only trap sat inside the fix.</b> The first attempt compared
3506
+ <code>store_dir().resolve()</code> against a normalised link target &mdash; resolving the side that
3507
+ exists and not the side that does not. On macOS <code>/tmp</code> is itself a symlink to
3508
+ <code>/private/tmp</code>, so a genuine boost link read as foreign and <code>heal</code> declined to
3509
+ repair anything at all. Both sides are now resolved down to their deepest real ancestor, which is
3510
+ the only comparison that is correct when one path is dangling by definition.
3511
+
3512
+ <b><code>doctor</code> reports it without going red.</b> A foreign broken link is printed as
3513
+ information, not counted as an issue: <code>heal</code> deliberately will not fix it, so counting it
3514
+ would leave <code>doctor</code> permanently red on something no boost command can clear &mdash;
3515
+ which is how a health check stops being read. Two tests pin the behaviour and both fail with the
3516
+ ownership check reverted.</p></details>
3517
+ <div class="meta">
3518
+ <span class="m">Complexity <b>S</b></span>
3519
+ <span class="m">Impact <b>Medium</b></span>
3520
+ <span class="m">Wow <b class="wow">★★★★</b></span>
3521
+ <span class="m">a dangling link is not garbage — an unmounted volume comes back, and heal deleted it anyway</span>
3522
+ </div>
3523
+ </article>
3524
+
3525
+ <article class="cap rcard" id="dry-run-promised-a-link-nobody-makes">
3526
+ <div class="head"><span class="pill shipped">Shipped</span><span class="cat">Correctness</span></div>
3527
+ <h3>install --dry-run predicted an install that never happens</h3>
3528
+ <details class="cardbody"><summary>Write-up</summary>
3529
+ <p><b>A preview has exactly one job, and this one got it wrong by an agent and a verb.</b>
3530
+ <code>boost install brainstorming --dry-run</code> reported
3531
+ <code>link&nbsp;&rarr;&nbsp;claude-code&nbsp;&middot;&nbsp;windsurf&nbsp;&middot;&nbsp;cursor&nbsp;&middot;&nbsp;gemini</code>.
3532
+ The real install reports three agents, plus a separate line saying Gemini reads the store directly
3533
+ &mdash; and <code>~/.gemini/skills</code> does not exist afterwards, because boost has never created
3534
+ it.
3535
+
3536
+ <b>One list was doing two jobs.</b> The dry-run block computed a single set of targets from
3537
+ <code>agents.enabled_agents()</code> and printed it for both the skill <code>link</code> line and the
3538
+ rule/workflow <code>materialize</code> line. For rules and workflows that is right: they really are
3539
+ materialised into every enabled agent's dotdir, Gemini included. For a <i>skill</i> it is wrong,
3540
+ because Gemini implements the Agent Skills standard and discovers the canonical store itself, so it
3541
+ is configured <code>links_skills: false</code> and is deliberately never symlinked. CLAUDE.md is
3542
+ explicit &mdash; iterate <code>linking_agents()</code> for anything symlink-shaped.
3543
+
3544
+ <b>The bug was already written down.</b> The functional test carried a comment saying so:
3545
+ "<i>the preview lists every enabled agent, so it still promises a gemini link the real install does
3546
+ not make &hellip; Pinned as it behaves today.</i>" Someone found it, understood it, described it
3547
+ accurately, and pinned the wrong behaviour rather than fixing it &mdash; which is how a known defect
3548
+ acquires a test that defends it.
3549
+
3550
+ <b>Fixed as a distinction, not a deletion.</b> A skill's preview names the agents that take links and
3551
+ adds the same "available to Gemini CLI (reads the store directly)" line the real install prints; a
3552
+ rule's preview still names all four, because a rule genuinely reaches all four. A test now compares
3553
+ the two runs field by field &mdash; the preview's link list against the real install's &mdash;
3554
+ because <code>"a&nbsp;&middot;&nbsp;b&nbsp;&middot;&nbsp;c"</code> contains
3555
+ <code>"a&nbsp;&middot;&nbsp;b"</code>, so a substring assertion passes on exactly this bug. It was
3556
+ written as a substring first and caught nothing until it was tightened.</p></details>
3557
+ <div class="meta">
3558
+ <span class="m">Complexity <b>S</b></span>
3559
+ <span class="m">Impact <b>Medium</b></span>
3560
+ <span class="m">Wow <b class="wow">★★★</b></span>
3561
+ <span class="m">the bug was written down in a test comment and pinned as "behaves today"</span>
3562
+ </div>
3563
+ </article>
3473
3564
  <!-- /ROADMAP:cards -->
3474
3565
 
3475
3566
  </div>
@@ -123,14 +123,47 @@ class TestInstall:
123
123
  r = boost("install", "--dry-run", "brainstorming")
124
124
  assert "would install brainstorming v1.4.0 from fixture-tap" in r.out
125
125
  assert "~/.boost/repos/fixture-tap/skills/brainstorming" in r.out
126
- # NOTE: the preview lists every *enabled* agent, so it still promises a
127
- # gemini link the real install does not make (gemini reads the store
128
- # directly — see test_exact_report_lines). Pinned as it behaves today.
129
- assert "link → claude-code · windsurf · cursor · gemini" in r.out
126
+ # The preview names the agents that actually take a link. Gemini reads
127
+ # the canonical store directly and is never symlinked, so promising one
128
+ # here made the dry run wrong about the one thing it exists to predict.
129
+ assert "link → claude-code · windsurf · cursor" in r.out
130
+ assert "· gemini" not in r.out
131
+ assert "available to Gemini CLI (reads the store directly)" in r.out
130
132
  assert "dry run — nothing was changed" in r.out
131
133
  assert not (paths.store_dir() / "brainstorming").exists()
132
134
  assert not paths.lockfile_path().exists()
133
135
 
136
+ def test_dry_run_predicts_the_real_install(self, boost, tapped):
137
+ """The whole job of a preview: say what the real run will do.
138
+
139
+ These two disagreed by one agent and one verb — `--dry-run` promised a
140
+ `~/.gemini/skills` symlink that no install has ever created.
141
+ """
142
+ def agents_on(text, marker):
143
+ line = next(x for x in text.splitlines() if marker in x)
144
+ return line.split("→", 1)[1].strip()
145
+
146
+ preview = boost("install", "--dry-run", "brainstorming").out
147
+ real = boost("install", "brainstorming").out
148
+ # Compared as whole fields, not substrings: "a · b · c" contains
149
+ # "a · b", so a substring check would have passed on the bug.
150
+ assert agents_on(preview, "link →") == agents_on(real, "linked →")
151
+ for text in (preview, real):
152
+ assert "available to Gemini CLI (reads the store directly)" in text
153
+ assert not (paths.home() / ".gemini" / "skills").exists()
154
+
155
+ def test_dry_run_still_names_gemini_for_a_rule(self, boost, fixture_tap_src,
156
+ tmp_path):
157
+ # The distinction is the point, not a blanket removal: a RULE really is
158
+ # materialized into ~/.gemini/, so the preview must keep saying so.
159
+ tap_dir = _copy_tap(fixture_tap_src, tmp_path / "rule-dry-tap")
160
+ _add_and_commit(tap_dir, "rules/house.mdc",
161
+ "---\nname: house-style\nversion: 1.0.0\n---\n\nUse tabs.\n",
162
+ "add rule")
163
+ boost("tap", tap_dir)
164
+ r = boost("install", "house-style", "--dry-run")
165
+ assert "materialize → claude-code · windsurf · cursor · gemini" in r.out
166
+
134
167
  def test_installs_declared_requires_closure(self, boost, tapped):
135
168
  # jira-integration declares `requires: [commit-messages]` in the fixture;
136
169
  # installing it must pull in the dependency, dependency-first.
@@ -79,6 +79,17 @@ class TestDoctor:
79
79
  assert "1 skill installed · 1 tap synced · 1 broken link" in r.out
80
80
  assert "need attention" in r.out # verdict flips on issues
81
81
 
82
+ def test_a_foreign_broken_link_is_reported_but_not_an_issue(
83
+ self, boost, installed):
84
+ # `heal` deliberately will not fix this, so counting it would leave
85
+ # doctor permanently red on something no boost command can clear.
86
+ mine = paths.home() / ".claude" / "skills" / "my-own-skill"
87
+ mine.symlink_to(paths.home() / "elsewhere" / "my-own-skill")
88
+ r = boost("doctor") # rc 0, not 1
89
+ assert "not created by boost" in r.out
90
+ assert "0 broken links" in r.out # none of boost's are broken
91
+ assert "need attention" not in r.out
92
+
82
93
  def test_missing_store_rc1(self, boost, installed):
83
94
  shutil.rmtree(paths.store_dir() / "brainstorming")
84
95
  r = boost("doctor", expect=1)
@@ -545,6 +556,34 @@ class TestHeal:
545
556
  r = boost("heal")
546
557
  assert "nothing to heal" in r.out
547
558
 
559
+ def test_a_link_boost_did_not_create_is_left_alone(self, boost, installed):
560
+ """`heal` deleted these. A broken link is not necessarily garbage.
561
+
562
+ `~/.claude/skills/` is a directory the user owns and boost merely links
563
+ into, so a dangling entry there can be a skill on an unmounted volume or
564
+ a repo temporarily moved — both of which come back. Removing it is not a
565
+ repair, it is data loss with a reassuring name.
566
+ """
567
+ mine = paths.home() / ".claude" / "skills" / "my-own-skill"
568
+ mine.symlink_to(paths.home() / "elsewhere" / "my-own-skill")
569
+
570
+ r = boost("heal")
571
+ assert "does not point into" in r.out
572
+ assert "left alone" in r.out
573
+ assert mine.is_symlink() # still there, still dangling
574
+ assert "removed broken link ~/.claude/skills/my-own-skill" not in r.out
575
+
576
+ def test_a_relative_link_into_the_store_is_still_ours(self, boost, installed):
577
+ # Ownership is decided by where the link points, not by how it is
578
+ # spelled — a relative target resolves against the link's own dir.
579
+ rel = paths.home() / ".claude" / "skills" / "relghost"
580
+ import os as _os
581
+ rel.symlink_to(_os.path.relpath(str(paths.store_dir() / "nowhere"),
582
+ str(rel.parent)))
583
+ r = boost("heal")
584
+ assert "removed broken link ~/.claude/skills/relghost" in r.out
585
+ assert not rel.is_symlink()
586
+
548
587
  def test_restores_missing_store_from_tap(self, boost, installed):
549
588
  shutil.rmtree(paths.store_dir() / "brainstorming")
550
589
  r = boost("heal")