boost-skill-cli 1.0.97__tar.gz → 1.0.99__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 (253) hide show
  1. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/Makefile +18 -1
  2. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/PKG-INFO +1 -1
  3. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/_version.py +2 -2
  4. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/commands/configuration.py +1 -1
  5. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/commands/discovery.py +32 -26
  6. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/commands/info.py +22 -22
  7. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/commands/intelligence.py +18 -19
  8. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/commands/pkg.py +3 -4
  9. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/commands/quality.py +34 -34
  10. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/commands/taps.py +5 -6
  11. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/commands/team.py +20 -21
  12. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/ai.py +2 -2
  13. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/embed.py +3 -1
  14. boost_skill_cli-1.0.99/boost_cli/core/nethttp.py +41 -0
  15. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/output.py +45 -9
  16. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_skill_cli.egg-info/PKG-INFO +1 -1
  17. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_skill_cli.egg-info/SOURCES.txt +11 -0
  18. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/design-roadmap.html +3 -3
  19. boost_skill_cli-1.0.99/docs/roadmap/items/BOOST-D04.md +16 -0
  20. boost_skill_cli-1.0.99/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +26 -0
  21. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/fork-safe-network-proxy-handler.md +3 -3
  22. boost_skill_cli-1.0.99/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +22 -0
  23. boost_skill_cli-1.0.99/docs/roadmap/items/retrieval-quality-eval-harness.md +39 -0
  24. boost_skill_cli-1.0.99/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +24 -0
  25. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap.html +97 -3
  26. boost_skill_cli-1.0.99/scripts/eval_recommend.py +272 -0
  27. boost_skill_cli-1.0.99/scripts/eval_retrieval.py +384 -0
  28. boost_skill_cli-1.0.99/tests/eval/baseline.json +17 -0
  29. boost_skill_cli-1.0.99/tests/eval/golden.jsonl +52 -0
  30. boost_skill_cli-1.0.99/tests/eval/recommend.jsonl +19 -0
  31. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/functional/test_cli_discovery.py +16 -0
  32. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_ai.py +6 -6
  33. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_embed.py +3 -3
  34. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_mutation_hardening.py +6 -2
  35. boost_skill_cli-1.0.99/tests/unit/test_nethttp.py +85 -0
  36. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_output.py +65 -4
  37. boost_skill_cli-1.0.97/docs/roadmap/items/BOOST-D04.md +0 -16
  38. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/.gitattributes +0 -0
  39. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/.gitignore +0 -0
  40. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/CLAUDE.md +0 -0
  41. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/CONTRIBUTING.md +0 -0
  42. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/LICENSE +0 -0
  43. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/MANIFEST.in +0 -0
  44. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/README.md +0 -0
  45. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/SECURITY.md +0 -0
  46. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost +0 -0
  47. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/__init__.py +0 -0
  48. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/__main__.py +0 -0
  49. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/cli.py +0 -0
  50. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/cliparse.py +0 -0
  51. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/commands/__init__.py +0 -0
  52. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/commands/bmad.py +0 -0
  53. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/commands/hooks.py +0 -0
  54. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/__init__.py +0 -0
  55. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/agents.py +0 -0
  56. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/catalog.py +0 -0
  57. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/claude_settings.py +0 -0
  58. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/config.py +0 -0
  59. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/dense.py +0 -0
  60. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/frontmatter.py +0 -0
  61. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/gitutil.py +0 -0
  62. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/journal.py +0 -0
  63. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/lockfile.py +0 -0
  64. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/logs.py +0 -0
  65. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/mcp.py +0 -0
  66. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/paths.py +0 -0
  67. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/policy.py +0 -0
  68. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/rag.py +0 -0
  69. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/registry.py +0 -0
  70. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/serve.py +0 -0
  71. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/staleness.py +0 -0
  72. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/store.py +0 -0
  73. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/typosquat.py +0 -0
  74. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/core/util.py +0 -0
  75. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/data/registries.json +0 -0
  76. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/errors.py +0 -0
  77. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_cli/spin.py +0 -0
  78. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
  79. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_skill_cli.egg-info/entry_points.txt +0 -0
  80. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_skill_cli.egg-info/requires.txt +0 -0
  81. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/boost_skill_cli.egg-info/top_level.txt +0 -0
  82. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/.claude/settings.local.json +0 -0
  83. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/DEBUGGING.md +0 -0
  84. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/demo.gif +0 -0
  85. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/demo.tape +0 -0
  86. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/index.html +0 -0
  87. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/mcp-hub.html +0 -0
  88. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/rag-architecture.md +0 -0
  89. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D01.md +0 -0
  90. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D02.md +0 -0
  91. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D03.md +0 -0
  92. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D05.md +0 -0
  93. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D06.md +0 -0
  94. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D07.md +0 -0
  95. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D08.md +0 -0
  96. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D09.md +0 -0
  97. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D10.md +0 -0
  98. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D11.md +0 -0
  99. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D12.md +0 -0
  100. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D13.md +0 -0
  101. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D14.md +0 -0
  102. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D15.md +0 -0
  103. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D16.md +0 -0
  104. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D17.md +0 -0
  105. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D18.md +0 -0
  106. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D19.md +0 -0
  107. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D20.md +0 -0
  108. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D21.md +0 -0
  109. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D22.md +0 -0
  110. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D23.md +0 -0
  111. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D24.md +0 -0
  112. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D25.md +0 -0
  113. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/BOOST-D26.md +0 -0
  114. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
  115. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
  116. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
  117. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
  118. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
  119. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
  120. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
  121. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
  122. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
  123. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
  124. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/command-reference-docs-site.md +0 -0
  125. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
  126. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
  127. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
  128. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
  129. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
  130. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
  131. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
  132. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
  133. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
  134. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
  135. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
  136. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
  137. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
  138. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
  139. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
  140. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/html-validation-html-validate.md +0 -0
  141. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
  142. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
  143. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
  144. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
  145. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
  146. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
  147. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
  148. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
  149. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
  150. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
  151. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
  152. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
  153. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
  154. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
  155. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
  156. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
  157. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
  158. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
  159. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
  160. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
  161. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
  162. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
  163. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
  164. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
  165. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
  166. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
  167. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
  168. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
  169. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
  170. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
  171. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
  172. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
  173. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
  174. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
  175. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
  176. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
  177. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
  178. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
  179. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
  180. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
  181. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
  182. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
  183. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
  184. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
  185. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
  186. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
  187. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
  188. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
  189. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
  190. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
  191. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/typo-detection-codespell.md +0 -0
  192. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
  193. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
  194. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
  195. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/update-diff-before-apply.md +0 -0
  196. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
  197. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
  198. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
  199. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
  200. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
  201. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/docs/roadmap/items/workspace-scope-install.md +0 -0
  202. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/index.html +0 -0
  203. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/pyproject.toml +0 -0
  204. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/scripts/build_registries.py +0 -0
  205. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/scripts/build_roadmap.py +0 -0
  206. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/scripts/mutation_gate.py +0 -0
  207. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/setup.cfg +0 -0
  208. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/style/README.md +0 -0
  209. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/style/boost.css +0 -0
  210. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/style/boost.js +0 -0
  211. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/style/demo.html +0 -0
  212. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/conftest.py +0 -0
  213. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/functional/test_cli_bmad.py +0 -0
  214. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/functional/test_cli_configuration.py +0 -0
  215. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/functional/test_cli_hooks.py +0 -0
  216. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/functional/test_cli_info.py +0 -0
  217. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/functional/test_cli_intelligence.py +0 -0
  218. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/functional/test_cli_pkg.py +0 -0
  219. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/functional/test_cli_quality.py +0 -0
  220. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/functional/test_cli_taps.py +0 -0
  221. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/functional/test_cli_team.py +0 -0
  222. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/functional/test_everyday_loop.py +0 -0
  223. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/make_fixture.py +0 -0
  224. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/smoke.sh +0 -0
  225. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_agents.py +0 -0
  226. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_catalog.py +0 -0
  227. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_claude_settings.py +0 -0
  228. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_cliparse.py +0 -0
  229. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_config.py +0 -0
  230. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_dense.py +0 -0
  231. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_dense_fallback.py +0 -0
  232. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_errors_and_cli_table.py +0 -0
  233. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_frontmatter.py +0 -0
  234. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_gitutil.py +0 -0
  235. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_journal.py +0 -0
  236. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_lockfile.py +0 -0
  237. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_logs.py +0 -0
  238. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_mcp.py +0 -0
  239. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_paths.py +0 -0
  240. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_pkg_confusions.py +0 -0
  241. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_policy.py +0 -0
  242. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_rag.py +0 -0
  243. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_registries_fresh.py +0 -0
  244. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_registry.py +0 -0
  245. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_roadmap_fresh.py +0 -0
  246. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_serve.py +0 -0
  247. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_spin.py +0 -0
  248. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_staleness.py +0 -0
  249. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_store.py +0 -0
  250. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_token_parity.py +0 -0
  251. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_typosquat.py +0 -0
  252. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_util.py +0 -0
  253. {boost_skill_cli-1.0.97 → boost_skill_cli-1.0.99}/tests/unit/test_version.py +0 -0
