boost-skill-cli 1.0.121__tar.gz → 1.0.123__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 (267) hide show
  1. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/.gitignore +3 -0
  2. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/CLAUDE.md +16 -2
  3. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/Makefile +17 -8
  4. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/PKG-INFO +1 -1
  5. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/_version.py +2 -2
  6. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/commands/discovery.py +2 -91
  7. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/commands/intelligence.py +1 -1
  8. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/commands/quality.py +1 -1
  9. boost_skill_cli-1.0.123/boost_cli/core/stackprobe.py +108 -0
  10. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_skill_cli.egg-info/PKG-INFO +1 -1
  11. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_skill_cli.egg-info/SOURCES.txt +4 -0
  12. boost_skill_cli-1.0.123/docs/roadmap/items/single-tech-stack-prober.md +27 -0
  13. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap.html +14 -2
  14. boost_skill_cli-1.0.123/scripts/ensure_eval_corpus.sh +29 -0
  15. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/scripts/eval_retrieval.py +5 -2
  16. boost_skill_cli-1.0.123/tests/eval/baseline.json +17 -0
  17. boost_skill_cli-1.0.123/tests/eval/taps.txt +23 -0
  18. boost_skill_cli-1.0.123/tests/unit/test_stackprobe.py +115 -0
  19. boost_skill_cli-1.0.121/docs/roadmap/items/single-tech-stack-prober.md +0 -16
  20. boost_skill_cli-1.0.121/tests/eval/baseline.json +0 -17
  21. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/.gitattributes +0 -0
  22. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/CONTRIBUTING.md +0 -0
  23. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/LICENSE +0 -0
  24. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/MANIFEST.in +0 -0
  25. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/README.md +0 -0
  26. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/SECURITY.md +0 -0
  27. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost +0 -0
  28. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/__init__.py +0 -0
  29. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/__main__.py +0 -0
  30. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/cli.py +0 -0
  31. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/cliparse.py +0 -0
  32. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/commands/__init__.py +0 -0
  33. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/commands/bmad.py +0 -0
  34. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/commands/configuration.py +0 -0
  35. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/commands/hooks.py +0 -0
  36. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/commands/info.py +0 -0
  37. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/commands/pkg.py +0 -0
  38. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/commands/taps.py +0 -0
  39. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/commands/team.py +0 -0
  40. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/__init__.py +0 -0
  41. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/agents.py +0 -0
  42. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/ai.py +0 -0
  43. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/catalog.py +0 -0
  44. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/claude_settings.py +0 -0
  45. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/config.py +0 -0
  46. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/dense.py +0 -0
  47. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/embed.py +0 -0
  48. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/frontmatter.py +0 -0
  49. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/gitutil.py +0 -0
  50. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/injectscan.py +0 -0
  51. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/journal.py +0 -0
  52. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/lockfile.py +0 -0
  53. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/logs.py +0 -0
  54. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/mcp.py +0 -0
  55. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/nethttp.py +0 -0
  56. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/output.py +0 -0
  57. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/paths.py +0 -0
  58. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/policy.py +0 -0
  59. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/rag.py +0 -0
  60. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/registry.py +0 -0
  61. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/secretscan.py +0 -0
  62. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/serve.py +0 -0
  63. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/staleness.py +0 -0
  64. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/store.py +0 -0
  65. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/typosquat.py +0 -0
  66. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/updatediff.py +0 -0
  67. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/core/util.py +0 -0
  68. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/data/registries.json +0 -0
  69. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/errors.py +0 -0
  70. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_cli/spin.py +0 -0
  71. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
  72. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_skill_cli.egg-info/entry_points.txt +0 -0
  73. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_skill_cli.egg-info/requires.txt +0 -0
  74. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/boost_skill_cli.egg-info/top_level.txt +0 -0
  75. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/.claude/settings.local.json +0 -0
  76. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/DEBUGGING.md +0 -0
  77. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/demo.gif +0 -0
  78. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/demo.tape +0 -0
  79. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/design-roadmap.html +0 -0
  80. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/index.html +0 -0
  81. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/mcp-hub.html +0 -0
  82. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/rag-architecture.md +0 -0
  83. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D01.md +0 -0
  84. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D02.md +0 -0
  85. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D03.md +0 -0
  86. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D04.md +0 -0
  87. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D05.md +0 -0
  88. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D06.md +0 -0
  89. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D07.md +0 -0
  90. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D08.md +0 -0
  91. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D09.md +0 -0
  92. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D10.md +0 -0
  93. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D11.md +0 -0
  94. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D12.md +0 -0
  95. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D13.md +0 -0
  96. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D14.md +0 -0
  97. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D15.md +0 -0
  98. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D16.md +0 -0
  99. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D17.md +0 -0
  100. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D18.md +0 -0
  101. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D19.md +0 -0
  102. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D20.md +0 -0
  103. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D21.md +0 -0
  104. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D22.md +0 -0
  105. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D23.md +0 -0
  106. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D24.md +0 -0
  107. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D25.md +0 -0
  108. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/BOOST-D26.md +0 -0
  109. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
  110. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
  111. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
  112. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
  113. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
  114. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
  115. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
  116. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
  117. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
  118. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
  119. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
  120. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/command-reference-docs-site.md +0 -0
  121. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
  122. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
  123. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
  124. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
  125. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
  126. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
  127. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
  128. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
  129. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
  130. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
  131. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
  132. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
  133. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
  134. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
  135. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
  136. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
  137. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/html-validation-html-validate.md +0 -0
  138. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
  139. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
  140. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
  141. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
  142. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
  143. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
  144. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
  145. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
  146. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
  147. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
  148. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
  149. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
  150. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
  151. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
  152. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
  153. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
  154. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
  155. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
  156. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
  157. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
  158. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
  159. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
  160. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
  161. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
  162. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
  163. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
  164. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
  165. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
  166. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
  167. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
  168. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
  169. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
  170. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
  171. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
  172. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
  173. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
  174. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
  175. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
  176. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
  177. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
  178. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
  179. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
  180. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
  181. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
  182. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
  183. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
  184. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
  185. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
  186. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
  187. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
  188. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
  189. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
  190. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/typo-detection-codespell.md +0 -0
  191. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
  192. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
  193. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
  194. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/update-diff-before-apply.md +0 -0
  195. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
  196. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
  197. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
  198. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
  199. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
  200. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/docs/roadmap/items/workspace-scope-install.md +0 -0
  201. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/index.html +0 -0
  202. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/pyproject.toml +0 -0
  203. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/scripts/build_registries.py +0 -0
  204. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/scripts/build_roadmap.py +0 -0
  205. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/scripts/eval_recommend.py +0 -0
  206. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/scripts/mutation_gate.py +0 -0
  207. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/setup.cfg +0 -0
  208. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/style/README.md +0 -0
  209. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/style/boost.css +0 -0
  210. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/style/boost.js +0 -0
  211. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/style/demo.html +0 -0
  212. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/conftest.py +0 -0
  213. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/eval/golden.jsonl +0 -0
  214. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/eval/recommend.jsonl +0 -0
  215. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/functional/test_cli_bmad.py +0 -0
  216. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/functional/test_cli_configuration.py +0 -0
  217. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/functional/test_cli_discovery.py +0 -0
  218. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/functional/test_cli_hooks.py +0 -0
  219. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/functional/test_cli_info.py +0 -0
  220. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/functional/test_cli_intelligence.py +0 -0
  221. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/functional/test_cli_pkg.py +0 -0
  222. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/functional/test_cli_quality.py +0 -0
  223. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/functional/test_cli_taps.py +0 -0
  224. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/functional/test_cli_team.py +0 -0
  225. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/functional/test_everyday_loop.py +0 -0
  226. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/make_fixture.py +0 -0
  227. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/smoke.sh +0 -0
  228. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_agents.py +0 -0
  229. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_ai.py +0 -0
  230. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_catalog.py +0 -0
  231. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_claude_settings.py +0 -0
  232. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_cliparse.py +0 -0
  233. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_config.py +0 -0
  234. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_dense.py +0 -0
  235. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_dense_fallback.py +0 -0
  236. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_docs_pages_linked.py +0 -0
  237. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_embed.py +0 -0
  238. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_errors_and_cli_table.py +0 -0
  239. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_frontmatter.py +0 -0
  240. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_gitutil.py +0 -0
  241. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_injectscan.py +0 -0
  242. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_journal.py +0 -0
  243. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_lockfile.py +0 -0
  244. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_logs.py +0 -0
  245. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_mcp.py +0 -0
  246. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_mutation_hardening.py +0 -0
  247. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_nethttp.py +0 -0
  248. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_output.py +0 -0
  249. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_paths.py +0 -0
  250. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_pkg_confusions.py +0 -0
  251. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_pkg_injection.py +0 -0
  252. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_pkg_secrets.py +0 -0
  253. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_policy.py +0 -0
  254. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_rag.py +0 -0
  255. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_registries_fresh.py +0 -0
  256. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_registry.py +0 -0
  257. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_roadmap_fresh.py +0 -0
  258. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_secretscan.py +0 -0
  259. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_serve.py +0 -0
  260. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_spin.py +0 -0
  261. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_staleness.py +0 -0
  262. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_store.py +0 -0
  263. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_token_parity.py +0 -0
  264. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_typosquat.py +0 -0
  265. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_updatediff.py +0 -0
  266. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_util.py +0 -0
  267. {boost_skill_cli-1.0.121 → boost_skill_cli-1.0.123}/tests/unit/test_version.py +0 -0
