boost-skill-cli 1.0.147__tar.gz → 1.0.149__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 (315) hide show
  1. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/Makefile +19 -1
  2. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/PKG-INFO +5 -1
  3. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/_version.py +2 -2
  4. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/commands/pkg.py +14 -5
  5. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/rules.py +19 -9
  6. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/store.py +47 -13
  7. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/workflows.py +11 -5
  8. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_skill_cli.egg-info/PKG-INFO +5 -1
  9. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_skill_cli.egg-info/SOURCES.txt +19 -0
  10. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_skill_cli.egg-info/requires.txt +6 -0
  11. boost_skill_cli-1.0.149/docs/roadmap/items/install-scope-user-or-project.md +27 -0
  12. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap.html +24 -1
  13. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/pyproject.toml +10 -0
  14. boost_skill_cli-1.0.149/scripts/bench_cli.sh +27 -0
  15. boost_skill_cli-1.0.149/tests/bdd/features/adapt.feature +46 -0
  16. boost_skill_cli-1.0.149/tests/bdd/features/browse.feature +26 -0
  17. boost_skill_cli-1.0.149/tests/bdd/features/count.feature +24 -0
  18. boost_skill_cli-1.0.149/tests/bdd/features/discover.feature +39 -0
  19. boost_skill_cli-1.0.149/tests/bdd/features/doctor.feature +30 -0
  20. boost_skill_cli-1.0.149/tests/bdd/features/environment.py +66 -0
  21. boost_skill_cli-1.0.149/tests/bdd/features/explain.feature +25 -0
  22. boost_skill_cli-1.0.149/tests/bdd/features/index.feature +25 -0
  23. boost_skill_cli-1.0.149/tests/bdd/features/install.feature +43 -0
  24. boost_skill_cli-1.0.149/tests/bdd/features/list.feature +42 -0
  25. boost_skill_cli-1.0.149/tests/bdd/features/mcp.feature +31 -0
  26. boost_skill_cli-1.0.149/tests/bdd/features/search.feature +37 -0
  27. boost_skill_cli-1.0.149/tests/bdd/features/steps/cli_steps.py +104 -0
  28. boost_skill_cli-1.0.149/tests/bdd/features/steps/discovery_steps.py +77 -0
  29. boost_skill_cli-1.0.149/tests/bdd/features/steps/mcp_steps.py +48 -0
  30. boost_skill_cli-1.0.149/tests/bdd/features/steps/quality_steps.py +12 -0
  31. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/functional/test_cli_pkg.py +16 -0
  32. boost_skill_cli-1.0.149/tests/perf/test_benchmarks.py +59 -0
  33. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_rules.py +18 -0
  34. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_store.py +48 -0
  35. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_workflows.py +10 -0
  36. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/.gitattributes +0 -0
  37. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/.gitignore +0 -0
  38. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/CLAUDE.md +0 -0
  39. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/CONTRIBUTING.md +0 -0
  40. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/LICENSE +0 -0
  41. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/MANIFEST.in +0 -0
  42. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/README.md +0 -0
  43. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/SECURITY.md +0 -0
  44. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost +0 -0
  45. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/__init__.py +0 -0
  46. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/__main__.py +0 -0
  47. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/cli.py +0 -0
  48. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/cliparse.py +0 -0
  49. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/commands/__init__.py +0 -0
  50. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/commands/bmad.py +0 -0
  51. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/commands/configuration.py +0 -0
  52. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/commands/discovery.py +0 -0
  53. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/commands/hooks.py +0 -0
  54. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/commands/info.py +0 -0
  55. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/commands/intelligence.py +0 -0
  56. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/commands/quality.py +0 -0
  57. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/commands/taps.py +0 -0
  58. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/commands/team.py +0 -0
  59. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/__init__.py +0 -0
  60. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/adapters.py +0 -0
  61. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/agents.py +0 -0
  62. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/ai.py +0 -0
  63. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/catalog.py +0 -0
  64. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/claude_settings.py +0 -0
  65. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/config.py +0 -0
  66. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/dense.py +0 -0
  67. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/embed.py +0 -0
  68. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/frontmatter.py +0 -0
  69. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/gitutil.py +0 -0
  70. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/imperative.py +0 -0
  71. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/injectscan.py +0 -0
  72. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/journal.py +0 -0
  73. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/lockfile.py +0 -0
  74. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/logs.py +0 -0
  75. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/mcp.py +0 -0
  76. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/nethttp.py +0 -0
  77. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/output.py +0 -0
  78. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/paths.py +0 -0
  79. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/policy.py +0 -0
  80. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/rag.py +0 -0
  81. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/registry.py +0 -0
  82. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/secretscan.py +0 -0
  83. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/serve.py +0 -0
  84. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/stackprobe.py +0 -0
  85. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/staleness.py +0 -0
  86. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/typosquat.py +0 -0
  87. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/updatediff.py +0 -0
  88. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/core/util.py +0 -0
  89. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/data/registries.json +0 -0
  90. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/errors.py +0 -0
  91. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_cli/spin.py +0 -0
  92. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
  93. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_skill_cli.egg-info/entry_points.txt +0 -0
  94. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/boost_skill_cli.egg-info/top_level.txt +0 -0
  95. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/.claude/settings.local.json +0 -0
  96. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/DEBUGGING.md +0 -0
  97. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/adapters.html +0 -0
  98. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/demo.gif +0 -0
  99. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/demo.tape +0 -0
  100. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/design-roadmap.html +0 -0
  101. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/eval.html +0 -0
  102. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/index.html +0 -0
  103. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/mcp-hub.html +0 -0
  104. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/rag-architecture.md +0 -0
  105. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D01.md +0 -0
  106. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D02.md +0 -0
  107. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D03.md +0 -0
  108. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D04.md +0 -0
  109. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D05.md +0 -0
  110. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D06.md +0 -0
  111. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D07.md +0 -0
  112. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D08.md +0 -0
  113. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D09.md +0 -0
  114. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D10.md +0 -0
  115. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D11.md +0 -0
  116. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D12.md +0 -0
  117. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D13.md +0 -0
  118. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D14.md +0 -0
  119. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D15.md +0 -0
  120. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D16.md +0 -0
  121. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D17.md +0 -0
  122. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D18.md +0 -0
  123. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D19.md +0 -0
  124. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D20.md +0 -0
  125. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D21.md +0 -0
  126. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D22.md +0 -0
  127. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D23.md +0 -0
  128. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D24.md +0 -0
  129. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D25.md +0 -0
  130. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/BOOST-D26.md +0 -0
  131. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
  132. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
  133. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
  134. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
  135. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/boost-run-live-agents.md +0 -0
  136. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
  137. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
  138. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
  139. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
  140. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
  141. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
  142. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
  143. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/command-reference-docs-site.md +0 -0
  144. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
  145. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
  146. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
  147. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
  148. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
  149. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
  150. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
  151. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
  152. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
  153. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
  154. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
  155. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
  156. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
  157. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
  158. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
  159. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/framework-adapter-multi-agent.md +0 -0
  160. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
  161. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
  162. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
  163. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
  164. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
  165. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/html-validation-html-validate.md +0 -0
  166. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
  167. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
  168. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
  169. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
  170. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
  171. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
  172. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
  173. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
  174. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
  175. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
  176. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
  177. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
  178. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
  179. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
  180. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
  181. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
  182. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
  183. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
  184. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
  185. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
  186. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
  187. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
  188. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
  189. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
  190. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
  191. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
  192. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
  193. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
  194. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
  195. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
  196. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
  197. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
  198. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
  199. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
  200. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
  201. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
  202. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
  203. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
  204. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
  205. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
  206. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
  207. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
  208. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
  209. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
  210. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
  211. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
  212. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
  213. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
  214. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
  215. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
  216. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
  217. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
  218. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
  219. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
  220. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
  221. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
  222. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
  223. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
  224. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
  225. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/typo-detection-codespell.md +0 -0
  226. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
  227. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
  228. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
  229. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/update-diff-before-apply.md +0 -0
  230. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
  231. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
  232. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
  233. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
  234. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
  235. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
  236. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
  237. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/docs/roadmap/items/workspace-scope-install.md +0 -0
  238. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/examples/README.md +0 -0
  239. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/examples/adapt-demo.sh +0 -0
  240. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/examples/boost-run-prototype.sh +0 -0
  241. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/index.html +0 -0
  242. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/scripts/build_registries.py +0 -0
  243. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/scripts/build_roadmap.py +0 -0
  244. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/scripts/ensure_eval_corpus.sh +0 -0
  245. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/scripts/eval_explain.py +0 -0
  246. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/scripts/eval_recommend.py +0 -0
  247. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/scripts/eval_retrieval.py +0 -0
  248. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/scripts/mutation_gate.py +0 -0
  249. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/setup.cfg +0 -0
  250. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/style/README.md +0 -0
  251. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/style/boost.css +0 -0
  252. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/style/boost.js +0 -0
  253. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/style/demo.html +0 -0
  254. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/conftest.py +0 -0
  255. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/eval/baseline.json +0 -0
  256. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/eval/explain.jsonl +0 -0
  257. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/eval/golden.jsonl +0 -0
  258. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/eval/recommend.jsonl +0 -0
  259. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/eval/taps.txt +0 -0
  260. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/functional/test_cli_adapt.py +0 -0
  261. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/functional/test_cli_bmad.py +0 -0
  262. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/functional/test_cli_configuration.py +0 -0
  263. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/functional/test_cli_discovery.py +0 -0
  264. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/functional/test_cli_hooks.py +0 -0
  265. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/functional/test_cli_info.py +0 -0
  266. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/functional/test_cli_intelligence.py +0 -0
  267. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/functional/test_cli_quality.py +0 -0
  268. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/functional/test_cli_taps.py +0 -0
  269. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/functional/test_cli_team.py +0 -0
  270. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/functional/test_everyday_loop.py +0 -0
  271. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/functional/test_property_parsers.py +0 -0
  272. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/make_fixture.py +0 -0
  273. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/smoke.sh +0 -0
  274. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_adapters.py +0 -0
  275. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_agents.py +0 -0
  276. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_ai.py +0 -0
  277. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_catalog.py +0 -0
  278. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_claude_settings.py +0 -0
  279. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_cliparse.py +0 -0
  280. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_config.py +0 -0
  281. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_dense.py +0 -0
  282. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_dense_fallback.py +0 -0
  283. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_docs_pages_linked.py +0 -0
  284. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_embed.py +0 -0
  285. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_errors_and_cli_table.py +0 -0
  286. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_frontmatter.py +0 -0
  287. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_gitutil.py +0 -0
  288. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_imperative.py +0 -0
  289. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_injectscan.py +0 -0
  290. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_journal.py +0 -0
  291. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_lockfile.py +0 -0
  292. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_logs.py +0 -0
  293. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_mcp.py +0 -0
  294. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_mutation_hardening.py +0 -0
  295. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_nethttp.py +0 -0
  296. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_output.py +0 -0
  297. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_paths.py +0 -0
  298. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_pkg_confusions.py +0 -0
  299. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_pkg_injection.py +0 -0
  300. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_pkg_secrets.py +0 -0
  301. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_policy.py +0 -0
  302. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_rag.py +0 -0
  303. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_registries_fresh.py +0 -0
  304. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_registry.py +0 -0
  305. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_roadmap_fresh.py +0 -0
  306. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_secretscan.py +0 -0
  307. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_serve.py +0 -0
  308. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_spin.py +0 -0
  309. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_stackprobe.py +0 -0
  310. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_staleness.py +0 -0
  311. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_token_parity.py +0 -0
  312. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_typosquat.py +0 -0
  313. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_updatediff.py +0 -0
  314. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_util.py +0 -0
  315. {boost_skill_cli-1.0.147 → boost_skill_cli-1.0.149}/tests/unit/test_version.py +0 -0