@@ -6,7 +6,7 @@ VENV := .venv
6
6
  PY := $(VENV)/bin/python
7
7
  PYTEST := $(VENV)/bin/pytest
8
8
 
9
- .PHONY: venv test unit functional smoke coverage mutation lint check demo clean-test
9
+ .PHONY: venv test unit functional smoke coverage mutation lint check demo clean-test eval eval-ai eval-rec
10
10
 
11
11
  venv:
12
12
  python3 -m venv $(VENV)
@@ -39,6 +39,23 @@ lint:
39
39
  $(PY) scripts/build_registries.py --check
40
40
  $(PY) scripts/build_roadmap.py --check
41
41
 
42
+ # Tier 1 retrieval quality gate: golden-set recall@k over the tapped catalog.
43
+ # Deterministic + offline; a release-quality gate, kept separate from `check`.
44
+ eval:
45
+ $(PY) scripts/eval_retrieval.py --build -k 10 --fail-under 0.85
46
+
47
+ # Tier 2a: LLM rerank lift over BM25 on the same golden set. Opt-in and
48
+ # key-gated — needs the `claude` CLI on PATH or ANTHROPIC_API_KEY; skips
49
+ # cleanly otherwise. Not part of `check` (network + cost).
50
+ eval-ai:
51
+ $(PY) scripts/eval_retrieval.py --rerank -k 10
52
+
53
+ # Tier 2b: recommendation quality — heuristic vs `_ai_picks` over golden
54
+ # stacks, with a hard grounding gate (no off-shortlist / hallucinated picks).
55
+ # Same opt-in/key-gated contract as eval-ai; the heuristic arm always runs.
56
+ eval-rec:
57
+ $(PY) scripts/eval_recommend.py --build -k 5 --fail-hallucination
58
+
42
59
  # regenerate generated artifacts from their source (registries + roadmap boards)