@@ -227,3 +227,6 @@ _bmad-output/
227
227
 
228
228
  # mutmut mutation-testing workspace (regenerated by `mutmut run`)
229
229
  mutants/
230
+
231
+ # sandboxed boost home for the Tier 1 eval corpus (`make eval` taps here)
232
+ .eval-home/
@@ -9,18 +9,32 @@ Package name on PyPI is `boost-skill-cli`; the command is `boost`.
9
9
  Before calling any change done, run the full gate:
10
10
 
11
11
  ```bash
12
- make check # == lint test smoke mutation
12
+ make check # == lint eval test smoke mutation
13
13
  ```
14
14
 
15
- It is four gates and **all must pass**:
15
+ It is five gates and **all must pass**:
16
16
 
17
17
  | Gate | Command | Threshold |
18
18
  |------------|------------------------------------------------|-----------|
19
19
  | `lint` | `ruff check boost_cli tests` + `mypy` | zero errors |
20
+ | `eval` | `ensure_eval_corpus.sh` + `eval_retrieval.py --build -k 10 --fail-under 0.85` | BM25 recall@k **≥ 0.85** over the pinned corpus |
20
21
  | `test` | `pytest tests/unit tests/functional --cov` | **80%** coverage (`fail_under = 80`) |
21
22
  | `smoke` | `bash tests/smoke.sh` | 0 failed |
