boost-skill-cli 1.0.200__tar.gz → 1.0.201__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 (373) hide show
  1. {boost_skill_cli-1.0.200/boost_skill_cli.egg-info → boost_skill_cli-1.0.201}/PKG-INFO +1 -1
  2. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/_version.py +2 -2
  3. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201/boost_skill_cli.egg-info}/PKG-INFO +1 -1
  4. boost_skill_cli-1.0.201/docs/roadmap/items/finish-mutation-hardening-across-core.md +31 -0
  5. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap.html +18 -6
  6. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_agents.py +7 -0
  7. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_ai.py +4 -1
  8. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_catalog.py +40 -0
  9. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_config.py +18 -0
  10. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_lockfile.py +30 -0
  11. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_output.py +6 -0
  12. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_paths.py +13 -0
  13. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_policy.py +35 -0
  14. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_registry.py +13 -0
  15. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_util.py +72 -0
  16. boost_skill_cli-1.0.200/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -19
  17. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/.gitattributes +0 -0
  18. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/.gitignore +0 -0
  19. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/.gitleaks.toml +0 -0
  20. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/.htmlvalidate.json +0 -0
  21. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/.lighthouserc.json +0 -0
  22. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/.lycheeignore +0 -0
  23. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/.markdownlint-cli2.jsonc +0 -0
  24. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/.pre-commit-config.yaml +0 -0
  25. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/.stylelintrc.json +0 -0
  26. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/.vale/styles/boost/Terminology.yml +0 -0
  27. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/.vale/styles/config/vocabularies/boost/accept.txt +0 -0
  28. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/.vale.ini +0 -0
  29. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/CLAUDE.md +0 -0
  30. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/CONTRIBUTING.md +0 -0
  31. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/LICENSE +0 -0
  32. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/MANIFEST.in +0 -0
  33. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/Makefile +0 -0
  34. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/README.md +0 -0
  35. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/SECURITY.md +0 -0
  36. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost +0 -0
  37. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/__init__.py +0 -0
  38. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/__main__.py +0 -0
  39. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/cli.py +0 -0
  40. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/cliparse.py +0 -0
  41. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/commands/__init__.py +0 -0
  42. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/commands/_common.py +0 -0
  43. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/commands/bmad.py +0 -0
  44. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/commands/configuration.py +0 -0
  45. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/commands/discovery.py +0 -0
  46. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/commands/hooks.py +0 -0
  47. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/commands/info.py +0 -0
  48. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/commands/intelligence.py +0 -0
  49. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/commands/pkg.py +0 -0
  50. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/commands/quality.py +0 -0
  51. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/commands/run.py +0 -0
  52. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/commands/safety.py +0 -0
  53. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/commands/taps.py +0 -0
  54. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/commands/team.py +0 -0
  55. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/__init__.py +0 -0
  56. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/adapters.py +0 -0
  57. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/agents.py +0 -0
  58. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/ai.py +0 -0
  59. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/capabilities.py +0 -0
  60. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/catalog.py +0 -0
  61. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/claude_settings.py +0 -0
  62. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/config.py +0 -0
  63. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/dense.py +0 -0
  64. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/ed25519.py +0 -0
  65. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/embed.py +0 -0
  66. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/faithfulness.py +0 -0
  67. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/frontmatter.py +0 -0
  68. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/gitutil.py +0 -0
  69. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/imperative.py +0 -0
  70. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/injectscan.py +0 -0
  71. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/integrity.py +0 -0
  72. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/journal.py +0 -0
  73. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/lockfile.py +0 -0
  74. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/logs.py +0 -0
  75. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/mcp.py +0 -0
  76. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/minisign.py +0 -0
  77. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/nethttp.py +0 -0
  78. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/output.py +0 -0
  79. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/paths.py +0 -0
  80. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/policy.py +0 -0
  81. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/projectlock.py +0 -0
  82. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/provenance.py +0 -0
  83. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/rag.py +0 -0
  84. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/registry.py +0 -0
  85. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/rules.py +0 -0
  86. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/scopes.py +0 -0
  87. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/secretscan.py +0 -0
  88. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/serve.py +0 -0
  89. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/stackprobe.py +0 -0
  90. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/staleness.py +0 -0
  91. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/store.py +0 -0
  92. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/typosquat.py +0 -0
  93. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/updatediff.py +0 -0
  94. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/util.py +0 -0
  95. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/core/workflows.py +0 -0
  96. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/data/registries.json +0 -0
  97. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/errors.py +0 -0
  98. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_cli/spin.py +0 -0
  99. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_skill_cli.egg-info/SOURCES.txt +0 -0
  100. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
  101. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_skill_cli.egg-info/entry_points.txt +0 -0
  102. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_skill_cli.egg-info/requires.txt +0 -0
  103. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/boost_skill_cli.egg-info/top_level.txt +0 -0
  104. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/.claude/settings.local.json +0 -0
  105. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/DEBUGGING.md +0 -0
  106. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/adapters.html +0 -0
  107. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/commands.html +0 -0
  108. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/demo.gif +0 -0
  109. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/demo.tape +0 -0
  110. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/design-roadmap.html +0 -0
  111. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/eval.html +0 -0
  112. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/index.html +0 -0
  113. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/mcp-hub.html +0 -0
  114. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/rag-architecture.md +0 -0
  115. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D01.md +0 -0
  116. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D02.md +0 -0
  117. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D03.md +0 -0
  118. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D04.md +0 -0
  119. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D05.md +0 -0
  120. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D06.md +0 -0
  121. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D07.md +0 -0
  122. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D08.md +0 -0
  123. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D09.md +0 -0
  124. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D10.md +0 -0
  125. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D11.md +0 -0
  126. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D12.md +0 -0
  127. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D13.md +0 -0
  128. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D14.md +0 -0
  129. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D15.md +0 -0
  130. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D16.md +0 -0
  131. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D17.md +0 -0
  132. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D18.md +0 -0
  133. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D19.md +0 -0
  134. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D20.md +0 -0
  135. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D21.md +0 -0
  136. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D22.md +0 -0
  137. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D23.md +0 -0
  138. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D24.md +0 -0
  139. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D25.md +0 -0
  140. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D26.md +0 -0
  141. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
  142. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
  143. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
  144. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
  145. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/boost-run-live-agents.md +0 -0
  146. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
  147. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
  148. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
  149. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
  150. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
  151. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
  152. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
  153. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/command-reference-docs-site.md +0 -0
  154. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
  155. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
  156. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
  157. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
  158. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
  159. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
  160. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
  161. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
  162. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
  163. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
  164. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
  165. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
  166. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
  167. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
  168. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/framework-adapter-multi-agent.md +0 -0
  169. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
  170. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
  171. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
  172. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
  173. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
  174. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/html-validation-html-validate.md +0 -0
  175. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/install-scope-user-or-project.md +0 -0
  176. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
  177. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
  178. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
  179. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
  180. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
  181. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
  182. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
  183. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
  184. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
  185. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
  186. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
  187. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
  188. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
  189. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
  190. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/mcp-search-before-reinventing.md +0 -0
  191. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
  192. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
  193. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
  194. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
  195. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
  196. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
  197. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
  198. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
  199. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
  200. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
  201. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
  202. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/pin-the-lint-toolchain.md +0 -0
  203. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
  204. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
  205. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/project-scope-across-every-command.md +0 -0
  206. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/project-scope-symlink-escape-on-write.md +0 -0
  207. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
  208. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
  209. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
  210. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
  211. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
  212. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
  213. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
  214. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
  215. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
  216. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
  217. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
  218. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
  219. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
  220. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
  221. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
  222. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
  223. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
  224. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
  225. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
  226. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
  227. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
  228. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
  229. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
  230. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
  231. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
  232. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
  233. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
  234. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
  235. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
  236. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
  237. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
  238. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
  239. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/typo-detection-codespell.md +0 -0
  240. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
  241. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
  242. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
  243. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/update-diff-before-apply.md +0 -0
  244. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
  245. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
  246. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
  247. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
  248. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
  249. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
  250. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
  251. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/docs/roadmap/items/workspace-scope-install.md +0 -0
  252. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/eslint.config.mjs +0 -0
  253. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/examples/README.md +0 -0
  254. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/examples/adapt-demo.sh +0 -0
  255. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/examples/boost-run-prototype.sh +0 -0
  256. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/index.html +0 -0
  257. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/noxfile.py +0 -0
  258. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/pyproject.toml +0 -0
  259. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/requirements/lint-tools.txt +0 -0
  260. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/scripts/bench_cli.sh +0 -0
  261. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/scripts/build_command_reference.py +0 -0
  262. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/scripts/build_registries.py +0 -0
  263. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/scripts/build_roadmap.py +0 -0
  264. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/scripts/check_anchors.py +0 -0
  265. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/scripts/ensure_eval_corpus.sh +0 -0
  266. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/scripts/eval_explain.py +0 -0
  267. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/scripts/eval_recommend.py +0 -0
  268. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/scripts/eval_retrieval.py +0 -0
  269. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/scripts/eval_stats_summary.py +0 -0
  270. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/scripts/import_budget.py +0 -0
  271. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/scripts/mutation_gate.py +0 -0
  272. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/scripts/perf_gate.py +0 -0
  273. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/setup.cfg +0 -0
  274. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/style/README.md +0 -0
  275. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/style/boost.css +0 -0
  276. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/style/boost.js +0 -0
  277. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/style/demo.html +0 -0
  278. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/bdd/features/adapt.feature +0 -0
  279. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/bdd/features/browse.feature +0 -0
  280. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/bdd/features/count.feature +0 -0
  281. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/bdd/features/discover.feature +0 -0
  282. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/bdd/features/doctor.feature +0 -0
  283. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/bdd/features/environment.py +0 -0
  284. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/bdd/features/explain.feature +0 -0
  285. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/bdd/features/index.feature +0 -0
  286. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/bdd/features/install.feature +0 -0
  287. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/bdd/features/list.feature +0 -0
  288. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/bdd/features/mcp.feature +0 -0
  289. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/bdd/features/search.feature +0 -0
  290. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/bdd/features/steps/cli_steps.py +0 -0
  291. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/bdd/features/steps/discovery_steps.py +0 -0
  292. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/bdd/features/steps/mcp_steps.py +0 -0
  293. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/bdd/features/steps/quality_steps.py +0 -0
  294. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/conftest.py +0 -0
  295. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/eval/baseline.json +0 -0
  296. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/eval/explain.jsonl +0 -0
  297. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/eval/golden.jsonl +0 -0
  298. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/eval/recommend.jsonl +0 -0
  299. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/eval/taps.txt +0 -0
  300. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_capabilities_policy.py +0 -0
  301. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_cli_adapt.py +0 -0
  302. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_cli_bmad.py +0 -0
  303. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_cli_configuration.py +0 -0
  304. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_cli_discovery.py +0 -0
  305. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_cli_hooks.py +0 -0
  306. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_cli_info.py +0 -0
  307. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_cli_intelligence.py +0 -0
  308. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_cli_pkg.py +0 -0
  309. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_cli_quality.py +0 -0
  310. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_cli_taps.py +0 -0
  311. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_cli_team.py +0 -0
  312. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_everyday_loop.py +0 -0
  313. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_integrity_enforce.py +0 -0
  314. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_property_parsers.py +0 -0
  315. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_run.py +0 -0
  316. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_tap_signing.py +0 -0
  317. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/functional/test_workspace_scope.py +0 -0
  318. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/make_fixture.py +0 -0
  319. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/perf/test_benchmarks.py +0 -0
  320. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/smoke.sh +0 -0
  321. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_adapters.py +0 -0
  322. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_adapters_multi.py +0 -0
  323. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_adapters_runner.py +0 -0
  324. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_capabilities.py +0 -0
  325. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_check_anchors.py +0 -0
  326. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_claude_settings.py +0 -0
  327. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_cliparse.py +0 -0
  328. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_command_reference_fresh.py +0 -0
  329. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_dense.py +0 -0
  330. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_dense_fallback.py +0 -0
  331. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_docs_pages_linked.py +0 -0
  332. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_ed25519.py +0 -0
  333. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_embed.py +0 -0
  334. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_errors_and_cli_table.py +0 -0
  335. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_eval_stats_summary.py +0 -0
  336. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_faithfulness.py +0 -0
  337. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_frontmatter.py +0 -0
  338. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_gitleaks_config.py +0 -0
  339. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_gitutil.py +0 -0
  340. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_imperative.py +0 -0
  341. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_import_budget.py +0 -0
  342. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_injectscan.py +0 -0
  343. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_integrity.py +0 -0
  344. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_journal.py +0 -0
  345. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_logs.py +0 -0
  346. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_mcp.py +0 -0
  347. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_minisign.py +0 -0
  348. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_mutation_hardening.py +0 -0
  349. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_nethttp.py +0 -0
  350. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_perf_gate.py +0 -0
  351. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_pkg_confusions.py +0 -0
  352. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_pkg_injection.py +0 -0
  353. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_pkg_secrets.py +0 -0
  354. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_projectlock.py +0 -0
  355. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_provenance.py +0 -0
  356. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_rag.py +0 -0
  357. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_registries_fresh.py +0 -0
  358. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_roadmap_fresh.py +0 -0
  359. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_rules.py +0 -0
  360. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_scopes.py +0 -0
  361. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_secretscan.py +0 -0
  362. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_serve.py +0 -0
  363. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_spin.py +0 -0
  364. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_stackprobe.py +0 -0
  365. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_staleness.py +0 -0
  366. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_store.py +0 -0
  367. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_token_parity.py +0 -0
  368. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_typosquat.py +0 -0
  369. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_updatediff.py +0 -0
  370. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_version.py +0 -0
  371. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/unit/test_workflows.py +0 -0
  372. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/visual/package.json +0 -0
  373. {boost_skill_cli-1.0.200 → boost_skill_cli-1.0.201}/tests/visual/visual_check.mjs +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.200