43
60
  generate:
44
61
  $(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.97
3
+ Version: 1.0.99
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.97'
22
- __version_tuple__ = version_tuple = (1, 0, 97)
21
+ __version__ = version = '1.0.99'
22
+ __version_tuple__ = version_tuple = (1, 0, 99)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -165,7 +165,7 @@ def cmd_clean(argv) -> int:
165
165
  out.warn("could not remove %s: %s" % (_tilde(pth), e))
166
166
  continue
167
167
  freed += size
168
- out.info("%s %s %s" % (verb, _tilde(pth), out.c("(%s)" % kind, out.DIM)))
168
+ out.info("%s %s %s" % (verb, _tilde(pth), out.role("(%s)" % kind, "muted")))
169
169
  if args.dry_run:
170
170
  out.dim(" %d item(s) · %s would be freed" % (len(items), util.human_size(freed)))
171
171
  else:
@@ -193,8 +193,7 @@ def cmd_search(argv):
193
193
  return 0
194
194
  if not scored:
195
195
  out.info("no matches for %r" % query)
196
- out.info(out.c("try `boost discover %s` to search all of GitHub" % query,
197
- out.DIM))
196
+ out.info(out.role("try `boost discover %s` to search all of GitHub" % query, "muted"))
198
197
  return 0
199
198
  ranker = "full-content BM25" if use_rag else "heuristic relevance"
200
199
  if args.smart:
@@ -216,15 +215,14 @@ def cmd_search(argv):
216
215
  frac = sc / top
217
216
  hue = "cyan" if frac >= 0.66 else "violet" if frac >= 0.33 else "pink"
218
217
  bar = out.aurora(out.meter(frac), hue)
219
- tag = " " + out.c("★ curated", out.YELLOW) if e.get("curated") else ""
218
+ tag = " " + out.role("★ curated", "warn") if e.get("curated") else ""
220
219
  tag_w = len(" ★ curated") if e.get("curated") else 0
221
220
  desc_w = max(cols - 2 - 5 - name_w - 2 - tag_w, 8) # 5 = meter + space
222
- name_cell = out.c(out.truncate(e["name"], name_w).ljust(name_w), out.CYAN)
221
+ name_cell = out.role(out.truncate(e["name"], name_w).ljust(name_w), "accent")
223
222
  out.info(bar + " " + name_cell + " "
224
223
  + out.truncate(e["description"] or "", desc_w) + tag)
225
- out.info(out.c("%d match%s · ranked by %s"
226
- % (len(scored), "" if len(scored) == 1 else "es", ranker),
227
- out.DIM))
224
+ out.info(out.role("%d match%s · ranked by %s"
225
+ % (len(scored), "" if len(scored) == 1 else "es", ranker), "muted"))
228
226
  return 0
229
227
 
230
228
 
@@ -258,11 +256,10 @@ def cmd_reindex(argv):
258
256
  % (stats["docs"], stats["entries"], stats["taps"],
259
257
  "" if stats["taps"] == 1 else "s"))