22
23
  | `mutation` | `python3 scripts/mutation_gate.py --run --min 80` | **80%** of `boost_cli/core` mutants killed |
23
24
 
25
+ The `eval` gate is the Tier 1 retrieval-quality check: it runs boost's RAG
26
+ engines over the golden set (`tests/eval/golden.jsonl`) and floors BM25
27
+ recall@k. The golden set grades real catalog items **by name**, so it needs a
28
+ corpus: `scripts/ensure_eval_corpus.sh` first taps the pinned repo list in
29
+ `tests/eval/taps.txt` (the minimal set covering all golden targets — `boost tap
30
+ --defaults` is NOT enough, it omits every rule/workflow repo). Over that corpus
31
+ BM25 recall is 1.000, so the 0.85 floor has wide margin; regression-vs-baseline
32
+ is relaxed in the gate (`--regression-eps 1`) so upstream repo drift can't flake
33
+ it. Edit `taps.txt` → regenerate `tests/eval/baseline.json`. It runs in CI's
34
+ `lint` job (pure-stdlib BM25, no `ANTHROPIC_API_KEY`; needs network to tap). The
35
+ opt-in Tier 2a/2b evals (`make eval-ai` / `eval-rec`) are key-gated and stay out
36
+ of `check`.
37
+
24
38
  New/changed core logic needs tests that both cover it *and* kill mutants —
25
39
  untested code counts as unkilled mutants, so the mutation gate fails even at 80%
26
40
  line coverage. Target `boost_cli/core` behavior with assertions, not just imports.
@@ -1,10 +1,14 @@
1
1
  # boost — test & quality gates
2
2
  # `make check` is the full production gate: unit + functional with >=80%
3
- # coverage, the shell-level smoke suite, and >=80% mutation strength.
3
+ # coverage, the shell-level smoke suite, >=80% mutation strength, and the
4
+ # Tier 1 retrieval-quality gate (golden-set recall@k).
4
5
 
5
- VENV := .venv
6
- PY := $(VENV)/bin/python
7
- PYTEST := $(VENV)/bin/pytest
6
+ VENV := .venv
7
+ PY := $(VENV)/bin/python
8
+ PYTEST := $(VENV)/bin/pytest
9
+ # Sandboxed boost home for the Tier 1 eval corpus (gitignored) — keeps the
10
+ # pinned taps out of the developer's real ~/.boost.
11
+ EVAL_HOME := $(CURDIR)/.eval-home
8
12
 
9
13
  .PHONY: venv test unit functional smoke coverage mutation lint check demo clean-test eval eval-ai eval-rec audit dist-check
10
14
 