@@ -10,7 +10,7 @@ PYTEST := $(VENV)/bin/pytest
10
10
  # pinned taps out of the developer's real ~/.boost.
11
11
  EVAL_HOME := $(CURDIR)/.eval-home
12
12
 
13
- .PHONY: venv test unit functional smoke coverage mutation lint check demo clean-test eval eval-ai eval-rec eval-stats eval-explain audit dist-check
13
+ .PHONY: venv test unit functional smoke coverage mutation lint check demo clean-test eval eval-ai eval-rec eval-stats eval-explain audit dist-check bdd bench bench-cli
14
14
 
15
15
  venv:
16
16
  python3 -m venv $(VENV)
@@ -96,6 +96,24 @@ eval-explain:
96
96
  PYTHON=$(PY) BOOST_HOME=$(EVAL_HOME) bash scripts/ensure_eval_corpus.sh
97
97
  BOOST_HOME=$(EVAL_HOME) $(PY) scripts/eval_explain.py --fail-under 0.80
98
98
 
99
+ # Opt-in Gherkin/BDD suite (tests/bdd) — additive to tests/functional, not a
100
+ # replacement. Needs the [bdd] extra (`pip install -e '.[bdd]'`); not part of
101
+ # `make check`.
102
+ bdd:
103
+ $(VENV)/bin/behave tests/bdd/features
104
+
105
+ # Opt-in micro-benchmarks (tests/perf) for perf-sensitive core paths. Needs
106
+ # the [perf] extra (`pip install -e '.[perf]'`); not part of `make check` — a
107
+ # timing regression is informational, not a merge gate.
108
+ bench:
109
+ $(PYTEST) tests/perf --benchmark-only -q
110
+
111
+ # Opt-in wall-clock benchmark of the real `boost` binary via hyperfine. Not
112
+ # part of `make check`; degrades cleanly (prints a skip message, exits 0) when
113
+ # hyperfine isn't installed (`brew install hyperfine`).
114
+ bench-cli:
115
+ @command -v hyperfine >/dev/null 2>&1 && bash scripts/bench_cli.sh || echo "hyperfine not on PATH — install via 'brew install hyperfine', skipping"
116
+
99
117
  # regenerate generated artifacts from their source (registries + roadmap boards)