3
+ Version: 1.0.201
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.200'
22
- __version_tuple__ = version_tuple = (1, 0, 200)
21
+ __version__ = version = '1.0.201'
22
+ __version_tuple__ = version_tuple = (1, 0, 201)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.200
3
+ Version: 1.0.201
4
4
  Summary: boost — Homebrew for AI coding skills
5
5
  Author: Jonathan Reyes
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -0,0 +1,31 @@
1
+ ---
2
+ id: finish-mutation-hardening-across-core
3
+ board: code
4
+ section: planned
5
+ status: shipped
6
+ category: Testing
7
+ complexity: L
8
+ impact: Med
9
+ wow: 2
10
+ note: behavioral gaps closed
11
+ order: 1
12
+ owner: loop/mutation-hardening
13
+ pr: 225
14
+ title: Finish mutation hardening across <code>core/</code>
15
+ ---
16
+ Audited the surviving mutants across all ten listed modules — catalog, util,
17
+ ai, registry, lockfile, policy, config, output, agents, paths — and
18
+ killed every one that reflected a real behavioral coverage gap: the
19
+ <code>search</code> desc-bonus accumulation and <code>classify_workflow</code>
20
+ signature logic; <code>score_skill</code> signal detection and the
21
+ <code>rel_time</code> bucket boundaries; <code>registry.remove</code> keeping
22
+ other taps; a 3-level <code>config.unset</code> slicing bug; the untested
23
+ <code>lockfile.remove_rule</code>/<code>remove_workflow</code> returns and
24
+ corrupt-history skip; the entirely-untested <code>policy.check_capabilities</code>;
25
+ and <code>confirm()</code>'s safe default. The residual survivors are
26
+ <b>equivalent mutants</b> — encoding defaults, macOS case-folding (killed
27
+ on CI's Linux runner), <code>+=</code> vs <code>=</code> on a zero-init score,
28
+ <code>//</code> vs <code>/</code> under <code>%d</code>, dead defensive defaults
29
+ carried by <code>DEFAULTS</code>, and test-double-stubbed plumbing kwargs —
30
+ none of which represents a missing assertion. The required mutation gate
31
+ stays green with margin.
@@ -459,17 +459,29 @@ message, so routing it through the helper would change user-facing errors.</p>
459
459
 
460
460
  <!-- ROADMAP:cards section=planned -->
461
461
  <article class="cap rcard">
462
- <div class="head"><span class="pill planned">Planned</span><span class="cat">Testing</span></div>
462
+ <div class="head"><span class="pill shipped">Shipped</span><span class="cat">Testing</span></div>
463
463
  <h3>Finish mutation hardening across <code>core/</code></h3>
464
- <p>Work down the remaining survivor counts, biggest first: catalog&nbsp;(27),
465
- util&nbsp;(26), ai&nbsp;(21), registry&nbsp;(20), lockfile&nbsp;(13),
466
- policy&nbsp;(12), config&nbsp;(9), output&nbsp;(8), agents&nbsp;(6),
467
- paths&nbsp;(4).</p>
464
+ <p>Audited the surviving mutants across all ten listed modules — catalog, util,
465
+ ai, registry, lockfile, policy, config, output, agents, paths — and
466
+ killed every one that reflected a real behavioral coverage gap: the
467
+ <code>search</code> desc-bonus accumulation and <code>classify_workflow</code>
468
+ signature logic; <code>score_skill</code> signal detection and the
469
+ <code>rel_time</code> bucket boundaries; <code>registry.remove</code> keeping
470
+ other taps; a 3-level <code>config.unset</code> slicing bug; the untested
471
+ <code>lockfile.remove_rule</code>/<code>remove_workflow</code> returns and
472
+ corrupt-history skip; the entirely-untested <code>policy.check_capabilities</code>;
473
+ and <code>confirm()</code>'s safe default. The residual survivors are
474
+ <b>equivalent mutants</b> — encoding defaults, macOS case-folding (killed
475
+ on CI's Linux runner), <code>+=</code> vs <code>=</code> on a zero-init score,
476
+ <code>//</code> vs <code>/</code> under <code>%d</code>, dead defensive defaults
477
+ carried by <code>DEFAULTS</code>, and test-double-stubbed plumbing kwargs —
478
+ none of which represents a missing assertion. The required mutation gate
479
+ stays green with margin.</p>
468
480
  <div class="meta">
469
481
  <span class="m">Complexity <b>L</b></span>
470
482
  <span class="m">Impact <b>Med</b></span>
471
483
  <span class="m">Wow <b class="wow">★★</b></span>
472
- <span class="m">~146 survivors</span>
484
+ <span class="m">behavioral gaps closed</span>
473
485
  </div>
474
486
  </article>
475
487
 
@@ -72,3 +72,10 @@ class TestEnsureAgentDirs:
72
72
  assert (sandbox / ".claude" / "skills").is_dir()
73
73
  assert (sandbox / ".windsurf" / "skills").is_dir()
74
74
  assert not (sandbox / ".cursor" / "skills").exists()
75
+
76
+ def test_is_idempotent_when_dirs_exist(self, sandbox):
77
+ # a second call over already-existing dirs must not raise — pins
78
+ # exist_ok=True (a False/dropped flag would raise FileExistsError).
79
+ agents.ensure_agent_dirs()
80
+ agents.ensure_agent_dirs()
81
+ assert (sandbox / ".claude" / "skills").is_dir()
@@ -202,7 +202,9 @@ class TestAskApi:
202
202
  monkeypatch.setenv("ANTHROPIC_API_KEY", "sekret")
203
203
  captured = _with_api(monkeypatch, {"content": [{"type": "text", "text": "x"}]})
204
204
  assert ai.ask("p") == "x"
205
- assert "system" not in json.loads(captured["req"].data.decode())
205
+ body = json.loads(captured["req"].data.decode())
206
+ assert "system" not in body
207
+ assert body["max_tokens"] == 1500 # the ask() default budget (pins 1500)
206
208
 
207
209
  def test_api_urlerror_returns_none(self, ai_on, monkeypatch):
208
210
  _without_cli(monkeypatch)
@@ -226,6 +228,7 @@ class TestAskAuthor:
226
228
  assert ai.ask_author("p", system="s") == "authored"
227
229
  assert calls[0]["cmd"][2:4] == ["--model", AUTHOR_MODEL]
228
230
  assert calls[0]["cmd"][-2:] == ["--append-system-prompt", "s"]
231
+ assert calls[0]["input"] == "p" # the prompt is forwarded, not dropped
229
232
  assert calls[0]["timeout"] == 240
230
233
 
231
234
  def test_author_api_max_tokens(self, ai_on, monkeypatch):
@@ -287,6 +287,26 @@ class TestScanRulesAndWorkflows:
287
287
  # a bare prompt .md with no dir marker and no subagent frontmatter
288
288
  assert catalog._classify_workflow(Path("prompts/idea.md"), {}) is False
289
289
 
290
+ def test_classify_workflow_signature_needs_name_and_description(self):
291
+ # Outside a workflow dir, the frontmatter signature requires BOTH a name
292
+ # AND a description AND a workflow meta key. (Pins the `and` between
293
+ # name/description — an `or` would classify a name-only file.)
294
+ loose = Path("prompts/agent.md")
295
+ full = {"name": "a", "description": "d", "tools": ["x"]}
296
+ assert catalog._classify_workflow(loose, full) is True
297
+ assert catalog._classify_workflow(loose, {"name": "a", "tools": ["x"]}) is False
298
+ assert catalog._classify_workflow(
299
+ loose, {"description": "d", "tools": ["x"]}) is False
300
+
301
+ def test_classify_workflow_signature_needs_a_workflow_meta_key(self):
302
+ # name+description alone do NOT make a loose .md a workflow — it needs one
303
+ # of the subagent/slash-command keys. (Pins `WORKFLOW_META_KEYS & set` —
304
+ # a `|` would make the set truthy for any frontmatter.)
305
+ loose = Path("prompts/agent.md")
306
+ assert catalog._classify_workflow(loose, {"name": "a", "description": "d"}) is False
307
+ assert catalog._classify_workflow(
308
+ loose, {"name": "a", "description": "d", "model": "opus"}) is True
309
+
290
310
  def test_mixed_kinds_all_present(self, tmp_path):
291
311
  root = tmp_path / "tap"
292
312
  write_skill(root / "skills" / "s", "---\nname: s\n---")
@@ -445,6 +465,16 @@ class TestResolveOne:
445
465
  assert ei.value.message == "no skill named 'brainstorm' in any tap"
446
466
  assert ei.value.hint == "closest matches: brainstorming"
447
467
 
468
+ def test_miss_hint_caps_at_three_joined_by_comma(self, sandbox):
469
+ # Five near-matches, but the hint lists exactly the top THREE, comma-
470
+ # joined. (Pins `search(name)[:3]` and the `", "` join separator.)
471
+ _fake_taps(("t", [_entry("planner-%d" % i, "t") for i in range(5)]))
472
+ with pytest.raises(BoostError) as ei:
473
+ catalog.resolve_one("planner")
474
+ listed = ei.value.hint.replace("closest matches: ", "").split(", ")
475
+ assert len(listed) == 3
476
+ assert all(n.startswith("planner-") for n in listed)
477
+
448
478
  def test_miss_no_close_match_no_hint(self, sandbox):
449
479
  _fake_taps(("t", [_entry("brainstorming", "t")]))
450
480
  with pytest.raises(BoostError) as ei:
@@ -525,6 +555,16 @@ class TestSearchRanking:
525
555
  assert [(m["name"], s) for m, s in catalog.search("planning", entries=[e])] \
526
556
  == [("x", 2)]
527
557
 
558
+ def test_desc_bonus_adds_to_name_score_not_replaces(self):
559
+ # An entry that matches BOTH the name and the description must accrue the
560
+ # description bonus (+30) ON TOP of the name-tier score, never reset to
561
+ # it. name "fmt-tool" starts-with "fmt" (+80) + token "fmt" in name (+12)
562
+ # + desc "a fmt helper" contains "fmt" (+30) + token in desc (+6) + token
563
+ # in blob (+2) = 130. (Pins `score += 30`, not `score = 30`.)
564
+ e = _entry("fmt-tool", "t", desc="a fmt helper")
565
+ assert [(m["name"], s) for m, s in catalog.search("fmt", entries=[e])] \
566
+ == [("fmt-tool", 130)]
567
+
528
568
 
529
569
  class TestMetaText:
530
570
  def test_flattens_keys_and_values_lowercased(self):
@@ -80,6 +80,15 @@ class TestSaveRoundtrip:
80
80
  assert json.loads(raw) == {"a": 1}
81
81
  assert raw.endswith("\n")
82
82
 
83
+ def test_save_is_pretty_printed_and_preserves_key_order(self, sandbox):
84
+ # 2-space indent and insertion order (sort_keys=False) — the config file
85
+ # is human-edited, so it must stay readable and stable, not compacted or
86
+ # alphabetized. Pins indent=2 and sort_keys=False.
87
+ config.save({"zeta": 1, "alpha": 2})
88
+ raw = paths.config_path().read_text(encoding="utf-8")
89
+ assert '\n "zeta": 1' in raw # 2-space indent, not compact
90
+ assert raw.index('"zeta"') < raw.index('"alpha"') # insertion, not sorted
91
+
83
92
 
84
93
  class TestCaching:
85
94
  def test_reads_only_once_when_file_unchanged(self, sandbox, monkeypatch):
@@ -198,6 +207,15 @@ class TestUnset:
198
207
  assert config.unset("never.was.here") is False
199
208
  assert config.unset("absent_top") is False
200
209
 
210
+ def test_unset_deeply_nested_key_targets_the_leaf(self, sandbox):
211
+ # a 3-level key exercises the parent-walk `parts[:-1]` and leaf `parts[-1]`
212
+ # correctly — a 2-level key can't tell them from `parts[:1]` / `parts[1]`.
213
+ cfg = config.load()
214
+ cfg["deep"] = {"mid": {"leaf": 1, "keep": 2}}
215
+ config.save(cfg)
216
+ assert config.unset("deep.mid.leaf") is True
217
+ assert config.load()["deep"]["mid"] == {"keep": 2} # only leaf removed
218
+
201
219
  def test_path_through_scalar_returns_false(self, sandbox):
202
220
  assert config.unset("ai.model.sub") is False
203
221
 
@@ -182,3 +182,33 @@ class TestHistory:
182
182
  lockfile.history_read("20990101T000000Z")
183
183
  assert ei.value.message == "no lock history entry 20990101T000000Z"
184
184
  assert ei.value.hint == "list entries with `boost replay`"
185
+
186
+ def test_history_list_skips_corrupt_without_stopping(self, sandbox):
187
+ # a corrupt snapshot that sorts BEFORE a valid one must be skipped, not
188
+ # halt the scan — pins the `continue` (a `break` would drop the later
189
+ # valid entry). The seed in _seed_history can't catch this because its
190
+ # corrupt file is newest, hence last.
191
+ paths.ensure_dirs()
192
+ d = paths.lock_history_dir()
193
+ (d / "lock-20200101T000000Z.json").write_text("not json", encoding="utf-8")
194
+ (d / "lock-20200102T000000Z.json").write_text(
195
+ json.dumps({"updated": "v", "skills": {"x": {}}}), encoding="utf-8")
196
+ assert [e["id"] for e in lockfile.history_list()] == ["20200102T000000Z"]
197
+
198
+
199
+ class TestRulesAndWorkflows:
200
+ def test_rule_roundtrip_and_remove(self, sandbox):
201
+ lockfile.set_rule("r", {"v": "1"})
202
+ assert lockfile.get_rule("r") == {"v": "1"}
203
+ assert lockfile.installed_rules() == {"r": {"v": "1"}}
204
+ assert lockfile.remove_rule("r") is True # present -> True
205
+ assert lockfile.get_rule("r") is None
206
+ assert lockfile.remove_rule("r") is False # absent -> False
207
+
208
+ def test_workflow_roundtrip_and_remove(self, sandbox):
209
+ lockfile.set_workflow("w", {"v": "2"})
210
+ assert lockfile.get_workflow("w") == {"v": "2"}
211
+ assert lockfile.installed_workflows() == {"w": {"v": "2"}}
212
+ assert lockfile.remove_workflow("w") is True # present -> True
213
+ assert lockfile.get_workflow("w") is None
214
+ assert lockfile.remove_workflow("w") is False # absent -> False
@@ -844,6 +844,12 @@ class TestConfirm:
844
844
  monkeypatch.setattr(sys, "stdin", FakeStream(tty=False))
845
845
  assert output.confirm("go?", default=False) is False
846
846
 
847
+ def test_default_is_false_when_unspecified(self, monkeypatch):
848
+ # safety: with no explicit default, an unattended (non-tty) confirm must
849
+ # NOT proceed — pins the `default: bool = False` signature default.
850
+ monkeypatch.setattr(sys, "stdin", FakeStream(tty=False))
851
+ assert output.confirm("delete everything?") is False
852
+
847
853
  def _tty(self, monkeypatch, answer):
848
854
  monkeypatch.setattr(sys, "stdin", FakeStream(tty=True))
849
855
  prompts = []
@@ -143,6 +143,19 @@ class TestRepoRoot:
143
143
  assert root == Path(paths.__file__).resolve().parent.parent.parent
144
144
 
145
145
 
146
+ class TestPackageAndStatePaths:
147
+ def test_package_root_is_the_boost_cli_dir(self):
148
+ root = paths.package_root()
149
+ assert root.name == "boost_cli"
150
+ assert (root / "core" / "paths.py").is_file()
151
+ assert root == Path(paths.__file__).resolve().parent.parent
152
+
153
+ def test_trusted_keys_path_name_and_location(self, sandbox):
154
+ p = paths.trusted_keys_path()
155
+ assert p.name == "trusted_keys.json"
156
+ assert p.parent == paths.state_dir()
157
+
158
+
146
159
  class TestLauncher:
147
160
  def test_prefers_console_script_on_path(self, monkeypatch):
148
161
  monkeypatch.setattr("boost_cli.core.paths.shutil.which",
@@ -153,6 +153,41 @@ class TestCheckInstall:
153
153
  assert policy.check_install({}, 0) == []
154
154
 
155
155
 
156
+ class TestCheckCapabilities:
157
+ def test_declared_denied_capability_violates(self, sandbox):
158
+ set_policy(denied_capabilities=["network"])
159
+ v = policy.check_capabilities({"capabilities": ["network"]}, "body")
160
+ assert v == ["declares the 'network' capability, denied by policy"]
161
+
162
+ def test_declared_but_not_denied_is_allowed(self, sandbox):
163
+ set_policy(denied_capabilities=["shell"])
164
+ assert policy.check_capabilities({"capabilities": ["network"]}, "body") == []
165
+
166
+ def test_empty_denylist_short_circuits(self, sandbox):
167
+ # no denied capabilities -> allowed regardless of what the skill declares
168
+ set_policy(denied_capabilities=[])
169
+ assert policy.check_capabilities({"capabilities": ["network", "shell"]}, "x") == []
170
+
171
+ def test_master_switch_bypasses(self, sandbox):
172
+ set_policy(denied_capabilities=["network"])
173
+ cfg = config.load()
174
+ cfg["policy_enforce"] = False
175
+ config.save(cfg)
176
+ assert policy.check_capabilities({"capabilities": ["network"]}, "body") == []
177
+
178
+ def test_detected_only_needs_strict_flag(self, sandbox):
179
+ # a body that *looks* like it uses the network but doesn't declare it:
180
+ # denied, yet only enforced when enforce_detected_capabilities is on.
181
+ body = "import requests\nrequests.get('https://example.com')\n"
182
+ set_policy(denied_capabilities=["network"],
183
+ enforce_detected_capabilities=False)
184
+ assert policy.check_capabilities({}, body) == []
185
+ set_policy(denied_capabilities=["network"],
186
+ enforce_detected_capabilities=True)
187
+ v = policy.check_capabilities({}, body)
188
+ assert v == ["looks like it uses 'network' (detected), denied by policy"]
189
+
190
+
156
191
  class TestCheckTapSigning:
157
192
  def test_off_by_default(self, sandbox, tmp_path):
158
193
  clone = tmp_path / "c"
@@ -207,6 +207,19 @@ class TestAddRemove:
207
207
  assert not tap.cache_file.exists()
208
208
  assert config.get("taps") == []
209
209
 
210
+ def test_remove_only_drops_the_named_tap(self, sandbox):
211
+ # Removing one of several taps must leave the others in config. Pins the
212
+ # `cfg["taps"] = [t ... if t["name"] != tap.name]` rewrite and its
213
+ # `config.save(cfg)` — a wrong key, empty default, or save(None) would
214
+ # blow away the survivors instead of keeping them.
215
+ cfg = config.load()
216
+ cfg["taps"] = [{"name": "one", "url": "u1", "curated": False},
217
+ {"name": "two", "url": "u2", "curated": False},
218
+ {"name": "three", "url": "u3", "curated": False}]
219
+ config.save(cfg)
220
+ registry.remove("two")
221
+ assert [t["name"] for t in config.get("taps")] == ["one", "three"]
222
+
210
223
  def test_remove_unknown_raises(self, sandbox):
211
224
  with pytest.raises(BoostError):
212
225
  registry.remove("nope")
@@ -73,6 +73,22 @@ class TestRelTime:
73
73
  def test_55_days_is_seven_weeks(self):
74
74
  assert util.rel_time(iso_ago(55 * 86400)) == "7w ago"
75
75
 
76
+ def test_exactly_60_seconds_rolls_to_minutes(self):
77
+ # the seconds bucket is `secs < 60`; at 60 it must roll to minutes.
78
+ # (Pins the 60 boundary literal — a 61 would keep it "60s ago".)
79
+ assert util.rel_time(iso_ago(60)) == "1m ago"
80
+
81
+ def test_exactly_3600_seconds_rolls_to_hours(self):
82
+ # the minutes bucket is `secs < 3600`; at one hour it rolls to hours.
83
+ # (Pins the 3600 boundary — a 3601 would say "60m ago".)
84
+ assert util.rel_time(iso_ago(3600)) == "1h ago"
85
+
86
+ def test_60_days_is_absolute_date_not_weeks(self):
87
+ # past the `secs < 604800 * 8` (eight-week) cutoff, output is a date, not
88
+ # "8w ago". (Pins the *8 multiplier — a *9 would extend weeks to 60 days.)
89
+ then = datetime.now(timezone.utc) - timedelta(days=60)
90
+ assert util.rel_time(then.strftime(ISO_FMT)) == then.strftime("%Y-%m-%d")
91
+
76
92
  def test_100_days_is_absolute_date(self):
77
93
  then = datetime.now(timezone.utc) - timedelta(days=100)
78
94
  assert util.rel_time(then.strftime(ISO_FMT)) == then.strftime("%Y-%m-%d")
@@ -377,6 +393,62 @@ class TestScoreSkill:
377
393
  d = make_skill(tmp_path, text)
378
394
  assert util.score_skill(d) == (95, [])
379
395
 
396
+ def test_48001_chars_is_penalized(self, tmp_path):
397
+ # one char over the 48_000 cutoff (`> 48_000`) crosses into the penalty;
398
+ # pins the boundary against a `> 48_001` off-by-one.
399
+ base = full_text()
400
+ text = base + "P" * (48_001 - len(base))
401
+ assert len(text) == 48_001
402
+ d = make_skill(tmp_path, text)
403
+ score, notes = util.score_skill(d)
404
+ assert score == 85
405
+ assert "very large SKILL.md (>48KB) — consider splitting" in notes
406
+
407
+ def test_heading_on_a_later_line_still_counts(self, tmp_path):
408
+ # the heading probe uses re.MULTILINE, so a heading below the first line
409
+ # must still register (no "no markdown headings" note). Pins re.M — a
410
+ # dropped flag would only match a heading at the very start of the body.
411
+ body = ("Intro prose that runs on for a while so the body clears the two "
412
+ "hundred character minimum comfortably and then some more.\n\n"
413
+ "## Later Heading\n\n- a bullet keeps the examples check happy.\n")
414
+ d = make_skill(tmp_path, full_text(body=body))
415
+ _score, notes = util.score_skill(d)
416
+ assert "no markdown headings in body" not in notes
417
+
418
+ def test_code_fence_alone_satisfies_examples(self, tmp_path):
419
+ # a ``` fence with NO numbered list and NO bullet must satisfy the
420
+ # examples check. Pins the leading `"```" in body or ...` term (an `and`
421
+ # or a corrupted literal would demand a list too).
422
+ body = ("# Heading\n\nProse padding to exceed two hundred characters so the "
423
+ "length bonus applies and nothing else trips a note here today.\n\n"
424
+ "```bash\necho hello\n```\n")
425
+ d = make_skill(tmp_path, full_text(body=body))
426
+ _score, notes = util.score_skill(d)
427
+ assert "no examples, steps, or code blocks" not in notes
428
+
429
+ def test_numbered_list_below_first_line_satisfies_examples(self, tmp_path):
430
+ # a numbered list (not on the first line, no fence, no bullet) satisfies
431
+ # the examples check via re.MULTILINE. Pins the `^\d+\. ` probe + its flag.
432
+ body = ("# Heading\n\nSome prose padding to comfortably exceed the two "
433
+ "hundred character minimum for the length bonus to apply now.\n\n"
434
+ "1. The first and only concrete step in this body.\n")
435
+ d = make_skill(tmp_path, full_text(body=body))
436
+ _score, notes = util.score_skill(d)
437
+ assert "no examples, steps, or code blocks" not in notes
438
+
439
+ def test_license_file_on_disk_adds_five_over_a_plain_extra(self, tmp_path):
440
+ # a LICENSE *file* (not just frontmatter) earns the license +5 on top of
441
+ # the extras +5 any sidecar earns. Isolating vs a plain extra pins the
442
+ # "LICENSE" filename literal against a corrupted/renamed check.
443
+ # minimal bodies keep both scores well below the 100 cap so the +5 shows
444
+ (tmp_path / "a").mkdir()
445
+ (tmp_path / "b").mkdir()
446
+ licensed = make_skill(tmp_path / "a", "hi",
447
+ extra_files={"LICENSE": "MIT\n"})
448
+ plain = make_skill(tmp_path / "b", "hi",
449
+ extra_files={"notes.md": "x\n"})
450
+ assert util.score_skill(licensed)[0] - util.score_skill(plain)[0] == 5
451
+
380
452
 
381
453
  class TestAtomicWriteText:
382
454
  def test_writes_content(self, tmp_path):
@@ -1,19 +0,0 @@
1
- ---
2
- id: finish-mutation-hardening-across-core
3
- board: code
4
- section: planned
5
- status: planned
6
- category: Testing
7
- complexity: L
8
- impact: Med
9
- wow: 2
10
- note: ~146 survivors
11
- order: 1
12
- owner:
13
- pr:
14
- title: Finish mutation hardening across <code>core/</code>
15
- ---
16
- Work down the remaining survivor counts, biggest first: catalog&nbsp;(27),
17
- util&nbsp;(26), ai&nbsp;(21), registry&nbsp;(20), lockfile&nbsp;(13),
18
- policy&nbsp;(12), config&nbsp;(9), output&nbsp;(8), agents&nbsp;(6),
19
- paths&nbsp;(4).