260
258
  if stats["reused"]:
261
- out.info(out.c("reused %d unchanged tap%s; reindexed: %s"
259
+ out.info(out.role("reused %d unchanged tap%s; reindexed: %s"
262
260
  % (len(stats["reused"]),
263
261
  "" if len(stats["reused"]) == 1 else "s",
264
- ", ".join(stats["reindexed"]) or "none"),
265
- out.DIM))
262
+ ", ".join(stats["reindexed"]) or "none"), "muted"))
266
263
  if args.dense:
267
264
  if dense_stats is None:
268
265
  out.warn("dense index skipped — %s" % embed.fallback_note())
@@ -426,15 +423,15 @@ def cmd_discover(argv):
426
423
  return 0
427
424
  if not shown:
428
425
  out.info("no indexed skills match %r" % " ".join(args.query))
429
- out.info(out.c("the index holds %d entries — rebuild with `boost index`"
430
- % len(all_items), out.DIM))
426
+ out.info(out.role("the index holds %d entries — rebuild with `boost index`"
427
+ % len(all_items), "muted"))
431
428
  return 0
432
429
  out.table([(it.get("repo", "?"), it.get("path", ""),
433
- out.c(it.get("url", ""), out.DIM)) for it in shown],
430
+ out.role(it.get("url", ""), "muted")) for it in shown],
434
431
  headers=("repo", "path", "url"))
435
- out.info(out.c("%d of %d indexed skills · GitHub reports ~%d total"
432
+ out.info(out.role("%d of %d indexed skills · GitHub reports ~%d total"
436
433
  % (len(shown), len(all_items),
437
- int(data.get("github_total") or 0)), out.DIM))
434
+ int(data.get("github_total") or 0)), "muted"))
438
435
  return 0
439
436
 
440
437
 
@@ -494,7 +491,7 @@ def cmd_recommend(argv):
494
491
  line = "stack: " + (", ".join(stack["languages"]) or "unknown")
495
492
  if stack["frameworks"]:
496
493
  line += " · frameworks: " + ", ".join(stack["frameworks"])
497
- out.info(out.c("%s (%s)" % (line, _tilde(target)), out.DIM))
494
+ out.info(out.role("%s (%s)" % (line, _tilde(target)), "muted"))
498
495
  shown = ranked[:args.limit]
499
496
  if not shown:
500
497
  shown = [{"entry": e, "score": 0, "because": {"curated"}}
@@ -509,15 +506,15 @@ def cmd_recommend(argv):
509
506
  e = r["entry"]
510
507
  because = "because: %s" % ", ".join(sorted(r["because"]))
511
508
  desc_w = max(cols - 2 - width - 2 - (len(because) + 2), 8)
512
- name_cell = out.c(out.truncate(e["name"], width).ljust(width), out.CYAN)
509
+ name_cell = out.role(out.truncate(e["name"], width).ljust(width), "accent")
513
510
  out.info(name_cell + " " + out.truncate(e["description"] or "", desc_w)
514
- + " " + out.c(because, out.DIM))
511
+ + " " + out.role(because, "muted"))
515
512
  if ai.available():
516
513
  picks = _ai_picks(stack, [r["entry"] for r in ranked[:20]])
517
514
  if picks:
518
515
  out.heading("AI picks")
519
516
  for pk in picks:
520
- out.info(out.c(str(pk.get("name", "?")), out.CYAN) + " "
517
+ out.info(out.role(str(pk.get("name", "?")), "accent") + " "
521
518
  + str(pk.get("reason", "")))
522
519
  return 0
523
520
 
@@ -533,8 +530,8 @@ def _browse_plain(entries, why: str):
533
530
  out.table([(e["name"], "v" + e["version"], e["tap"],
534
531
  "★" if e.get("curated") else "") for e in entries],
535
532
  headers=("name", "version", "tap", ""))
536
- out.info(out.c("%d skills · install with `boost install <name>`"
537
- % len(entries), out.DIM))
533
+ out.info(out.role("%d skills · install with `boost install <name>`"
534
+ % len(entries), "muted"))
538
535
  return 0
539
536
 
540
537
 
@@ -801,7 +798,16 @@ def cmd_browse(argv):
801
798
  picked = _browse_tui(curses, entries)
802
799
  if picked is None:
803
800
  return 0
804
- res = store.install(picked)
801
+ try:
802
+ res = store.install(picked)
803
+ except BoostError as e:
804
+ # browse lists every catalog kind (skills, rules, workflows), but only
805
+ # skills install; a rule/workflow pick — or an already-installed/pinned
806
+ # skill — must not exit the interactive TUI with a fatal error.
807
+ out.warn(e.message)
808
+ if e.hint:
809
+ out.info(out.c(e.hint, out.DIM))
810
+ return 0
805
811
  out.ok("installed %s v%s → %s"
806
812
  % (picked["name"], picked["version"], _tilde(res.dest)))
807
813
  if res.linked:
@@ -844,7 +850,7 @@ def cmd_trending(argv):
844
850
  out.truncate(by_name.get(name, {}).get("description", ""), descw))