100
118
  generate:
101
119
  $(PY) scripts/build_registries.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.147
3
+ Version: 1.0.149
4
4
  Summary: boost — Homebrew for AI coding skills
5
5
  Author: Jonathan Reyes
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -708,6 +708,10 @@ Requires-Dist: ragas<0.3,>=0.2; extra == "eval"
708
708
  Requires-Dist: langchain-core<0.4; extra == "eval"
709
709
  Requires-Dist: langchain-community<0.4; extra == "eval"
710
710
  Requires-Dist: langchain-openai<1; extra == "eval"
711
+ Provides-Extra: bdd
712
+ Requires-Dist: behave>=1.2.6; extra == "bdd"
713
+ Provides-Extra: perf
714
+ Requires-Dist: pytest-benchmark>=4.0; extra == "perf"
711
715
  Dynamic: license-file
712
716
 
713
717
  # boost — a package manager for AI coding skills
@@ -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.147'
22
- __version_tuple__ = version_tuple = (1, 0, 147)
21
+ __version__ = version = '1.0.149'
22
+ __version_tuple__ = version_tuple = (1, 0, 149)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -118,7 +118,9 @@ def _warn_secrets(res: store.InstallResult) -> None:
118
118
  def _report_result(res: store.InstallResult) -> None:
119
119
  """The canonical three-line install report."""
120
120
  if res.kind in ("rule", "workflow"):
121
- out.ok("materialized %s" % (" · ".join(res.linked) or "(no enabled agents)"))
121
+ where = " (this repo)" if res.scope == "project" else ""
122
+ out.ok("materialized%s → %s"
123
+ % (where, " · ".join(res.linked) or "(no enabled agents)"))
122
124
  out.ok("lock updated (.skill-lock.json)")
123
125
  _warn_injection(res)
124
126
  _warn_secrets(res)
@@ -166,6 +168,9 @@ def cmd_install(argv: List[str]) -> int:
166
168
  help="reinstall even if already installed or pinned")
167
169
  ap.add_argument("--agent", action="append", metavar="A",
168
170
  help="link only into this agent (repeatable)")
171
+ ap.add_argument("--scope", choices=("user", "project"), default="user",
172
+ help="rules/workflows: install into your user config (default) "
173
+ "or the current repo (project)")
169
174
  ap.add_argument("--dry-run", action="store_true",
170
175
  help="show what would happen without changing anything")
171
176
  args = ap.parse_args(argv)
@@ -191,8 +196,10 @@ def cmd_install(argv: List[str]) -> int:
191
196
  seen = (lockfile.get_rule if k == "rule"
192
197
  else lockfile.get_workflow)(e["name"])
193
198
  verb = "reinstall" if seen else "install"
194
- out.info("would %s %s %s v%s from %s" % (verb, k, e["name"],
195
- e["version"], e["tap"]))
199
+ where = "into this repo" if args.scope == "project" else "user config"
200
+ out.info("would %s %s %s v%s from %s (%s)" % (verb, k, e["name"],
201
+ e["version"], e["tap"],
202
+ where))
196
203
  out.info(" materialize → %s" % (" · ".join(targets)
197
204
  or "(no enabled agents)"))