@@ -54,10 +58,15 @@ dist-check:
54
58
  $(VENV)/bin/check-wheel-contents dist/*.whl
55
59
  $(VENV)/bin/pyroma --min 8 dist/*.tar.gz
56
60
 
57
- # Tier 1 retrieval quality gate: golden-set recall@k over the tapped catalog.
58
- # Deterministic + offline; a release-quality gate, kept separate from `check`.
61
+ # Tier 1 retrieval quality gate: golden-set recall@k over a pinned corpus
62
+ # (tests/eval/taps.txt). Part of `check` and required in CI (the lint job).
63
+ # Taps the pinned repos into a sandboxed $(EVAL_HOME) first (network on the
64
+ # first run; a sentinel skips re-tapping after), then floors BM25 recall@k at
65
+ # 0.85. Regression-vs-baseline is relaxed here (drift tolerance); the absolute
66
+ # floor is the gate.
59
67
  eval:
60
- $(PY) scripts/eval_retrieval.py --build -k 10 --fail-under 0.85
68
+ PYTHON=$(PY) BOOST_HOME=$(EVAL_HOME) bash scripts/ensure_eval_corpus.sh
69
+ BOOST_HOME=$(EVAL_HOME) $(PY) scripts/eval_retrieval.py --build -k 10 --fail-under 0.85 --regression-eps 1
61
70
 
62
71
  # Tier 2a: LLM rerank lift over BM25 on the same golden set. Opt-in and
63
72
  # key-gated — needs the `claude` CLI on PATH or ANTHROPIC_API_KEY; skips
@@ -80,7 +89,7 @@ generate:
80
89
  demo:
81
90
  vhs docs/demo.tape
82
91
 
83
- check: lint test smoke mutation
92
+ check: lint eval test smoke mutation
84
93
  @echo "== all gates passed =="
85
94
 
86
95
  clean-test:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.121
3
+ Version: 1.0.123
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.121'
22
- __version_tuple__ = version_tuple = (1, 0, 121)
21
+ __version__ = version = '1.0.123'
22
+ __version_tuple__ = version_tuple = (1, 0, 123)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -7,7 +7,6 @@ from __future__ import annotations
7
7
 
8
8
  import argparse
9
9
  import json
10
- import os
11
10
  import re
12
11
  import shutil
13
12
  import subprocess
@@ -19,15 +18,10 @@ from pathlib import Path
19
18
  from .. import cliparse, spin
20
19
  from ..core import agents, ai, catalog, dense, embed, gitutil, journal, lockfile, paths, rag, registry, store, util
21
20
  from ..core import output as out
21
+ from ..core.stackprobe import detect_stack # re-exported: shared with Quality
22
22
  from ..errors import BoostError
23
23
 
24
- _SKIP_DIRS = {".git", "node_modules", "__pycache__", ".venv", "venv",
25
- "dist", "build", "target", "vendor"}
26
-
27
- _EXT_LANGS = {".py": "python", ".ts": "typescript", ".tsx": "typescript",
28
- ".js": "javascript", ".jsx": "javascript", ".go": "go",
29
- ".rs": "rust", ".java": "java", ".rb": "ruby", ".kt": "kotlin",
30
- ".swift": "swift", ".php": "php", ".cs": "csharp"}
24
+ __all__ = ["detect_stack"]
31
25
 
32
26
 
33
27
  def _positive_int(s: str) -> int:
@@ -44,13 +38,6 @@ def _positive_int(s: str) -> int:
44
38
  _tilde = paths.tilde
45
39
 
46
40
 
47
- def _read_text(p: Path) -> str:
48
- try:
49
- return p.read_text(encoding="utf-8", errors="replace")
50
- except OSError:
51
- return ""
52
-
53
-
54
41
  def _json_array(text):
55
42
  """Best-effort extraction of the first JSON array in an AI reply."""
56
43
  m = re.search(r"\[.*\]", text or "", re.S)
@@ -67,82 +54,6 @@ def _discovery_path() -> Path:
67
54
  return paths.cache_dir() / "discovery.json"
68
55
 
69
56
 
70
- def detect_stack(path) -> dict:
71
- """Detect a project's tech stack from files on disk.
72
-
73
- Walks at most two directory levels (skipping .git/node_modules etc.) and
74
- returns {"languages": [...], "frameworks": [...], "keywords": [...]}.
75
- Shared with the Quality commands.
76
- """
77
- root = Path(path)
78
- langs, frameworks, extras = set(), set(), set()
79
- markers: dict = {}
80
- ext_counts: dict = {}
81
- for dirpath, dirnames, filenames in os.walk(str(root)):
82
- rel = os.path.relpath(dirpath, str(root))
83
- depth = 0 if rel == "." else rel.count(os.sep) + 1
84
- dirnames[:] = [] if depth >= 2 else [d for d in dirnames
85
- if d not in _SKIP_DIRS]
86
- for fn in filenames:
87
- markers.setdefault(fn.lower(), Path(dirpath) / fn)
88
- ext = os.path.splitext(fn)[1].lower()
89
- if ext:
90
- ext_counts[ext] = ext_counts.get(ext, 0) + 1
91
-
92
- def read(*names) -> str:
93
- return "\n".join(_read_text(markers[n]) for n in names
94
- if n in markers).lower()
95
-
96
- if "package.json" in markers:
97
- langs.add("javascript")
98
- try:
99
- pkg = json.loads(_read_text(markers["package.json"]))
100
- except json.JSONDecodeError:
101
- pkg = {}
102
- if not isinstance(pkg, dict):
103
- pkg = {}
104
- deps: set[str] = set()
105
- for section in ("dependencies", "devDependencies", "peerDependencies"):
106
- deps.update(pkg.get(section) or {})
107
- for dep in ("react", "vue", "next", "express"):
108
- if any(d == dep or d.startswith((dep + "/", "@" + dep + "/"))
109
- for d in deps):
110
- frameworks.add(dep)
111
- if "typescript" in deps:
112
- langs.add("typescript")
113
- if "pyproject.toml" in markers or "requirements.txt" in markers:
114
- langs.add("python")
115
- blob = read("pyproject.toml", "requirements.txt")
116
- for fw in ("django", "flask", "fastapi", "pytest"):
117
- if fw in blob:
118
- frameworks.add(fw)
119
- if "go.mod" in markers:
120
- langs.add("go")
121
- if "cargo.toml" in markers:
122
- langs.add("rust")
123
- if any(n in markers for n in ("pom.xml", "build.gradle", "build.gradle.kts")):
124
- langs.add("java")
125
- if "spring" in read("pom.xml", "build.gradle", "build.gradle.kts"):
126
- frameworks.add("spring")
127
- if "gemfile" in markers:
128
- langs.add("ruby")
129
- if "rails" in read("gemfile"):
130
- frameworks.add("rails")
131
- if "tsconfig.json" in markers:
132
- langs.add("typescript")
133
- if "dockerfile" in markers:
134
- extras.add("docker")
135
- if (root / ".github" / "workflows").is_dir():
136
- extras.add("ci")
137
- if ext_counts.get(".tf"):
138
- extras.add("terraform")
139
- for ext, n in ext_counts.items():
140
- if n >= 2 and ext in _EXT_LANGS:
141
- langs.add(_EXT_LANGS[ext])
142
- return {"languages": sorted(langs), "frameworks": sorted(frameworks),
143
- "keywords": sorted(langs | frameworks | extras)}
144
-
145
-
146
57
  def _ai_rank(query: str, scored):
147
58
  """Ask Claude to reorder the top hits. Returns a new scored list or None."""
148
59
  top = scored[:15]
@@ -327,7 +327,7 @@ def _probe_repo(root: Path) -> dict:
327
327
  def _stack_from_discovery(root: Path) -> Optional[Tuple[List[str], List[str]]]:
328
328
  """Use discovery's shared stack prober when present; normalize its shape."""
329
329
  try:
330
- from .discovery import detect_stack
330
+ from ..core.stackprobe import detect_stack
331
331
  result = detect_stack(root)
332
332
  except Exception:
333
333
  return None
@@ -185,7 +185,7 @@ def _stack_keywords(cwd: Path) -> set:
185
185
  like `testing` or `git` can match even when detect_stack is language-only)."""
186
186
  kws: List[str] = []
187
187
  try:
188
- from .discovery import detect_stack
188
+ from ..core.stackprobe import detect_stack
189
189
  stack = detect_stack(cwd)
190
190
  if isinstance(stack, dict):
191
191
  kws.extend(str(k) for k in (stack.get("keywords") or []))
@@ -0,0 +1,108 @@
1
+ """Tech-stack probing: read a project tree and name its languages/frameworks.
2
+
3
+ ``detect_stack`` used to live in ``commands/discovery.py`` even though the
4
+ Intelligence and Quality command modules both imported it — engine logic
5
+ stranded in a command module, reached across the command layer. It belongs in
6
+ ``core``: a pure, filesystem-only prober with no command dependencies, so every
7
+ consumer shares one implementation instead of a copy plus a fallback table.
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import json
12
+ import os
13
+ from pathlib import Path
14
+ from typing import Dict
15
+
16
+ # Directories that never describe the project's own stack — skip them so a
17
+ # vendored dependency can't masquerade as a first-party language.
18
+ _SKIP_DIRS = {".git", "node_modules", "__pycache__", ".venv", "venv",
19
+ "dist", "build", "target", "vendor"}
20
+
21
+ # A file extension seen ``>= 2`` times is treated as a language signal even
22
+ # without a manifest — enough to catch a script-only repo.
23
+ _EXT_LANGS = {".py": "python", ".ts": "typescript", ".tsx": "typescript",
24
+ ".js": "javascript", ".jsx": "javascript", ".go": "go",
25
+ ".rs": "rust", ".java": "java", ".rb": "ruby", ".kt": "kotlin",
26
+ ".swift": "swift", ".php": "php", ".cs": "csharp"}
27
+
28
+
29
+ def _read_text(p: Path) -> str:
30
+ try:
31
+ return p.read_text(encoding="utf-8", errors="replace")
32
+ except OSError:
33
+ return ""
34
+
35
+
36
+ def detect_stack(path) -> Dict[str, list]:
37
+ """Detect a project's tech stack from files on disk.
38
+
39
+ Walks at most two directory levels (skipping .git/node_modules etc.) and
40
+ returns ``{"languages": [...], "frameworks": [...], "keywords": [...]}``.
41
+ """
42
+ root = Path(path)
43
+ langs, frameworks, extras = set(), set(), set()
44
+ markers: dict = {}
45
+ ext_counts: dict = {}
46
+ for dirpath, dirnames, filenames in os.walk(str(root)):
47
+ rel = os.path.relpath(dirpath, str(root))
48
+ depth = 0 if rel == "." else rel.count(os.sep) + 1
49
+ dirnames[:] = [] if depth >= 2 else [d for d in dirnames
50
+ if d not in _SKIP_DIRS]
51
+ for fn in filenames:
52
+ markers.setdefault(fn.lower(), Path(dirpath) / fn)
53
+ ext = os.path.splitext(fn)[1].lower()
54
+ if ext:
55
+ ext_counts[ext] = ext_counts.get(ext, 0) + 1
56
+
57
+ def read(*names) -> str:
58
+ return "\n".join(_read_text(markers[n]) for n in names
59
+ if n in markers).lower()
60
+
61
+ if "package.json" in markers:
62
+ langs.add("javascript")
63
+ try:
64
+ pkg = json.loads(_read_text(markers["package.json"]))
65
+ except json.JSONDecodeError:
66
+ pkg = {}
67
+ if not isinstance(pkg, dict):
68
+ pkg = {}
69
+ deps: set = set()
70
+ for section in ("dependencies", "devDependencies", "peerDependencies"):
71
+ deps.update(pkg.get(section) or {})
72
+ for dep in ("react", "vue", "next", "express"):
73
+ if any(d == dep or d.startswith((dep + "/", "@" + dep + "/"))
74
+ for d in deps):
75
+ frameworks.add(dep)
76
+ if "typescript" in deps:
77
+ langs.add("typescript")
78
+ if "pyproject.toml" in markers or "requirements.txt" in markers:
79
+ langs.add("python")
80
+ blob = read("pyproject.toml", "requirements.txt")
81
+ for fw in ("django", "flask", "fastapi", "pytest"):
82
+ if fw in blob:
83
+ frameworks.add(fw)
84
+ if "go.mod" in markers:
85
+ langs.add("go")
86
+ if "cargo.toml" in markers:
87
+ langs.add("rust")
88
+ if any(n in markers for n in ("pom.xml", "build.gradle", "build.gradle.kts")):
89
+ langs.add("java")
90
+ if "spring" in read("pom.xml", "build.gradle", "build.gradle.kts"):
91
+ frameworks.add("spring")
92
+ if "gemfile" in markers:
93
+ langs.add("ruby")
94
+ if "rails" in read("gemfile"):
95
+ frameworks.add("rails")
96
+ if "tsconfig.json" in markers:
97
+ langs.add("typescript")
98
+ if "dockerfile" in markers:
99
+ extras.add("docker")
100
+ if (root / ".github" / "workflows").is_dir():
101
+ extras.add("ci")
102
+ if ext_counts.get(".tf"):
103
+ extras.add("terraform")
104
+ for ext, n in ext_counts.items():
105
+ if n >= 2 and ext in _EXT_LANGS:
106
+ langs.add(_EXT_LANGS[ext])
107
+ return {"languages": sorted(langs), "frameworks": sorted(frameworks),
108
+ "keywords": sorted(langs | frameworks | extras)}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.121
3
+ Version: 1.0.123
4
4
  Summary: boost — Homebrew for AI coding skills
5
5
  Author: Jonathan Reyes
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -52,6 +52,7 @@ boost_cli/core/rag.py
52
52
  boost_cli/core/registry.py
53
53
  boost_cli/core/secretscan.py
54
54
  boost_cli/core/serve.py
55
+ boost_cli/core/stackprobe.py
55
56
  boost_cli/core/staleness.py
56
57
  boost_cli/core/store.py
57
58
  boost_cli/core/typosquat.py
@@ -194,6 +195,7 @@ docs/roadmap/items/workflow-sast-zizmor.md
194
195
  docs/roadmap/items/workspace-scope-install.md
195
196
  scripts/build_registries.py
196
197
  scripts/build_roadmap.py
198
+ scripts/ensure_eval_corpus.sh
197
199
  scripts/eval_recommend.py
198
200
  scripts/eval_retrieval.py
199
201
  scripts/mutation_gate.py
@@ -207,6 +209,7 @@ tests/smoke.sh
207
209
  tests/eval/baseline.json
208
210
  tests/eval/golden.jsonl
209
211
  tests/eval/recommend.jsonl
212
+ tests/eval/taps.txt
210
213
  tests/functional/test_cli_bmad.py
211
214
  tests/functional/test_cli_configuration.py
212
215
  tests/functional/test_cli_discovery.py
@@ -251,6 +254,7 @@ tests/unit/test_roadmap_fresh.py
251
254
  tests/unit/test_secretscan.py
252
255
  tests/unit/test_serve.py
253
256
  tests/unit/test_spin.py
257
+ tests/unit/test_stackprobe.py
254
258
  tests/unit/test_staleness.py
255
259
  tests/unit/test_store.py
256
260
  tests/unit/test_token_parity.py
@@ -0,0 +1,27 @@
1
+ ---
2
+ id: single-tech-stack-prober
3
+ board: code
4
+ section: internals
5
+ status: shipped
6
+ category: Tech-debt
7
+ complexity: M
8
+ impact: Med
9
+ wow: 2
10
+ note: prober moved to core
11
+ order: 13
12
+ owner: loop/core-stack-prober
13
+ pr: 140
14
+ title: Single tech-stack prober
15
+ ---
16
+ Shipped in <b>#140</b>. The canonical <code>detect_stack</code> prober — a
17
+ ~75-line pure function that lived in the <b>command</b> module
18
+ <code>commands/discovery.py</code> yet was imported across the command layer by
19
+ both <code>intelligence</code> and <code>quality</code> — now lives in one place:
20
+ a new pure core module <code>core/stackprobe.py</code> (with its private
21
+ <code>_SKIP_DIRS</code>/<code>_EXT_LANGS</code>/<code>_read_text</code> helpers,
22
+ used nowhere else). Every consumer imports the single core prober;
23
+ <code>discovery</code> re-exports it for compatibility, and the now-dead helpers
24
+ + unused <code>os</code> import were removed from it. Covered by 16 new
25
+ mutation-gated unit tests. The consumer-local enrichment fallbacks
26
+ (<code>_local_stack</code>, <code>_STACK_MARKERS</code>) are intentionally kept —
27
+ they add coarse filesystem signal the language-only prober doesn't.
@@ -603,13 +603,25 @@ message, so routing it through the helper would change user-facing errors.</p>
603
603
  </article>
604
604
 
605
605
  <article class="cap rcard">
606
- <div class="head"><span class="pill planned">Planned</span><span class="cat">Tech-debt</span></div>
606
+ <div class="head"><span class="pill shipped">Shipped</span><span class="cat">Tech-debt</span></div>
607
607
  <h3>Single tech-stack prober</h3>
608
- <p>Stack detection exists three times — <code>discovery.detect_stack</code>, <code>intelligence._local_stack</code>, <code>quality._STACK_MARKERS</code> (<code>discovery.py:74 · intelligence.py:359 · quality.py:55</code>) — and two already <code>import detect_stack</code> yet still carry a parallel marker table "as a fallback". Consolidate into one core prober.</p>
608
+ <p>Shipped in <b>#140</b>. The canonical <code>detect_stack</code> prober a
609
+ ~75-line pure function that lived in the <b>command</b> module
610
+ <code>commands/discovery.py</code> yet was imported across the command layer by
611
+ both <code>intelligence</code> and <code>quality</code> — now lives in one place:
612
+ a new pure core module <code>core/stackprobe.py</code> (with its private
613
+ <code>_SKIP_DIRS</code>/<code>_EXT_LANGS</code>/<code>_read_text</code> helpers,
614
+ used nowhere else). Every consumer imports the single core prober;
615
+ <code>discovery</code> re-exports it for compatibility, and the now-dead helpers
616
+ + unused <code>os</code> import were removed from it. Covered by 16 new
617
+ mutation-gated unit tests. The consumer-local enrichment fallbacks
618
+ (<code>_local_stack</code>, <code>_STACK_MARKERS</code>) are intentionally kept —
619
+ they add coarse filesystem signal the language-only prober doesn't.</p>
609
620
  <div class="meta">
610
621
  <span class="m">Complexity <b>M</b></span>
611
622
  <span class="m">Impact <b>Med</b></span>
612
623
  <span class="m">Wow <b class="wow">★★</b></span>
624
+ <span class="m">prober moved to core</span>
613
625
  </div>
614
626
  </article>
615
627
 
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env bash
2
+ # Tap the pinned Tier 1 eval corpus (tests/eval/taps.txt) into $BOOST_HOME so
3
+ # scripts/eval_retrieval.py has the repos its golden set grades against. Used by
4
+ # CI's lint job and by `make eval`.
5
+ #
6
+ # Idempotent: a sentinel skips re-tapping so a local `make check` stays fast (and
7
+ # offline) after the first run. CI runs on a fresh $HOME and always taps. Set
8
+ # FORCE=1 to re-tap. Honors $PYTHON (defaults to python3) so make can pass its
9
+ # venv interpreter.
10
+ set -euo pipefail
11
+
12
+ root=$(cd "$(dirname "$0")/.." && pwd)
13
+ py="${PYTHON:-python3}"
14
+ home="${BOOST_HOME:-$HOME/.boost}"
15
+ sentinel="$home/.eval-corpus-ready"
16
+
17
+ if [ -z "${FORCE:-}" ] && [ -f "$sentinel" ]; then
18
+ echo "eval corpus already tapped ($sentinel) — skipping (FORCE=1 to re-tap)"
19
+ exit 0
20
+ fi
21
+
22
+ while IFS= read -r repo || [ -n "$repo" ]; do
23
+ case "$repo" in ''|\#*) continue ;; esac
24
+ echo "tap $repo"
25
+ PYTHONPATH="$root" "$py" -m boost_cli tap "$repo"
26
+ done < "$root/tests/eval/taps.txt"
27
+
28
+ mkdir -p "$home"
29
+ : > "$sentinel"
@@ -1,8 +1,11 @@
1
1
  #!/usr/bin/env python3
2
2
  """Golden-set retrieval eval for boost's RAG engines.
3
3
 
4
- Tier 1 (deterministic, offline): grades the always-on retrieval stack against a
5
- fixed set of query -> expected-skill judgments. It is the semantic-quality gate
4
+ Tier 1 (deterministic given a pinned corpus): grades the always-on retrieval
5
+ stack against a fixed set of query -> expected-skill judgments. The judgments
6
+ name real catalog items, so the corpus must contain them — CI and `make eval`
7
+ first tap the pinned repo list (tests/eval/taps.txt) via
8
+ scripts/ensure_eval_corpus.sh. It is the semantic-quality gate
6
9
  the exact-arithmetic unit tests in tests/unit/test_rag.py cannot be — those pin
7
10
  the math, this asks "does the right skill actually come back for a real question."
8
11
 
@@ -0,0 +1,17 @@
1
+ {
2
+ "k": 10,
3
+ "engines": {
4
+ "catalog.search": {
5
+ "recall@k": 0.9651162790697675,
6
+ "hit@1": 0.7906976744186046,
7
+ "MRR": 0.8565715292459479,
8
+ "nDCG@k": 0.8753239696644998
9
+ },
10
+ "BM25 full-content": {
11
+ "recall@k": 1.0,
12
+ "hit@1": 0.8604651162790697,
13
+ "MRR": 0.9186046511627907,
14
+ "nDCG@k": 0.9390680511952059
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,23 @@
1
+ # Pinned corpus for the Tier 1 retrieval-quality gate (scripts/eval_retrieval.py).
2
+ #
3
+ # The golden set (golden.jsonl) grades real catalog items by NAME, so the gate
4
+ # needs the repos that actually contain those items tapped before it can score.
5
+ # This is the minimal set of repos that covers all 44 golden targets across the
6
+ # skill / rule / workflow kinds. Over it, BM25 recall@10 == 1.000, so the 0.85
7
+ # floor gate has a wide margin and tolerates upstream drift.
8
+ #
9
+ # NOTE: `boost tap --defaults` is NOT sufficient — it taps only skill repos and
10
+ # scores 0.000 on every rule and workflow query (overall recall ~0.33). That is
11
+ # why this explicit list exists.
12
+ #
13
+ # If you edit this list, regenerate the baseline:
14
+ # BOOST_HOME=/tmp/evalhome bash scripts/ensure_eval_corpus.sh
15
+ # BOOST_HOME=/tmp/evalhome python3 scripts/eval_retrieval.py --build --save-baseline
16
+ #
17
+ # Future hardening: pin each repo to a commit SHA for full reproducibility.
18
+ anthropics/skills
19
+ 0xfurai/claude-code-subagents
20
+ NeoLabHQ/context-engineering-kit
21
+ Aaronontheweb/dotnet-cursor-rules
22
+ ChrisWiles/claude-code-showcase
23
+ LessUp/awesome-cursorrules-zh