845
851
  for name, rec in ranked[:args.limit]],
846
852
  headers=("name", "installs", "last", "description"))
847
- out.info(out.c("based on local install activity", out.DIM))
853
+ out.info(out.role("based on local install activity", "muted"))
848
854
  return 0
849
855
 
850
856
 
@@ -901,14 +907,14 @@ def cmd_stats(argv):
901
907
  out.kv("version", cat["version"])
902
908
  out.kv("tap", cat["tap"])
903
909
  out.kv("description", cat["description"])
904
- out.info(out.c("not installed — `boost install %s`" % name, out.DIM))
910
+ out.info(out.role("not installed — `boost install %s`" % name, "muted"))
905
911
  out.kv("activity", "%d installs · %d updates · %d uninstalls"
906
912
  % (acts["install"], acts["update"], acts["uninstall"]))
907
913
  if lock and latest:
908
914
  if util.semver_gt(latest, lock.get("version", "0")):
909
- out.kv("latest", "%s %s" % (latest, out.c("(update available)", out.YELLOW)))
915
+ out.kv("latest", "%s %s" % (latest, out.role("(update available)", "warn")))
910
916
  else:
911
- out.kv("latest", "%s %s" % (latest, out.c("(up to date)", out.DIM)))
917
+ out.kv("latest", "%s %s" % (latest, out.role("(up to date)", "muted")))
912
918
  if upstream:
913
919
  out.kv("upstream", upstream)
914
920
  return 0
@@ -78,8 +78,8 @@ def _file_count(d: Path) -> int:
78
78
 
79
79
 
80
80
  def _mark(installed: bool) -> str:
81
- return (out.c("✓ installed", out.GREEN) if installed
82
- else out.c("✗ not installed", out.RED))
81
+ return (out.role("✓ installed", "success") if installed
82
+ else out.role("✗ not installed", "danger"))
83
83
 
84
84
 
85
85
  def _print_wrapped(text: str) -> None:
@@ -122,7 +122,7 @@ def cmd_list(argv):
122
122
  flags = ([out.aurora("pinned", "yellow")] if e.get("pinned") else []) + \
123
123
  ([out.aurora("quarantined", "pink")] if e.get("quarantined")
124
124
  else []) + \
125
- [out.c("#" + t, out.DIM) for t in e.get("tags") or []]
125
+ [out.role("#" + t, "muted") for t in e.get("tags") or []]
126
126
  rows.append((name, e.get("version", "?"), e.get("tap", "?"),
127
127
  "·".join(a.split("-")[0] for a in e.get("agents") or []),
128
128
  " ".join(flags)))
@@ -204,8 +204,8 @@ def cmd_info(argv):
204
204
  out.kv("version", inst_v)
205
205
  latest = str((cat or {}).get("version") or "")
206
206
  if cat and latest != inst_v:
207
- out.kv("latest", out.c(latest, out.YELLOW, out.BOLD)
208
- + out.c(" (update available)", out.DIM))
207
+ out.kv("latest", out.role(latest, "warn", bold=True)
208
+ + out.role(" (update available)", "muted"))
209
209
  else:
210
210
  out.kv("latest", str(cat.get("version", "?")))
211
211
  out.kv("tap", (lock or cat).get("tap", "?"))
@@ -251,10 +251,10 @@ def cmd_cat(argv):
251
251
  return 0
252
252
  block, body = frontmatter.split(text)
253
253
  if block:
254
- print(out.c("---", out.DIM))
254
+ print(out.role("---", "muted"))
255
255
  for line in block.splitlines():
256
- print(out.c(line, out.DIM))
257
- print(out.c("---", out.DIM))
256
+ print(out.role(line, "muted"))
257
+ print(out.role("---", "muted"))
258
258
  print()
259
259
  for line in body.splitlines():
260
260
  print(out.c(line, out.BOLD) if re.match(r"^#{1,6} ", line) else line)
@@ -297,7 +297,7 @@ def cmd_edit(argv):
297
297
 
298
298
 
299
299
  def _inline(s: str) -> str:
300
- s = re.sub(r"`([^`]+)`", lambda m: out.c(m.group(1), out.CYAN), s)
300
+ s = re.sub(r"`([^`]+)`", lambda m: out.role(m.group(1), "accent"), s)
301
301
  return re.sub(r"\*\*([^*]+)\*\*", lambda m: out.c(m.group(1), out.BOLD), s)
302
302
 
303
303
 
@@ -310,7 +310,7 @@ def _render_markdown(body: str) -> None:
310
310
  in_fence = not in_fence
311
311
  continue
312
312
  if in_fence:
313
- print(out.c(" " + line, out.DIM))
313
+ print(out.role(" " + line, "muted"))
314
314
  prev_blank = False
315
315
  continue
316
316
  if not line:
@@ -323,12 +323,12 @@ def _render_markdown(body: str) -> None:
323
323
  if m:
324
324
  level, txt = len(m.group(1)), m.group(2)
325
325
  if level == 1:
326
- print(out.c(txt, out.BOLD, out.YELLOW))
327
- print(out.c("─" * min(len(txt), 60), out.DIM))
326
+ print(out.role(txt, "warn", bold=True))
327
+ print(out.role("─" * min(len(txt), 60), "muted"))
328
328
  elif level == 2:
329
329
  print(out.c(txt, out.BOLD))
330
330
  else:
331
- print(out.c(txt, out.BOLD, out.DIM))
331
+ print(out.role(txt, "muted", bold=True))
332
332
  continue
333
333
  m = re.match(r"^(\s*)[-*]\s+(.*)$", line)
334
334
  if m:
@@ -470,7 +470,7 @@ def cmd_log(argv):
470
470
  if not events:
471
471
  out.info("no activity yet")
472
472
  return 0
473
- colors = {"install": out.GREEN, "uninstall": out.RED}
473
+ action_roles = {"install": "success", "uninstall": "danger"}
474
474
  w_time = max(len(util.rel_time(e.get("ts", ""))) for e in events)
475
475
  w_user = max(len(e.get("user", "?")) for e in events)
476
476
  for e in events:
@@ -478,7 +478,7 @@ def cmd_log(argv):
478
478
  out.info(("%s %s %s %s" % (
479
479
  util.rel_time(e.get("ts", "")).ljust(w_time),
480
480
  e.get("user", "?").ljust(w_user),
481
- out.c(action, colors.get(action, out.CYAN)),
481
+ out.role(action, action_roles.get(action, "accent")),
482
482
  e.get("subject", ""))).rstrip())
483
483
  return 0
484
484
 
@@ -539,16 +539,16 @@ def cmd_deps(argv):
539
539
  return 1 if problems else 0
540
540
  out.info(out.c(args.name, out.BOLD))
541
541
  if not requires:
542
- out.info(" requires: " + out.c("(none)", out.DIM))
542
+ out.info(" requires: " + out.role("(none)", "muted"))
543
543
  for r in requires:
544
544
  out.info(" requires: %s %s" % (r, _mark(r in inst)))
545
545
  for sub in _as_list((_skill_meta(r) or {}).get("requires")):
546
546
  out.info(" ↳ %s %s" % (sub, _mark(sub in inst)))
547
547
  if not conflicts:
548
- out.info(" conflicts: " + out.c("(none)", out.DIM))
548
+ out.info(" conflicts: " + out.role("(none)", "muted"))
549
549
  for c_name in conflicts:
550
- state = (out.c("✗ installed (conflict!)", out.RED) if c_name in inst
551
- else out.c("not installed", out.DIM))
550
+ state = (out.role("✗ installed (conflict!)", "danger") if c_name in inst
551
+ else out.role("not installed", "muted"))
552
552
  out.info(" conflicts: %s %s" % (c_name, state))
553
553
  return 1 if problems else 0
554
554
 
@@ -575,7 +575,7 @@ def cmd_deps(argv):
575
575
  % (out.c(u["skill"], out.BOLD), u["requires"], _mark(False)))
576
576
  for a, b in pairs:
577
577
  out.info("%s %s %s" % (out.c(a, out.BOLD),
578
- out.c("conflicts with", out.RED), out.c(b, out.BOLD)))
578
+ out.role("conflicts with", "danger"), out.c(b, out.BOLD)))
579
579
  if not unmet and not pairs:
580
580
  out.ok("no unmet requirements or conflicts across %d skill%s"
581
581
  % (len(inst), "" if len(inst) == 1 else "s"))
@@ -613,7 +613,7 @@ def cmd_tag(argv):
613
613
  return 0
614
614
  if not mapping:
615
615
  out.info("no tags yet")