198
205
  continue
@@ -210,7 +217,7 @@ def cmd_install(argv: List[str]) -> int:
210
217
  if multi:
211
218
  out.heading("%s v%s (%s)" % (e["name"], e["version"], e["tap"]))
212
219
  try:
213
- res = store.install(e, force=args.force, only_agents=only)
220
+ res = store.install(e, force=args.force, only_agents=only, scope=args.scope)
214
221
  except BoostError as err:
215
222
  if not multi:
216
223
  raise
@@ -414,7 +421,9 @@ def _update_materialized(kind: str, installed: Dict[str, dict], results) -> int:
414
421
  if not changed:
415
422
  continue
416
423
  try:
417
- store.install(entry, force=True)
424
+ # keep the item where it was installed (user vs a specific repo).
425
+ store.install(entry, force=True,
426
+ scope=lk.get("scope", "user"), base=lk.get("base"))
418
427
  except BoostError as err:
419
428
  out.warn("%s: %s" % (name, err.message))
420
429
  continue
@@ -15,7 +15,7 @@ the filesystem writes and the lock record so uninstall can reverse them.
15
15
  from __future__ import annotations
16
16
 
17
17
  from pathlib import Path
18
- from typing import Tuple
18
+ from typing import Optional, Tuple
19
19
 
20
20
  # Name-scoped managed-block markers for CLAUDE.md. Stable + per-rule so install
21
21
  # is idempotent (a re-install replaces the block) and uninstall strips exactly
@@ -40,17 +40,27 @@ def markers(name: str) -> Tuple[str, str]:
40
40
  return BLOCK_START % name, BLOCK_END % name
41
41
 
42
42
 
43
- def rule_target(agent: str, skills_dir: Path, name: str) -> Tuple[str, Path]:
44
- """Where rule ``name`` materializes for ``agent``, given its skills dir.
43
+ def rule_target(agent: str, skills_dir: Path, name: str,
44
+ base: "Optional[Path]" = None) -> Tuple[str, Path]:
45
+ """Where rule ``name`` materializes for ``agent``.
45
46
 