616
- out.info(out.c("hint: boost tag <skill> +mytag", out.DIM))
616
+ out.info(out.role("hint: boost tag <skill> +mytag", "muted"))
617
617
  return 0
618
618
  out.table([("#" + t, ", ".join(mapping[t])) for t in sorted(mapping)],
619
619
  headers=("TAG", "SKILLS"))
@@ -649,6 +649,6 @@ def cmd_tag(argv):
649
649
  if args.json:
650
650
  print(json.dumps({"name": args.name, "tags": tags}, indent=2))
651
651
  return 0
652
- shown = " ".join(out.c("#" + t, out.CYAN) for t in tags) or out.c("(no tags)", out.DIM)
652
+ shown = " ".join(out.role("#" + t, "accent") for t in tags) or out.role("(no tags)", "muted")
653
653
  (out.ok if changed else out.info)("%s %s" % (args.name, shown))
654
654
  return 0
@@ -78,7 +78,7 @@ def _install_generated(name: str, text: str) -> None:
78
78
  res = store.install_from_path(src, name=name, tap_label="local")
79
79
  out.ok("installed %s → %s" % (name, _tilde(res.dest)))
80
80
  if res.linked:
81
- out.info(out.c("linked into: %s" % ", ".join(res.linked), out.DIM))
81
+ out.info(out.role("linked into: %s" % ", ".join(res.linked), "muted"))
82
82
 
83
83
 
84
84
  def _write_generated(dest: Path, text: str) -> bool:
@@ -139,7 +139,7 @@ def cmd_distill(argv: List[str]) -> int:
139
139
  dest = Path.cwd() / new / "SKILL.md"
140
140
  if not _write_generated(dest, merged):
141
141
  return 1
142
- out.info(out.c("install it with `boost import ./%s`" % new, out.DIM))
142
+ out.info(out.role("install it with `boost import ./%s`" % new, "muted"))
143
143
  journal.log("distill", new, sources=names)
144
144
  return 0
145
145
 
@@ -212,7 +212,7 @@ def cmd_simulate(argv: List[str]) -> int:
212
212
 
213
213
  text, origin = _skill_text(args.name)
214
214
  task = args.task or "a typical coding task in this repo"
215
- out.heading("simulating %s %s" % (args.name, out.c("(%s)" % origin, out.DIM)))
215
+ out.heading("simulating %s %s" % (args.name, out.role("(%s)" % origin, "muted")))
216
216
 
217
217
  if ai.available():