46
- Returns ``(mode, path)``: ``MODE_CLAUDE`` writes/merges the CLAUDE.md at the
47
- agent root; ``MODE_FILE`` drops a file into the agent's ``rules/`` dir. The
48
- agent root is the parent of its configured skills dir (``~/.cursor/skills``
49
- -> ``~/.cursor``), so no extra config is needed.
47
+ Returns ``(mode, path)``: ``MODE_CLAUDE`` writes/merges a CLAUDE.md;
48
+ ``MODE_FILE`` drops a file into the agent's ``rules/`` dir.
49
+
50
+ ``base`` selects the scope:
51
+ * ``None`` (user scope) — the agent's user config: the parent of its
52
+ configured skills dir (``~/.cursor/skills`` -> ``~/.cursor``), and
53
+ ``~/.claude/CLAUDE.md`` for Claude.
54
+ * a directory (project scope) — that repo: ``<base>/.cursor/rules/…`` and,
55
+ since Claude reads per-repo memory from the root, ``<base>/CLAUDE.local.md``
56
+ (the personal, git-ignored file) for Claude.
50
57
  """
51
- root = Path(skills_dir).parent
58
+ dotdir = Path(skills_dir).parent.name # ".claude" / ".cursor" / …
52
59
  if agent in CLAUDE_MD_AGENTS:
53
- return MODE_CLAUDE, root / "CLAUDE.md"
60
+ if base is not None:
61
+ return MODE_CLAUDE, Path(base) / "CLAUDE.local.md"
62
+ return MODE_CLAUDE, Path(skills_dir).parent / "CLAUDE.md"
63
+ root = (Path(base) / dotdir) if base is not None else Path(skills_dir).parent
54
64
  ext = RULE_DIR_EXT.get(agent, DEFAULT_RULE_EXT)
55
65
  return MODE_FILE, root / "rules" / (name + ext)
56
66
 
@@ -26,6 +26,7 @@ class InstallResult:
26
26
  score: int = 0
27
27
  upgraded: bool = False
28
28
  kind: str = "skill"
29
+ scope: str = "user" # "user" or "project" — where a rule/workflow landed
29
30
  # For rules/workflows the installed content is a single file (or a merged
30
31
  # CLAUDE.md block), not a SKILL.md tree — carry the raw source so the caller
31
32
  # scans exactly what it installed instead of a non-existent SKILL.md.
@@ -117,14 +118,32 @@ def _copy_skill(src: Path, dest: Path) -> None:
117
118
  shutil.rmtree(backup, ignore_errors=True)
118
119
 
119
120
 
121
+ def _resolve_base(scope: str, base) -> Optional[Path]:
122
+ """Directory a project-scoped install materializes under (the repo), or None
123
+ for user scope. An explicit ``base`` (e.g. from a lock record on update/sync)
124
+ wins so a re-materialization lands where the original install did, not in
125
+ whatever the current working directory happens to be."""
126
+ if base:
127
+ return Path(base)
128
+ return Path.cwd() if scope == "project" else None
129
+
130
+
120
131
  def install(entry: dict, force: bool = False,
121
- only_agents: Optional[List[str]] = None) -> InstallResult:
122
- """Install a catalog entry. Raises BoostError on policy block or conflict."""
132
+ only_agents: Optional[List[str]] = None,
133
+ scope: str = "user", base=None) -> InstallResult:
134
+ """Install a catalog entry. Raises BoostError on policy block or conflict.
135
+
136
+ ``scope`` is ``"user"`` (default — the agent's user config dirs) or
137
+ ``"project"`` (the current repo). Skills ignore scope (they always live in
138
+ the canonical store); rules/workflows honor it.
139
+ """
123
140
  kind = entry.get("kind", "skill")
124
141
  if kind == "rule":
125
- return _install_rule(entry, force=force, only_agents=only_agents)
142
+ return _install_rule(entry, force=force, only_agents=only_agents,
143
+ scope=scope, base=base)
126
144
  if kind == "workflow":
127
- return _install_workflow(entry, force=force, only_agents=only_agents)
145
+ return _install_workflow(entry, force=force, only_agents=only_agents,
146
+ scope=scope, base=base)
128
147
  if kind != "skill":
129
148
  raise BoostError(
130
149
  "%s is a %s, which boost does not know how to install" % (entry["name"], kind),
@@ -172,14 +191,16 @@ def install(entry: dict, force: bool = False,
172
191
 
173
192
 
174
193
  def _install_rule(entry: dict, force: bool = False,
175
- only_agents: Optional[List[str]] = None) -> InstallResult:
194
+ only_agents: Optional[List[str]] = None,
195
+ scope: str = "user", base=None) -> InstallResult:
176
196
  """Materialize a rule into each enabled agent's native format.
177
197
 
178
198
  Cursor/Windsurf/Cline get a verbatim file drop in their ``rules/`` dir
179
199
  (frontmatter preserved — it is native rule metadata); Claude Code has no
180
200
  rules folder, so the rule merges into ``CLAUDE.md`` as an idempotent managed
181
- block. Every materialization is recorded so ``uninstall`` reverses exactly
182
- what was written.
201
+ block. With ``scope="project"`` these land under the repo (and Claude uses
202
+ ``CLAUDE.local.md``). Every materialization is recorded so ``uninstall``
203
+ reverses exactly what was written.
183
204
  """
184
205
  import hashlib
185
206
 
@@ -204,13 +225,14 @@ def _install_rule(entry: dict, force: bool = False,
204
225
  meta, body = frontmatter.parse(raw)
205
226
  claude_body = rules.render_claude_body(str(meta.get("name") or name), body)
206
227
 
228
+ resolved_base = _resolve_base(scope, base)
207
229
  paths.ensure_dirs()
208
230
  materializations: List[dict] = []
209
231
  linked: List[str] = []
210
232
  for agent, skills_dir in agents.enabled_agents().items():
211
233
  if only_agents and agent not in only_agents:
212
234
  continue
213
- mode, path = rules.rule_target(agent, skills_dir, name)
235
+ mode, path = rules.rule_target(agent, skills_dir, name, base=resolved_base)
214
236
  path.parent.mkdir(parents=True, exist_ok=True)
215
237
  if mode == rules.MODE_CLAUDE:
216
238
  current = path.read_text(encoding="utf-8") if path.exists() else ""
@@ -228,6 +250,8 @@ def _install_rule(entry: dict, force: bool = False,
228
250
  "source_file": entry.get("skill_md", ""),
229
251
  "commit": gitutil.head_commit(tap.path),
230
252
  "sha256": hashlib.sha256(raw.encode("utf-8")).hexdigest(),
253
+ "scope": scope,
254
+ "base": str(resolved_base) if resolved_base is not None else None,
231
255
  "installed_at": (existing or {}).get("installed_at", now),
232
256
  "updated_at": now,
233
257
  "materializations": materializations,
@@ -240,6 +264,7 @@ def _install_rule(entry: dict, force: bool = False,
240
264
  kind="rule", scan_text=raw)
241
265
  res.linked = linked
242
266
  res.upgraded = existing is not None
267
+ res.scope = scope
243
268
  return res
244
269
 
245
270
 
@@ -266,12 +291,14 @@ def _uninstall_rule(name: str, rule: dict) -> dict:
266
291
 
267
292
 
268
293
  def _install_workflow(entry: dict, force: bool = False,
269
- only_agents: Optional[List[str]] = None) -> InstallResult:
294
+ only_agents: Optional[List[str]] = None,
295
+ scope: str = "user", base=None) -> InstallResult:
270
296
  """Materialize a workflow (slash command / subagent) into each enabled agent.
271
297
 
272
298
  A verbatim Markdown drop into the agent's ``commands/`` or ``agents/`` dir —
273
- the slot derived from the source path — with no transformation. Every drop is
274
- recorded so ``uninstall`` removes exactly the files it wrote.
299
+ the slot derived from the source path — with no transformation. With
300
+ ``scope="project"`` the drop lands under the repo (``<repo>/.claude/…``).
301
+ Every drop is recorded so ``uninstall`` removes exactly the files it wrote.
275
302
  """
276
303
  import hashlib
277
304
 
@@ -296,13 +323,14 @@ def _install_workflow(entry: dict, force: bool = False,
296
323
  raw = src.read_text(encoding="utf-8", errors="replace")
297
324
  slot = workflows.detect_slot(source_rel)
298
325
 
326
+ resolved_base = _resolve_base(scope, base)
299
327
  paths.ensure_dirs()
300
328
  materializations: List[dict] = []
301
329
  linked: List[str] = []
302
330
  for agent, skills_dir in agents.enabled_agents().items():
303
331
  if only_agents and agent not in only_agents:
304
332
  continue
305
- path = workflows.workflow_target(skills_dir, slot, name)
333
+ path = workflows.workflow_target(skills_dir, slot, name, base=resolved_base)
306
334
  path.parent.mkdir(parents=True, exist_ok=True)
307
335
  util.atomic_write_text(path, raw)
308
336
  materializations.append({"agent": agent, "slot": slot, "path": str(path)})
@@ -317,6 +345,8 @@ def _install_workflow(entry: dict, force: bool = False,
317
345
  "source_file": source_rel,
318
346
  "commit": gitutil.head_commit(tap.path),
319
347
  "sha256": hashlib.sha256(raw.encode("utf-8")).hexdigest(),
348
+ "scope": scope,
349
+ "base": str(resolved_base) if resolved_base is not None else None,
320
350
  "installed_at": (existing or {}).get("installed_at", now),
321
351
  "updated_at": now,
322
352
  "materializations": materializations,
@@ -329,6 +359,7 @@ def _install_workflow(entry: dict, force: bool = False,
329
359
  kind="workflow", scan_text=raw)
330
360
  res.linked = linked
331
361
  res.upgraded = existing is not None
362
+ res.scope = scope
332
363
  return res
333
364
 
334
365
 
@@ -506,7 +537,10 @@ def sync_apply(plan: Dict[str, list]) -> List[str]:
506
537
  matches = [e for e in catalog.find(name)
507
538
  if e["tap"] == tap_name and e.get("kind", "skill") == kind]
508
539
  if matches:
509
- install(matches[0], force=True)
540
+ # preserve the original scope/base so a project rule repairs
541
+ # into its repo, not wherever sync happens to run.
542
+ install(matches[0], force=True,
543
+ scope=entry.get("scope", "user"), base=entry.get("base"))
510
544
  actions.append("re-materialized %s %s from %s"
511
545
  % (kind, name, tap_name))
512
546
  continue
@@ -14,6 +14,7 @@ the filesystem writes and the lock record so uninstall can reverse them.
14
14
  from __future__ import annotations
15
15
 
16
16
  from pathlib import Path
17
+ from typing import Optional
17
18
 
18
19
  SLOT_COMMANDS = "commands"
19
20
  SLOT_AGENTS = "agents"
@@ -36,11 +37,16 @@ def detect_slot(source_rel: str) -> str:
36
37
  return SLOT_AGENTS if parts & AGENT_DIRS else SLOT_COMMANDS
37
38
 
38
39
 
39
- def workflow_target(skills_dir: Path, slot: str, name: str) -> Path:
40
+ def workflow_target(skills_dir: Path, slot: str, name: str,
41
+ base: Optional[Path] = None) -> Path:
40
42
  """Where workflow ``name`` (in ``slot``) materializes for an agent.
41
43
 
42
- The agent root is the parent of its configured skills dir
43
- (``~/.claude/skills`` -> ``~/.claude``), so the file lands at
44
- ``<root>/<slot>/<name>.md`` with no extra config.
44
+ ``base`` selects the scope:
45
+ * ``None`` (user scope) the parent of the agent's configured skills dir
46
+ (``~/.claude/skills`` -> ``~/.claude/<slot>/<name>.md``).
47
+ * a directory (project scope) — that repo's per-agent dotdir
48
+ (``<base>/.claude/<slot>/<name>.md``).
45
49
  """
46
- return Path(skills_dir).parent / slot / (name + ".md")
50
+ root = (Path(base) / Path(skills_dir).parent.name) if base is not None \
51
+ else Path(skills_dir).parent
52
+ return root / slot / (name + ".md")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.147
3
+ Version: 1.0.149
4
4
  Summary: boost — Homebrew for AI coding skills
5
5
  Author: Jonathan Reyes
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -708,6 +708,10 @@ Requires-Dist: ragas<0.3,>=0.2; extra == "eval"
708
708
  Requires-Dist: langchain-core<0.4; extra == "eval"
709
709
  Requires-Dist: langchain-community<0.4; extra == "eval"
710
710
  Requires-Dist: langchain-openai<1; extra == "eval"
711
+ Provides-Extra: bdd
712
+ Requires-Dist: behave>=1.2.6; extra == "bdd"
713
+ Provides-Extra: perf
714
+ Requires-Dist: pytest-benchmark>=4.0; extra == "perf"
711
715
  Dynamic: license-file
712
716
 
713
717
  # boost — a package manager for AI coding skills
@@ -141,6 +141,7 @@ docs/roadmap/items/github-pages-deploy-is-broken-every-push.md
141
141
  docs/roadmap/items/golden-set-statistical-power.md
142
142
  docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md
143
143
  docs/roadmap/items/html-validation-html-validate.md
144
+ docs/roadmap/items/install-scope-user-or-project.md
144
145
  docs/roadmap/items/integrity-verification-boost-verify.md
145
146
  docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md
146
147
  docs/roadmap/items/layering-guard-import-linter.md
@@ -216,6 +217,7 @@ docs/roadmap/items/workspace-scope-install.md
216
217
  examples/README.md
217
218
  examples/adapt-demo.sh
218
219
  examples/boost-run-prototype.sh
220
+ scripts/bench_cli.sh
219
221
  scripts/build_registries.py
220
222
  scripts/build_roadmap.py
221
223
  scripts/ensure_eval_corpus.sh
@@ -230,6 +232,22 @@ style/demo.html
230
232
  tests/conftest.py
231
233
  tests/make_fixture.py
232
234
  tests/smoke.sh
235
+ tests/bdd/features/adapt.feature
236
+ tests/bdd/features/browse.feature
237
+ tests/bdd/features/count.feature
238
+ tests/bdd/features/discover.feature
239
+ tests/bdd/features/doctor.feature
240
+ tests/bdd/features/environment.py
241
+ tests/bdd/features/explain.feature
242
+ tests/bdd/features/index.feature
243
+ tests/bdd/features/install.feature
244
+ tests/bdd/features/list.feature
245
+ tests/bdd/features/mcp.feature
246
+ tests/bdd/features/search.feature
247
+ tests/bdd/features/steps/cli_steps.py
248
+ tests/bdd/features/steps/discovery_steps.py
249
+ tests/bdd/features/steps/mcp_steps.py
250
+ tests/bdd/features/steps/quality_steps.py
233
251
  tests/eval/baseline.json
234
252
  tests/eval/explain.jsonl
235
253
  tests/eval/golden.jsonl
@@ -248,6 +266,7 @@ tests/functional/test_cli_taps.py
248
266
  tests/functional/test_cli_team.py
249
267
  tests/functional/test_everyday_loop.py
250
268
  tests/functional/test_property_parsers.py
269
+ tests/perf/test_benchmarks.py
251
270
  tests/unit/test_adapters.py
252
271
  tests/unit/test_agents.py
253
272
  tests/unit/test_ai.py
@@ -1,4 +1,7 @@
1
1
 
2
+ [bdd]
3
+ behave>=1.2.6
4
+
2
5
  [eval]
3
6
  ranx>=0.3.20
4
7
  ragas<0.3,>=0.2
@@ -6,5 +9,8 @@ langchain-core<0.4
6
9
  langchain-community<0.4
7
10
  langchain-openai<1
8
11
 
12
+ [perf]
13
+ pytest-benchmark>=4.0
14
+
9
15
  [rag]
10
16
  sqlite-vec>=0.1.6
@@ -0,0 +1,27 @@
1
+ ---
2
+ id: install-scope-user-or-project
3
+ board: code
4
+ section: internals
5
+ status: shipped
6
+ category: Install engine · UX
7
+ complexity: M
8
+ impact: High
9
+ wow: 3
10
+ note: rules/workflows were user-global only
11
+ order: 27
12
+ owner: loop/install-scope
13
+ pr: 169
14
+ title: <code>boost install --scope user|project</code> for rules/workflows
15
+ ---
16
+ Rule and workflow install always materialized into user-global agent config
17
+ (<code>~/.claude/CLAUDE.md</code>, <code>~/.cursor/rules</code>, …), so a
18
+ rule meant for one repo leaked into every session. Add
19
+ <code>--scope project</code>: materialize into the current repo instead —
20
+ <code>&lt;repo&gt;/.cursor/rules/</code>, <code>&lt;repo&gt;/.claude/commands|agents/</code>,
21
+ and, since Claude reads per-repo memory from the root and has no rules
22
+ folder, <code>&lt;repo&gt;/CLAUDE.local.md</code> (the personal, git-ignored
23
+ file). The chosen scope + base dir are recorded in the lock so
24
+ <code>update</code>/<code>sync</code> re-materialize back into the same
25
+ repo rather than wherever they happen to run. Default stays
26
+ <code>--scope user</code> (unchanged behavior). Uninstall already reverses
27
+ by recorded path, so it works for either scope.
@@ -118,7 +118,7 @@
118
118
  <div class="stat"><b>16</b><span>Shipped</span></div>
119
119
  <div class="stat"><b>1</b><span>Next up</span></div>
120
120
  <div class="stat"><b>4</b><span>Planned</span></div>
121
- <div class="stat"><b>107</b><span>Loop finds</span></div>
121
+ <div class="stat"><b>108</b><span>Loop finds</span></div>
122
122
  <!-- /ROADMAP:stats -->
123
123
  </div>
124
124
  </section>
@@ -840,6 +840,29 @@ chunks instead cost ~70%.</p>
840
840
  <span class="m">close the last skill-only gaps for rules/workflows</span>
841
841
  </div>
842
842
  </article>
843
+
844
+ <article class="cap rcard">
845
+ <div class="head"><span class="pill shipped">Shipped</span><span class="cat">Install engine · UX</span></div>
846
+ <h3><code>boost install --scope user|project</code> for rules/workflows</h3>
847
+ <p>Rule and workflow install always materialized into user-global agent config
848
+ (<code>~/.claude/CLAUDE.md</code>, <code>~/.cursor/rules</code>, …), so a
849
+ rule meant for one repo leaked into every session. Add
850
+ <code>--scope project</code>: materialize into the current repo instead —
851
+ <code>&lt;repo&gt;/.cursor/rules/</code>, <code>&lt;repo&gt;/.claude/commands|agents/</code>,
852
+ and, since Claude reads per-repo memory from the root and has no rules
853
+ folder, <code>&lt;repo&gt;/CLAUDE.local.md</code> (the personal, git-ignored
854
+ file). The chosen scope + base dir are recorded in the lock so
855
+ <code>update</code>/<code>sync</code> re-materialize back into the same
856
+ repo rather than wherever they happen to run. Default stays
857
+ <code>--scope user</code> (unchanged behavior). Uninstall already reverses
858
+ by recorded path, so it works for either scope.</p>
859
+ <div class="meta">
860
+ <span class="m">Complexity <b>M</b></span>
861
+ <span class="m hi">Impact <b>High</b></span>
862
+ <span class="m">Wow <b class="wow">★★★</b></span>
863
+ <span class="m">rules/workflows were user-global only</span>
864
+ </div>
865
+ </article>
843
866
  <!-- /ROADMAP:cards -->
844
867
 
845
868
  </div>
@@ -55,6 +55,16 @@ eval = [
55
55
  "langchain-community<0.4",
56
56
  "langchain-openai<1",
57
57
  ]
58
+ # Opt-in Gherkin/BDD functional suite (tests/bdd) — reusable Given/When/Then
59
+ # scenarios over the same in-process CLI entrypoint tests/functional drives.
60
+ # Additive to, not a replacement for, the pytest functional suite; not part of
61
+ # `make check`. `pip install -e '.[bdd]'`.
62
+ bdd = ["behave>=1.2.6"]
63
+ # Opt-in micro-benchmarks (tests/perf, `make bench`) for perf-sensitive core
64
+ # paths (BM25 indexing/search, catalog scan). Not part of `make check` — a
65
+ # timing regression shouldn't block a merge the way a correctness gate does.
66
+ # `pip install -e '.[perf]'`.
67
+ perf = ["pytest-benchmark>=4.0"]
58
68
 
59
69
  [project.scripts]
60
70
  boost = "boost_cli.cli:main"
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env bash
2
+ # Wall-clock benchmark of the real `boost` binary via hyperfine — the actual
3
+ # fork+exec CLI, not the in-process pytest-benchmark suite (tests/perf).
4
+ # Opt-in (`make bench-cli`); not part of `make check`. Degrades cleanly if
5
+ # hyperfine isn't installed.
6
+ set -uo pipefail
7
+
8
+ if ! command -v hyperfine >/dev/null 2>&1; then
9
+ echo "hyperfine not installed — install via 'brew install hyperfine', skipping"
10
+ exit 0
11
+ fi
12
+
13
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
14
+ SB="$(mktemp -d "${TMPDIR:-/tmp}/boost-bench-XXXXXX")"
15
+ trap 'rm -rf "$SB"' EXIT
16
+ export HOME="$SB" BOOST_NO_AI=1 BOOST_ASSUME_YES=1 NO_COLOR=1
17
+
18
+ FIX="$(python3 "$ROOT/tests/make_fixture.py" "$SB/fixture-tap")"
19
+ "$ROOT/boost" tap "$FIX" >/dev/null
20
+ "$ROOT/boost" install brainstorming >/dev/null
21
+
22
+ echo "== hyperfine: $(command -v hyperfine) over $ROOT/boost (sandbox: $SB)"
23
+ hyperfine --warmup 3 \
24
+ "$ROOT/boost --help" \
25
+ "$ROOT/boost list" \
26
+ "$ROOT/boost search brainstorming" \
27
+ "$ROOT/boost count"
@@ -0,0 +1,46 @@
1
+ Feature: boost adapt
2
+ Render a skill as another agent framework's native source (CrewAI, Agents SDK).
3
+
4
+ Background:
5
+ Given a fresh boost environment
6
+ And the fixture tap is added
7
+
8
+ Scenario: adapting an installed skill to CrewAI
9
+ Given the "brainstorming" skill is installed
10
+ When I run "boost adapt brainstorming --to crewai"
11
+ Then the exit code should be 0
12
+ And the output should contain "from crewai import Agent"
13
+ And the output should contain "brainstorming = Agent("
14
+
15
+ Scenario: adapting an installed skill to the Agents SDK
16
+ Given the "brainstorming" skill is installed
17
+ When I run "boost adapt brainstorming --to agents-sdk"
18
+ Then the exit code should be 0
19
+ And the output should contain "from agents import Agent"
20
+ And the output should match "name=\"brainstorming\""
21
+
22
+ Scenario: adapting a tapped-but-not-installed skill still resolves
23
+ When I run "boost adapt brainstorming --to crewai"
24
+ Then the exit code should be 0
25
+ And the output should contain "brainstorming = Agent("
26
+
27
+ Scenario: --model none opts out of pinning an LLM
28
+ Given the "brainstorming" skill is installed
29
+ When I run "boost adapt brainstorming --to crewai --model none"
30
+ Then the exit code should be 0
31
+ And the output should not contain "llm="
32
+
33
+ Scenario: an unknown framework is rejected
34
+ Given the "brainstorming" skill is installed
35
+ When I run "boost adapt brainstorming --to langchain"
36
+ Then the exit code should be 1
37
+ And the output should contain "unknown framework"
38
+
39
+ Scenario: --to is required
40
+ Given the "brainstorming" skill is installed
41
+ When I run "boost adapt brainstorming"
42
+ Then the exit code should be 2
43
+
44
+ Scenario: adapting an unknown skill fails
45
+ When I run "boost adapt does-not-exist --to crewai"
46
+ Then the exit code should be 1
@@ -0,0 +1,26 @@
1
+ Feature: boost browse
2
+ Interactive full-screen TUI with fuzzy search. There is no TTY in these
3
+ scenarios, so `browse` takes its documented non-interactive escape hatch
4
+ and prints the full catalog instead of launching curses.
5
+
6
+ Background:
7
+ Given a fresh boost environment
8
+
9
+ Scenario: no skills available to browse
10
+ When I run "boost browse"
11
+ Then the exit code should be 1
12
+ And the output should contain "no skills available to browse"
13
+
14
+ Scenario: without a TTY, prints the full catalog instead of the TUI
15
+ Given the fixture tap is added
16
+ When I run "boost browse"
17
+ Then the exit code should be 0
18
+ And the output should contain "interactive mode needs a TTY — showing the full catalog"
19
+ And the output should contain "brainstorming"
20
+ And the output should contain "commit-messages"
21
+ And the output should contain "5 skills · install with `boost install <name>`"
22
+
23
+ Scenario: --help documents the command without touching the catalog
24
+ When I run "boost browse --help"
25
+ Then the exit code should be 0
26
+ And the output should contain "Interactive full-screen TUI with fuzzy search"
@@ -0,0 +1,24 @@
1
+ Feature: boost count
2
+ A one-line inventory summary: installed / available / taps / discovery index.
3
+
4
+ Background:
5
+ Given a fresh boost environment
6
+
7
+ Scenario: an empty environment
8
+ When I run "boost count"
9
+ Then the exit code should be 0
10
+ And the output should contain "installed 0 · available 0 (across 0 taps) · discovery index not built"
11
+
12
+ Scenario: one tap with one installed skill
13
+ Given the "brainstorming" skill is installed
14
+ When I run "boost count"
15
+ Then the exit code should be 0
16
+ And the output should contain "installed 1 · available 5 (across 1 tap) · discovery index not built"
17
+ And the output should contain "╭─ inventory"
18
+
19
+ Scenario: --json is machine readable
20
+ Given the "brainstorming" skill is installed
21
+ When I run "boost count --json"
22
+ Then the exit code should be 0
23
+ And the output should match "\"installed\": 1"
24
+ And the output should match "\"taps\": 1"