218
218
  reply = ai.ask(
@@ -236,13 +236,13 @@ def cmd_simulate(argv: List[str]) -> int:
236
236
  for rule in rules[:8]:
237
237
  out.info(" • " + rule)
238
238
  if len(rules) > 8:
239
- out.info(out.c(" … and %d more rules" % (len(rules) - 8), out.DIM))
239
+ out.info(out.role(" … and %d more rules" % (len(rules) - 8), "muted"))
240
240
  else:
241
241
  out.info(" • (no imperative rules found in the skill body)")
242
242
  desc = str(meta.get("description") or "").strip()
243
243
  if desc:
244
- out.info(out.c('likely triggers when the task involves: "%s"'
245
- % desc[:100], out.DIM))
244
+ out.info(out.role('likely triggers when the task involves: "%s"'
245
+ % desc[:100], "muted"))
246
246
  return 0
247
247
 
248
248
 
@@ -526,8 +526,8 @@ def cmd_absorb(argv: List[str]) -> int:
526
526
  src = paths.home() / ".claude" / "projects"
527
527
  if not src.exists():
528
528
  out.info("no chat history found under ~/.claude — nothing to absorb")
529
- out.info(out.c("point at a .jsonl file or directory with "
530
- "--history PATH", out.DIM))
529
+ out.info(out.role("point at a .jsonl file or directory with "
530
+ "--history PATH", "muted"))
531
531
  return 0
532
532
  files = [src] if src.is_file() else sorted(src.rglob("*.jsonl"))
533
533
  if not files:
@@ -663,7 +663,7 @@ def cmd_evolve(argv: List[str]) -> int:
663
663
  old_meta, _ = frontmatter.parse(old)
664
664
  old_ver = str(old_meta.get("version") or "0.0.0")
665
665
 
666
- out.heading("evolving %s %s" % (args.name, out.c("(v%s)" % old_ver, out.DIM)))
666
+ out.heading("evolving %s %s" % (args.name, out.role("(v%s)" % old_ver, "muted")))
667
667
  new = _evolve_ai(old, old_ver, args.feedback) if ai.available() else None
668
668
  if new is None:
669
669
  _note_fallback()
@@ -673,7 +673,7 @@ def cmd_evolve(argv: List[str]) -> int:
673
673
  new_ver = str(new_meta.get("version") or old_ver)
674
674
 
675
675
  if not args.apply:
676
- out.info(out.c("re-run with --apply to write these changes", out.DIM))
676
+ out.info(out.role("re-run with --apply to write these changes", "muted"))
677
677
  return 0
678
678
  skill_md.write_text(new)
679
679
  entry["sha256"] = util.sha256_dir(store.skill_store_dir(args.name))
@@ -726,11 +726,11 @@ def _print_diff(old: str, new: str) -> None:
726
726
  if line.startswith(("+++", "---")):
727
727
  print(out.c(line, out.BOLD))
728
728
  elif line.startswith("@@"):
729
- print(out.c(line, out.CYAN))
729
+ print(out.role(line, "accent"))
730
730
  elif line.startswith("+"):
731
- print(out.c(line, out.GREEN))
731
+ print(out.role(line, "success"))
732
732
  elif line.startswith("-"):
733
- print(out.c(line, out.RED))
733
+ print(out.role(line, "danger"))
734
734
  else:
735
735
  print(line)
736
736
 
@@ -776,7 +776,7 @@ def cmd_context(argv: List[str]) -> int:
776
776
  journal.log("context", args.pattern, op="map", skills=skills)
777
777
  out.ok("mapped %s → %s" % (args.pattern, ", ".join(skills)))
778
778
  if missing:
779
- out.info(out.c("not installed yet: %s" % ", ".join(missing), out.DIM))
779
+ out.info(out.role("not installed yet: %s" % ", ".join(missing), "muted"))
780
780
  return 0
781
781
  if action == "unmap":
782
782
  rules = [r for r in state["rules"] if r.get("pattern") != args.pattern]
@@ -872,7 +872,7 @@ def _context_apply(state: dict) -> int:
872
872
  if not linked and not unlinked:
873
873
  out.info("nothing to change")
874
874
  if missing:
875
- out.info(out.c("mapped but not installed: %s" % ", ".join(missing), out.DIM))
875
+ out.info(out.role("mapped but not installed: %s" % ", ".join(missing), "muted"))
876
876
  if linked or unlinked:
877
877
  journal.log("context", branch, op="apply",
878
878
  linked=linked or None, unlinked=unlinked or None)
@@ -921,9 +921,8 @@ def cmd_focus(argv: List[str]) -> int:
921
921
  if state.get("active"):
922
922
  out.info("⌁ focus: %s %s"
923
923
  % (", ".join(state["active"]),
924
- out.c("(since %s)" % util.rel_time(state.get("since", "")),
925
- out.DIM)))
926
- out.info(out.c("end it with `boost focus --clear`", out.DIM))
924
+ out.role("(since %s)" % util.rel_time(state.get("since", "")), "muted")))
925
+ out.info(out.role("end it with `boost focus --clear`", "muted"))
927
926
  else:
928
927
  out.info("no focus session — start one with `boost focus SKILL...`")
929
928
  return 0
@@ -950,7 +949,7 @@ def cmd_focus(argv: List[str]) -> int:
950
949
  journal.log("focus", ",".join(names))
951
950
  out.info("⌁ focus: %s %s"
952
951
  % (", ".join(names),
953
- out.c("(other %d skills sidelined)" % sidelined, out.DIM)))
952
+ out.role("(other %d skills sidelined)" % sidelined, "muted")))
954
953
  return 0
955
954
 
956
955
 
@@ -164,9 +164,8 @@ def cmd_install(argv: List[str]) -> int:
164
164
  if len(results) == 1:
165
165
  r0 = results[0]
166
166
  if r0.linked:
167
- lines.append(out.c("%s → %s" % (r0.name, " · ".join(r0.linked)),
168
- out.DIM))
169
- lines.append(out.c("next: boost info %s" % r0.name, out.DIM))
167
+ lines.append(out.role("%s → %s" % (r0.name, " · ".join(r0.linked)), "muted"))
168
+ lines.append(out.role("next: boost info %s" % r0.name, "muted"))
170
169
  print(out.panel(lines, title="installed", hue="green"))
171
170
  return 1 if failed else 0
172
171
 
@@ -197,7 +196,7 @@ def cmd_uninstall(argv: List[str]) -> int:
197
196
  if removed:
198
197
  lines = ["Uninstalled %s" % _plural(removed, "skill")]
199
198
  if removed == 1 and len(args.names) == 1:
200
- lines.append(out.c("next: boost list", out.DIM))
199
+ lines.append(out.role("next: boost list", "muted"))
201
200
  print(out.panel(lines, title="removed", hue="pink"))
202
201
  return 1 if failed else 0
203
202