boost-skill-cli 1.0.263__tar.gz → 1.0.265__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 (503) hide show
  1. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/PKG-INFO +1 -1
  2. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/_version.py +2 -2
  3. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/commands/info.py +21 -1
  4. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/config.py +4 -0
  5. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/logs.py +66 -8
  6. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_skill_cli.egg-info/PKG-INFO +1 -1
  7. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/DEBUGGING.md +28 -0
  8. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/build_roadmap.py +51 -9
  9. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_logs.py +140 -0
  10. boost_skill_cli-1.0.265/tests/unit/test_roadmap_fresh.py +151 -0
  11. boost_skill_cli-1.0.263/tests/unit/test_roadmap_fresh.py +0 -86
  12. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/.gitattributes +0 -0
  13. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/.gitignore +0 -0
  14. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/.gitleaks.toml +0 -0
  15. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/.htmlvalidate.json +0 -0
  16. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/.lighthouserc.json +0 -0
  17. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/.lycheeignore +0 -0
  18. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/.markdownlint-cli2.jsonc +0 -0
  19. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/.pre-commit-config.yaml +0 -0
  20. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/.stylelintrc.json +0 -0
  21. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/.vale/styles/boost/Terminology.yml +0 -0
  22. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/.vale/styles/config/vocabularies/boost/accept.txt +0 -0
  23. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/.vale.ini +0 -0
  24. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/CLAUDE.md +0 -0
  25. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/CODE_OF_CONDUCT.md +0 -0
  26. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/CONTRIBUTING.md +0 -0
  27. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/LICENSE +0 -0
  28. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/MANIFEST.in +0 -0
  29. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/Makefile +0 -0
  30. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/README.md +0 -0
  31. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/SECURITY.md +0 -0
  32. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost +0 -0
  33. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/__init__.py +0 -0
  34. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/__main__.py +0 -0
  35. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/cli.py +0 -0
  36. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/cliparse.py +0 -0
  37. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/commands/__init__.py +0 -0
  38. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/commands/_common.py +0 -0
  39. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/commands/bmad.py +0 -0
  40. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/commands/configuration.py +0 -0
  41. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/commands/discovery.py +0 -0
  42. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/commands/hooks.py +0 -0
  43. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/commands/intelligence.py +0 -0
  44. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/commands/pkg.py +0 -0
  45. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/commands/quality.py +0 -0
  46. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/commands/run.py +0 -0
  47. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/commands/safety.py +0 -0
  48. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/commands/taps.py +0 -0
  49. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/commands/team.py +0 -0
  50. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/__init__.py +0 -0
  51. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/adapters.py +0 -0
  52. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/agents.py +0 -0
  53. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/ai.py +0 -0
  54. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/capabilities.py +0 -0
  55. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/catalog.py +0 -0
  56. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/claude_settings.py +0 -0
  57. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/dense.py +0 -0
  58. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/ed25519.py +0 -0
  59. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/embed.py +0 -0
  60. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/faithfulness.py +0 -0
  61. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/frontmatter.py +0 -0
  62. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/gitutil.py +0 -0
  63. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/imperative.py +0 -0
  64. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/injectscan.py +0 -0
  65. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/integrity.py +0 -0
  66. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/journal.py +0 -0
  67. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/lockfile.py +0 -0
  68. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/mcp.py +0 -0
  69. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/mcpdecl.py +0 -0
  70. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/minisign.py +0 -0
  71. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/nethttp.py +0 -0
  72. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/output.py +0 -0
  73. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/paths.py +0 -0
  74. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/policy.py +0 -0
  75. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/projectlock.py +0 -0
  76. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/provenance.py +0 -0
  77. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/rag.py +0 -0
  78. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/registry.py +0 -0
  79. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/resolve.py +0 -0
  80. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/rules.py +0 -0
  81. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/scopes.py +0 -0
  82. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/secretscan.py +0 -0
  83. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/selfupdate.py +0 -0
  84. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/serve.py +0 -0
  85. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/stackprobe.py +0 -0
  86. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/staleness.py +0 -0
  87. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/store.py +0 -0
  88. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/trustaudit.py +0 -0
  89. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/typosquat.py +0 -0
  90. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/updatediff.py +0 -0
  91. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/util.py +0 -0
  92. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/core/workflows.py +0 -0
  93. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/data/registries.json +0 -0
  94. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/errors.py +0 -0
  95. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_cli/spin.py +0 -0
  96. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_skill_cli.egg-info/SOURCES.txt +0 -0
  97. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
  98. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_skill_cli.egg-info/entry_points.txt +0 -0
  99. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_skill_cli.egg-info/requires.txt +0 -0
  100. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/boost_skill_cli.egg-info/top_level.txt +0 -0
  101. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/codecov.yml +0 -0
  102. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/.claude/settings.local.json +0 -0
  103. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/adapters.html +0 -0
  104. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/carousel/gifs/distill.gif +0 -0
  105. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/carousel/gifs/doctor.gif +0 -0
  106. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/carousel/gifs/explain.gif +0 -0
  107. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/carousel/gifs/hooks.gif +0 -0
  108. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/carousel/gifs/install.gif +0 -0
  109. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/carousel/gifs/pulse.gif +0 -0
  110. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/carousel/gifs/search.gif +0 -0
  111. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/carousel/gifs/tap.gif +0 -0
  112. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/carousel/tapes/distill.tape +0 -0
  113. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/carousel/tapes/doctor.tape +0 -0
  114. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/carousel/tapes/explain.tape +0 -0
  115. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/carousel/tapes/hooks.tape +0 -0
  116. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/carousel/tapes/install.tape +0 -0
  117. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/carousel/tapes/pulse.tape +0 -0
  118. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/carousel/tapes/search.tape +0 -0
  119. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/carousel/tapes/tap.tape +0 -0
  120. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/carousel.html +0 -0
  121. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/commands.html +0 -0
  122. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/demo.gif +0 -0
  123. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/demo.tape +0 -0
  124. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/design-roadmap.html +0 -0
  125. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/eval.html +0 -0
  126. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/index.html +0 -0
  127. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/mcp-hub.html +0 -0
  128. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/rag-architecture.md +0 -0
  129. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D01.md +0 -0
  130. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D02.md +0 -0
  131. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D03.md +0 -0
  132. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D04.md +0 -0
  133. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D05.md +0 -0
  134. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D06.md +0 -0
  135. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D07.md +0 -0
  136. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D08.md +0 -0
  137. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D09.md +0 -0
  138. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D10.md +0 -0
  139. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D11.md +0 -0
  140. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D12.md +0 -0
  141. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D13.md +0 -0
  142. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D14.md +0 -0
  143. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D15.md +0 -0
  144. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D16.md +0 -0
  145. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D17.md +0 -0
  146. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D18.md +0 -0
  147. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D19.md +0 -0
  148. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D20.md +0 -0
  149. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D21.md +0 -0
  150. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D22.md +0 -0
  151. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D23.md +0 -0
  152. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D24.md +0 -0
  153. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D25.md +0 -0
  154. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/BOOST-D26.md +0 -0
  155. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
  156. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/adapter-conformance-langgraph-leg-never-ran.md +0 -0
  157. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/ai-bridge-silent-failure-logging.md +0 -0
  158. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/ambiguous-tap-short-name-resolution.md +0 -0
  159. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
  160. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
  161. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
  162. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/boost-run-live-agents.md +0 -0
  163. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
  164. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
  165. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
  166. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
  167. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
  168. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
  169. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/ci-job-timeout-minutes.md +0 -0
  170. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/ci-summary-step-fails-itself.md +0 -0
  171. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
  172. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/command-carousel-page.md +0 -0
  173. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/command-reference-docs-site.md +0 -0
  174. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
  175. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
  176. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
  177. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
  178. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/crash-listing-branch-untested.md +0 -0
  179. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
  180. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/demo-gif-workflow-has-never-succeeded.md +0 -0
  181. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/dense-search-fallback-and-stale-tap-pruning.md +0 -0
  182. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/dependabot-missing-pip-ecosystem.md +0 -0
  183. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
  184. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/docsite-chrome-and-content-audit.md +0 -0
  185. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
  186. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
  187. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
  188. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
  189. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
  190. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
  191. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
  192. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
  193. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
  194. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/framework-adapter-multi-agent.md +0 -0
  195. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
  196. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
  197. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/github-community-health-files.md +0 -0
  198. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
  199. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
  200. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
  201. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/html-validation-html-validate.md +0 -0
  202. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/install-docs-never-mentioned-upgrading.md +0 -0
  203. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/install-from-path-bypasses-policy-and-pin-checks.md +0 -0
  204. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/install-resolves-skill-dependencies.md +0 -0
  205. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/install-scope-user-or-project.md +0 -0
  206. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/installed-skill-trust-audit.md +0 -0
  207. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
  208. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
  209. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/journal-rotation-race-and-handle-leak.md +0 -0
  210. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
  211. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/license-compliance-scanning.md +0 -0
  212. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
  213. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/lint-tap-misscopes-rule-workflow-entries.md +0 -0
  214. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
  215. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
  216. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/lock-invariant-cannot-parse-extras-pins.md +0 -0
  217. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
  218. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
  219. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
  220. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/main-has-no-branch-protection.md +0 -0
  221. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/main-ruleset-ref-pattern-has-literal-quotes.md +0 -0
  222. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
  223. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
  224. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/markdownlint-lints-the-fuzz-corpus.md +0 -0
  225. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/mcp-aware-skills.md +0 -0
  226. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
  227. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
  228. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
  229. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/mcp-search-before-reinventing.md +0 -0
  230. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
  231. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
  232. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/merge-queue-would-deadlock-most-required-checks.md +0 -0
  233. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
  234. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/mutation-gate-was-the-whole-critical-path.md +0 -0
  235. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
  236. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
  237. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
  238. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/mypy-strict-mode-for-commands.md +0 -0
  239. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/negative-limit-inverts-log-pulse-output.md +0 -0
  240. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/onboard-overwrites-generated-files-without-confirm.md +0 -0
  241. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
  242. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
  243. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
  244. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
  245. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/path-traversal-unsanitized-rule-workflow-name.md +0 -0
  246. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
  247. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/pin-the-lint-toolchain.md +0 -0
  248. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/post-deploy-always-defeated-by-skipped-setup.md +0 -0
  249. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
  250. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
  251. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/project-scope-across-every-command.md +0 -0
  252. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/project-scope-symlink-escape-on-write.md +0 -0
  253. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
  254. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
  255. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
  256. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
  257. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
  258. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/publish-gate-ignores-pip-audit-and-metadata.md +0 -0
  259. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/publish-trigger-was-reachable-from-a-fork.md +0 -0
  260. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/pytest-tmpdir-cve-blocked-by-py39-floor.md +0 -0
  261. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
  262. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
  263. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
  264. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
  265. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/rel-time-tests-race-the-wall-clock.md +0 -0
  266. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/required-checks-can-declare-a-check-that-deadlocks-prs.md +0 -0
  267. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/required-checks-config-drift.md +0 -0
  268. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
  269. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
  270. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/roadmap-html-goes-stale-on-every-rebase.md +0 -0
  271. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
  272. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/ruff-016-widens-the-default-rule-set.md +0 -0
  273. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
  274. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
  275. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
  276. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
  277. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
  278. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/sbom-release-event-never-fires.md +0 -0
  279. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
  280. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/scorecard-findings-triage.md +0 -0
  281. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
  282. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
  283. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
  284. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
  285. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/self-update-broken-for-pip-pipx-installs.md +0 -0
  286. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/serve-py-traversal-guards-untested.md +0 -0
  287. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
  288. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
  289. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
  290. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
  291. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
  292. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
  293. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/structured-json-log-output-mode.md +0 -0
  294. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
  295. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
  296. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/sync-deletes-unowned-broken-symlinks.md +0 -0
  297. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
  298. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
  299. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/typo-detection-codespell.md +0 -0
  300. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
  301. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
  302. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/uninstall-has-no-confirmation-prompt.md +0 -0
  303. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
  304. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/update-diff-before-apply.md +0 -0
  305. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
  306. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/update-reinstall-widens-agent-scope.md +0 -0
  307. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
  308. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
  309. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
  310. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/wire-bdd-suite-into-ci.md +0 -0
  311. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
  312. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
  313. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
  314. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap/items/workspace-scope-install.md +0 -0
  315. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/docs/roadmap.html +0 -0
  316. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/eslint.config.mjs +0 -0
  317. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/examples/README.md +0 -0
  318. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/examples/adapt-demo.sh +0 -0
  319. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/examples/boost-run-prototype.sh +0 -0
  320. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/index.html +0 -0
  321. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/noxfile.py +0 -0
  322. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/pyproject.toml +0 -0
  323. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/requirements/coverage-tools.in +0 -0
  324. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/requirements/coverage-tools.txt +0 -0
  325. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/requirements/lint-tools.in +0 -0
  326. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/requirements/lint-tools.txt +0 -0
  327. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/requirements/mutation-tools.in +0 -0
  328. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/requirements/mutation-tools.txt +0 -0
  329. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/requirements/release-tools.in +0 -0
  330. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/requirements/release-tools.txt +0 -0
  331. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/requirements/test-tools.in +0 -0
  332. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/requirements/test-tools.txt +0 -0
  333. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/a11y_check.py +0 -0
  334. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/bench_cli.sh +0 -0
  335. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/build_command_reference.py +0 -0
  336. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/build_registries.py +0 -0
  337. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/check_anchors.py +0 -0
  338. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/check_required_checks.py +0 -0
  339. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/ensure_eval_corpus.sh +0 -0
  340. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/eval_explain.py +0 -0
  341. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/eval_recommend.py +0 -0
  342. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/eval_retrieval.py +0 -0
  343. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/eval_stats_summary.py +0 -0
  344. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/import_budget.py +0 -0
  345. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/lock_toolchain.py +0 -0
  346. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/mutation_gate.py +0 -0
  347. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/mutation_shards.py +0 -0
  348. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/mutation_weights.json +0 -0
  349. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/perf_gate.py +0 -0
  350. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/post_deploy_smoke.py +0 -0
  351. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/scripts/release_preflight.py +0 -0
  352. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/setup.cfg +0 -0
  353. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/sonar-project.properties +0 -0
  354. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/style/README.md +0 -0
  355. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/style/boost.css +0 -0
  356. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/style/boost.js +0 -0
  357. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/style/demo.html +0 -0
  358. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/bdd/features/adapt.feature +0 -0
  359. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/bdd/features/browse.feature +0 -0
  360. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/bdd/features/count.feature +0 -0
  361. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/bdd/features/discover.feature +0 -0
  362. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/bdd/features/doctor.feature +0 -0
  363. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/bdd/features/environment.py +0 -0
  364. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/bdd/features/explain.feature +0 -0
  365. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/bdd/features/index.feature +0 -0
  366. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/bdd/features/install.feature +0 -0
  367. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/bdd/features/list.feature +0 -0
  368. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/bdd/features/mcp.feature +0 -0
  369. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/bdd/features/search.feature +0 -0
  370. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/bdd/features/steps/cli_steps.py +0 -0
  371. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/bdd/features/steps/discovery_steps.py +0 -0
  372. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/bdd/features/steps/mcp_steps.py +0 -0
  373. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/bdd/features/steps/quality_steps.py +0 -0
  374. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/conftest.py +0 -0
  375. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/eval/baseline.json +0 -0
  376. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/eval/explain.jsonl +0 -0
  377. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/eval/golden.jsonl +0 -0
  378. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/eval/recommend.jsonl +0 -0
  379. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/eval/taps.txt +0 -0
  380. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_capabilities_policy.py +0 -0
  381. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_cli_adapt.py +0 -0
  382. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_cli_bmad.py +0 -0
  383. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_cli_configuration.py +0 -0
  384. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_cli_discovery.py +0 -0
  385. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_cli_hooks.py +0 -0
  386. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_cli_info.py +0 -0
  387. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_cli_intelligence.py +0 -0
  388. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_cli_pkg.py +0 -0
  389. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_cli_quality.py +0 -0
  390. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_cli_taps.py +0 -0
  391. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_cli_team.py +0 -0
  392. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_everyday_loop.py +0 -0
  393. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_integrity_enforce.py +0 -0
  394. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_property_parsers.py +0 -0
  395. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_run.py +0 -0
  396. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_tap_signing.py +0 -0
  397. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/functional/test_workspace_scope.py +0 -0
  398. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/README.md +0 -0
  399. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/frontmatter/01-typical.md +0 -0
  400. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/frontmatter/02-lossy-version.md +0 -0
  401. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/frontmatter/03-lossy-numbers.md +0 -0
  402. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/frontmatter/04-lists.md +0 -0
  403. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/frontmatter/05-nested.md +0 -0
  404. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/frontmatter/06-empty-block.md +0 -0
  405. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/frontmatter/07-unterminated.md +0 -0
  406. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/frontmatter/08-none.md +0 -0
  407. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/frontmatter/09-unbalanced-quote.md +0 -0
  408. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/frontmatter/10-keywords.md +0 -0
  409. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/frontmatter/11-crlf.md +0 -0
  410. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/frontmatter/12-bom.md +0 -0
  411. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/registry/01-shorthand.txt +0 -0
  412. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/registry/02-https.txt +0 -0
  413. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/registry/03-ssh.txt +0 -0
  414. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/registry/04-traversal.txt +0 -0
  415. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/registry/05-empty.txt +0 -0
  416. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/registry/06-space.txt +0 -0
  417. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/registry/07-slash.txt +0 -0
  418. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/corpus/registry/08-bare-host.txt +0 -0
  419. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/fuzz_frontmatter.py +0 -0
  420. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/fuzz/fuzz_registry.py +0 -0
  421. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/make_fixture.py +0 -0
  422. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/perf/test_benchmarks.py +0 -0
  423. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/smoke.sh +0 -0
  424. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_a11y_check.py +0 -0
  425. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_adapters.py +0 -0
  426. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_adapters_multi.py +0 -0
  427. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_adapters_runner.py +0 -0
  428. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_agents.py +0 -0
  429. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_ai.py +0 -0
  430. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_capabilities.py +0 -0
  431. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_catalog.py +0 -0
  432. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_check_anchors.py +0 -0
  433. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_claude_settings.py +0 -0
  434. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_cliparse.py +0 -0
  435. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_command_reference_fresh.py +0 -0
  436. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_community_health_files.py +0 -0
  437. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_config.py +0 -0
  438. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_dense.py +0 -0
  439. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_dense_fallback.py +0 -0
  440. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_dependabot_config.py +0 -0
  441. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_docs_pages_linked.py +0 -0
  442. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_docsite_chrome.py +0 -0
  443. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_ed25519.py +0 -0
  444. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_embed.py +0 -0
  445. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_errors_and_cli_table.py +0 -0
  446. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_eval_stats_summary.py +0 -0
  447. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_faithfulness.py +0 -0
  448. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_frontmatter.py +0 -0
  449. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_fuzz_targets.py +0 -0
  450. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_gitleaks_config.py +0 -0
  451. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_gitutil.py +0 -0
  452. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_imperative.py +0 -0
  453. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_import_budget.py +0 -0
  454. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_injectscan.py +0 -0
  455. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_integrity.py +0 -0
  456. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_journal.py +0 -0
  457. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_lockfile.py +0 -0
  458. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_marketing_counts.py +0 -0
  459. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_mcp.py +0 -0
  460. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_mcpdecl.py +0 -0
  461. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_minisign.py +0 -0
  462. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_mutation_hardening.py +0 -0
  463. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_mutation_shards.py +0 -0
  464. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_mutmut_source_paths.py +0 -0
  465. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_nethttp.py +0 -0
  466. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_output.py +0 -0
  467. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_paths.py +0 -0
  468. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_perf_gate.py +0 -0
  469. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_pkg_confusions.py +0 -0
  470. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_pkg_injection.py +0 -0
  471. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_pkg_secrets.py +0 -0
  472. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_policy.py +0 -0
  473. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_post_deploy_smoke.py +0 -0
  474. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_projectlock.py +0 -0
  475. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_provenance.py +0 -0
  476. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_rag.py +0 -0
  477. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_registries_fresh.py +0 -0
  478. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_registry.py +0 -0
  479. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_release_preflight.py +0 -0
  480. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_required_checks.py +0 -0
  481. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_resolve.py +0 -0
  482. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_rules.py +0 -0
  483. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_scopes.py +0 -0
  484. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_secretscan.py +0 -0
  485. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_selfupdate.py +0 -0
  486. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_serve.py +0 -0
  487. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_spin.py +0 -0
  488. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_stackprobe.py +0 -0
  489. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_staleness.py +0 -0
  490. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_store.py +0 -0
  491. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_token_parity.py +0 -0
  492. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_toolchain_lock.py +0 -0
  493. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_trustaudit.py +0 -0
  494. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_typosquat.py +0 -0
  495. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_updatediff.py +0 -0
  496. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_util.py +0 -0
  497. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_version.py +0 -0
  498. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_workflow_timeouts.py +0 -0
  499. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/unit/test_workflows.py +0 -0
  500. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/visual/a11y_check.mjs +0 -0
  501. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/visual/console_check.mjs +0 -0
  502. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/tests/visual/package.json +0 -0
  503. {boost_skill_cli-1.0.263 → boost_skill_cli-1.0.265}/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.263
3
+ Version: 1.0.265
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.263'
22
- __version_tuple__ = version_tuple = (1, 0, 263)
21
+ __version__ = version = '1.0.265'
22
+ __version_tuple__ = version_tuple = (1, 0, 265)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -540,6 +540,26 @@ def cmd_explain(argv):
540
540
  return 0
541
541
 
542
542
 
543
+ def _diag_line(line: str) -> str:
544
+ """Render one stored log line for display, whether it is text or JSON.
545
+
546
+ ``BOOST_LOG_FORMAT=json`` makes the file JSONL, which is the point — but
547
+ this command is the *human* view of that same file, and raw JSONL is not
548
+ it. Anything that is not a boost log object passes through untouched, so a
549
+ file whose format changed mid-life still reads end to end.
550
+ """
551
+ if not line.startswith("{"):
552
+ return line
553
+ try:
554
+ rec = json.loads(line)
555
+ except ValueError:
556
+ return line
557
+ if not isinstance(rec, dict) or "msg" not in rec:
558
+ return line
559
+ return "%s %-7s %s: %s" % (rec.get("ts", ""), rec.get("level", ""),
560
+ rec.get("logger", ""), rec["msg"])
561
+
562
+
543
563
  def _show_diagnostics(limit):
544
564
  lp = logs.log_path()
545
565
  if not lp.exists():
@@ -548,7 +568,7 @@ def _show_diagnostics(limit):
548
568
  lines = lp.read_text(encoding="utf-8", errors="replace").splitlines()
549
569
  out.heading("diagnostic log — %s" % lp)
550
570
  for line in lines[-limit:]:
551
- out.info(line)
571
+ out.info(_diag_line(line))
552
572
  return 0
553
573
 
554
574
 
@@ -30,6 +30,10 @@ DEFAULTS = {
30
30
  # See core/logs.py and docs/DEBUGGING.md.
31
31
  "level": "OFF",
32
32
  "file": True, # set false (or BOOST_NO_LOG=1) to disable the log file
33
+ # "text" (default) or "json". json emits one JSON object per line —
34
+ # the same fields, but readable by jq or a log collector without a
35
+ # regex. Overridden by BOOST_LOG_FORMAT.
36
+ "format": "text",
33
37
  },
34
38
  }
35
39
 
@@ -28,10 +28,21 @@ to disable the file.
28
28
  Each invocation bookends the trail with an ``invoke:`` line and a ``done:`` line
29
29
  that carries the exit code and wall-clock duration, so the log doubles as a
30
30
  lightweight timing record for spotting slow commands after the fact.
31
+
32
+ Line *format* is resolved separately from verbosity, same precedence shape:
33
+
34
+ 1. ``BOOST_LOG_FORMAT=json|text``
35
+ 2. config ``logging.format`` (default ``text``)
36
+
37
+ ``json`` emits one JSON object per line — the same fields the text formatter
38
+ renders — so ``~/.boost/logs/boost.log`` pipes straight into ``jq`` or a log
39
+ collector instead of needing a regex. It is the same JSONL shape
40
+ ``core.journal`` already writes for the pulse feed.
31
41
  """
32
42
  from __future__ import annotations
33
43
 
34
44
  import contextlib
45
+ import json
35
46
  import logging
36
47
  import logging.handlers
37
48
  import os
@@ -51,6 +62,9 @@ BACKUP_COUNT = 3 # … times (N+1) files kept = ~4 MB ceiling
51
62
  KEEP_CRASH_REPORTS = 20
52
63
 
53
64
  _LEVELS = ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL")
65
+ _FORMATS = ("text", "json")
66
+ _TEXT_FMT = "%(asctime)s %(levelname)-7s %(name)s: %(message)s"
67
+ _DATE_FMT = "%Y-%m-%dT%H:%M:%SZ"
54
68
 
55
69
  # Set by configure(); read by main()'s exception handler to decide whether to
56
70
  # print a full traceback or a friendly one-liner.
@@ -98,6 +112,54 @@ def _console_level(verbose: bool, debug: bool, quiet: bool) -> Optional[int]:
98
112
  return getattr(logging, cfg) if cfg in _LEVELS else None
99
113
 
100
114
 
115
+ class JsonFormatter(logging.Formatter):
116
+ """One JSON object per line, carrying the text formatter's own fields.
117
+
118
+ Hand-rolled rather than pulled from a dependency: the runtime is
119
+ stdlib-only, ``core.journal`` already writes JSONL by hand for the pulse
120
+ feed, and a formatter that can raise is a formatter that loses the trail it
121
+ exists to keep — hence ``default=str``, so an unexpected object in a record
122
+ degrades to its repr instead of killing the handler.
123
+
124
+ ``converter`` is set on the instance by :func:`_formatter`, not here: as a
125
+ class attribute mypy binds it as a method and the signature stops matching
126
+ the base class's.
127
+ """
128
+
129
+ def format(self, record: logging.LogRecord) -> str:
130
+ payload = {
131
+ "ts": self.formatTime(record, _DATE_FMT),
132
+ "level": record.levelname,
133
+ "logger": record.name,
134
+ "msg": record.getMessage(),
135
+ }
136
+ if record.exc_info:
137
+ payload["exc"] = self.formatException(record.exc_info)
138
+ return json.dumps(payload, ensure_ascii=False, default=str)
139
+
140
+
141
+ def log_format() -> str:
142
+ """Resolve the log line format: env first, then config, else ``text``."""
143
+ env = (os.environ.get("BOOST_LOG_FORMAT") or "").strip().lower()
144
+ if env in _FORMATS:
145
+ return env
146
+ from . import config
147
+ cfg = str(config.get("logging.format", "text") or "text").strip().lower()
148
+ return cfg if cfg in _FORMATS else "text"
149
+
150
+
151
+ def _formatter(fmt_name: str) -> logging.Formatter:
152
+ """Build the formatter both handlers share."""
153
+ fmt: logging.Formatter = (JsonFormatter() if fmt_name == "json"
154
+ else logging.Formatter(_TEXT_FMT,
155
+ datefmt=_DATE_FMT))
156
+ # Both stamp a literal ``Z`` (UTC) suffix, so the timestamp has to be
157
+ # rendered in UTC — otherwise it uses local time and every line is
158
+ # mislabelled by the machine's offset. gmtime keeps it honest.
159
+ fmt.converter = time.gmtime
160
+ return fmt
161
+
162
+
101
163
  def _file_enabled() -> bool:
102
164
  if os.environ.get("BOOST_NO_LOG"):
103
165
  return False
@@ -141,14 +203,10 @@ def configure(verbose: bool = False, debug: bool = False,
141
203
  return logger
142
204
  _configured = True
143
205
 
144
- fmt = logging.Formatter(
145
- "%(asctime)s %(levelname)-7s %(name)s: %(message)s",
146
- datefmt="%Y-%m-%dT%H:%M:%SZ",
147
- )
148
- # datefmt stamps a literal ``Z`` (UTC) suffix, so the timestamp must be
149
- # rendered in UTC — otherwise ``%(asctime)s`` uses local time and every
150
- # line is mislabelled by the machine's offset. gmtime keeps it honest.
151
- fmt.converter = time.gmtime
206
+ # One formatter for both handlers: a user who asked for JSON asked for it
207
+ # everywhere, and a file/console split would make `--debug` disagree with
208
+ # the file it is meant to be showing.
209
+ fmt = _formatter(log_format())
152
210
 
153
211
  # File handler — always DEBUG, best-effort (never break the CLI over a log).
154
212
  if _file_enabled():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.263
3
+ Version: 1.0.265
4
4
  Summary: boost — Homebrew for AI coding skills
5
5
  Author: Jonathan Reyes
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -80,6 +80,33 @@ BOOST_NO_LOG=1 boost install foo # this run writes no file
80
80
  boost config set logging.file false # permanently
81
81
  ```
82
82
 
83
+ ### Structured (JSON) log lines
84
+
85
+ The trail is plain text by default. `json` emits **one JSON object per line**
86
+ carrying the same fields, so the file pipes straight into `jq` or a log
87
+ collector instead of needing a regex:
88
+
89
+ ```bash
90
+ BOOST_LOG_FORMAT=json boost install foo # this run
91
+ boost config set logging.format json # permanently
92
+
93
+ jq -r 'select(.level=="WARNING") | .msg' ~/.boost/logs/boost.log
94
+ ```
95
+
96
+ | Field | Meaning |
97
+ |-------|---------|
98
+ | `ts` | UTC timestamp, `2026-07-27T14:03:11Z` |
99
+ | `level` | `DEBUG` … `CRITICAL` |
100
+ | `logger` | always `boost` today |
101
+ | `msg` | the formatted message, arguments already interpolated |
102
+ | `exc` | the traceback — present only on records logged with an exception |
103
+
104
+ The format applies to the console channel too, so `--debug` shows the same
105
+ shape the file is recording. `boost log --diagnostics` renders JSON lines back
106
+ as text, so switching format doesn't cost you the built-in viewer, and a file
107
+ whose format changed mid-life still reads end to end. An unrecognised value
108
+ falls back to `text` rather than failing the run.
109
+
83
110
  ---
84
111
 
85
112
  ## Crash reports
@@ -149,6 +176,7 @@ Everything that changes boost's runtime behaviour, in one place:
149
176
  | `BOOST_AGENTS_STORE` | override `~/.agents/skills` (the canonical store) |
150
177
  | `BOOST_DEBUG` | `=1` → console `DEBUG` + tracebacks |
151
178
  | `BOOST_LOG_LEVEL` | explicit console diagnostic level |
179
+ | `BOOST_LOG_FORMAT` | `text` (default) or `json` — one JSON object per log line |
152
180
  | `BOOST_NO_LOG` | `=1` → don't write the diagnostic log file |
153
181
  | `BOOST_NO_AI` | `=1` → disable all AI calls (offline / deterministic) |
154
182
  | `BOOST_ASSUME_YES` | `=1` → auto-confirm prompts (also `--yes`/`-y`) |
@@ -265,6 +265,40 @@ def build_design() -> tuple[Path, str]:
265
265
  return DESIGN_HTML, html
266
266
 
267
267
 
268
+ _CARD_ID = re.compile(r'<article class="(?:cap rcard|ritem)" id="([^"]+)"')
269
+
270
+
271
+ def diagnose(path, committed: str, fresh: str) -> list[str]:
272
+ """Explain *why* a board drifted, in the terms the reader needs.
273
+
274
+ The common cause is not a hand-edit. It is a rebase: another PR's card
275
+ merges in as a clean new ``docs/roadmap/items/*.md``, git merges the
276
+ generated HTML textually and succeeds, and the board is silently missing
277
+ that card. The old message said only "out of date", so a PR that changed no
278
+ Python at all went red across lint and every test leg with nothing in the
279
+ log pointing at the actual cause.
280
+ """
281
+ was = _CARD_ID.findall(committed)
282
+ now = _CARD_ID.findall(fresh)
283
+ missing = [i for i in now if i not in set(was)]
284
+ extra = [i for i in was if i not in set(now)]
285
+ lines = []
286
+ if missing:
287
+ lines.append(" missing %d card(s) present in docs/roadmap/items/: %s"
288
+ % (len(missing), ", ".join(missing[:8])
289
+ + (" …" if len(missing) > 8 else "")))
290
+ lines.append(" ↳ almost always a rebase: someone else's card landed on "
291
+ "main and the generated HTML merged textually.")
292
+ if extra:
293
+ lines.append(" %d card(s) in the HTML have no item file: %s"
294
+ % (len(extra), ", ".join(extra[:8])
295
+ + (" …" if len(extra) > 8 else "")))
296
+ if not missing and not extra:
297
+ lines.append(" the same cards, rendered differently — an item file's "
298
+ "fields or body changed, or the generator did.")
299
+ return lines
300
+
301
+
268
302
  def main(argv: list[str] | None = None) -> int:
269
303
  parser = argparse.ArgumentParser(description="Regenerate the roadmap boards.")
270
304
  parser.add_argument(
@@ -277,21 +311,29 @@ def main(argv: list[str] | None = None) -> int:
277
311
  drift = []
278
312
  for path, fresh in targets:
279
313
  if args.check:
280
- if path.read_text(encoding="utf-8") != fresh:
281
- drift.append(path)
314
+ committed = path.read_text(encoding="utf-8")
315
+ if committed != fresh:
316
+ drift.append((path, committed, fresh))
282
317
  else:
283
318
  path.write_text(fresh, encoding="utf-8")
284
319
  print("wrote %s" % path)
285
320
 
286
321
  if args.check:
287
322
  if drift:
288
- print(
289
- "ERROR: roadmap HTML is out of date — regenerate with\n"
290
- " python3 scripts/build_roadmap.py\n"
291
- "and commit the result (see CONTRIBUTING.md):\n %s"
292
- % "\n ".join(str(p) for p in drift),
293
- file=sys.stderr,
294
- )
323
+ report = ["ERROR: the roadmap board is stale — regenerate with",
324
+ " python3 scripts/build_roadmap.py",
325
+ "and commit the result (see CONTRIBUTING.md).",
326
+ ""]
327
+ for path, committed, fresh in drift:
328
+ report.append("%s" % path)
329
+ report.extend(diagnose(path, committed, fresh))
330
+ print("\n".join(report), file=sys.stderr)
331
+ # One annotation so the cause is visible on the checks tab without
332
+ # opening a log: this failure lands on every matrix leg at once and
333
+ # reads as a broken build rather than a stale generated file.
334
+ print("::error::roadmap board is stale — run "
335
+ "`python3 scripts/build_roadmap.py` and commit "
336
+ "(usually needed after a rebase)")
295
337
  return 1
296
338
  print("roadmap boards are up to date.")
297
339
  return 0
@@ -1,10 +1,13 @@
1
1
  """Diagnostic logging & crash reporting."""
2
2
  from __future__ import annotations
3
3
 
4
+ import json
4
5
  import logging
5
6
  import logging.handlers
6
7
  import pathlib
8
+ import re
7
9
  import time
10
+ from datetime import datetime, timezone
8
11
 
9
12
  import pytest
10
13
 
@@ -471,3 +474,140 @@ def test_a_real_crash_shows_up_in_the_listing(boost, monkeypatch):
471
474
  res = boost("log", "--crashes")
472
475
  assert crashed == ["count"]
473
476
  assert "command: boost count" in res.out
477
+
478
+
479
+ # ── BOOST_LOG_FORMAT=json ────────────────────────────────────────────────────
480
+
481
+ class TestLogFormatResolution:
482
+ """Env beats config beats the `text` default — same shape as the level."""
483
+
484
+ def test_defaults_to_text(self, env):
485
+ assert logs.log_format() == "text"
486
+
487
+ def test_env_selects_json(self, env, monkeypatch):
488
+ monkeypatch.setenv("BOOST_LOG_FORMAT", "json")
489
+ assert logs.log_format() == "json"
490
+
491
+ def test_env_is_case_and_space_insensitive(self, env, monkeypatch):
492
+ monkeypatch.setenv("BOOST_LOG_FORMAT", " JSON ")
493
+ assert logs.log_format() == "json"
494
+
495
+ def test_an_unknown_env_value_falls_back_to_text(self, env, monkeypatch):
496
+ # A typo must not silently disable logging or crash configure().
497
+ monkeypatch.setenv("BOOST_LOG_FORMAT", "yaml")
498
+ assert logs.log_format() == "text"
499
+
500
+ def test_config_selects_json_when_env_is_unset(self, env, monkeypatch):
501
+ from boost_cli.core import config
502
+ monkeypatch.delenv("BOOST_LOG_FORMAT", raising=False)
503
+ config.set_value("logging.format", "json")
504
+ assert logs.log_format() == "json"
505
+
506
+ def test_env_wins_over_config(self, env, monkeypatch):
507
+ from boost_cli.core import config
508
+ config.set_value("logging.format", "json")
509
+ monkeypatch.setenv("BOOST_LOG_FORMAT", "text")
510
+ assert logs.log_format() == "text"
511
+
512
+
513
+ class TestJsonFileOutput:
514
+ def _records(self, env, monkeypatch):
515
+ monkeypatch.setenv("BOOST_LOG_FORMAT", "json")
516
+ logs.configure()
517
+ logs.get_logger().info("hello %s", "world")
518
+ text = logs.log_path().read_text(encoding="utf-8")
519
+ return [json.loads(ln) for ln in text.splitlines() if ln.strip()]
520
+
521
+ def test_one_json_object_per_line(self, env, monkeypatch):
522
+ recs = self._records(env, monkeypatch)
523
+ assert len(recs) == 1
524
+ assert recs[0]["msg"] == "hello world", "args must be interpolated"
525
+ assert recs[0]["level"] == "INFO"
526
+ assert recs[0]["logger"] == "boost"
527
+
528
+ def test_the_timestamp_is_utc_with_a_z(self, env, monkeypatch):
529
+ ts = self._records(env, monkeypatch)[0]["ts"]
530
+ assert re.match(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$", ts), ts
531
+ # Parsed as UTC it must be within a minute of now; a local-time stamp
532
+ # wearing a Z would be off by the machine's offset.
533
+ parsed = datetime.strptime(ts, "%Y-%m-%dT%H:%M:%SZ").replace(
534
+ tzinfo=timezone.utc)
535
+ assert abs((datetime.now(timezone.utc) - parsed).total_seconds()) < 60
536
+
537
+ def test_an_exception_is_carried_in_its_own_field(self, env, monkeypatch):
538
+ monkeypatch.setenv("BOOST_LOG_FORMAT", "json")
539
+ logs.configure()
540
+ try:
541
+ raise ValueError("boom")
542
+ except ValueError:
543
+ logs.get_logger().exception("caught it")
544
+ rec = [json.loads(ln) for ln in
545
+ logs.log_path().read_text(encoding="utf-8").splitlines()][-1]
546
+ assert rec["msg"] == "caught it"
547
+ assert "ValueError: boom" in rec["exc"]
548
+ assert "\n" not in json.dumps(rec), "one physical line per record"
549
+
550
+ def test_an_unserializable_arg_degrades_instead_of_losing_the_line(
551
+ self, env, monkeypatch):
552
+ # A formatter that raises loses the trail it exists to keep.
553
+ class Weird:
554
+ def __repr__(self):
555
+ return "<weird>"
556
+
557
+ monkeypatch.setenv("BOOST_LOG_FORMAT", "json")
558
+ logs.configure()
559
+ logs.get_logger().info("got %r", Weird())
560
+ rec = [json.loads(ln) for ln in
561
+ logs.log_path().read_text(encoding="utf-8").splitlines()][-1]
562
+ assert rec["msg"] == "got <weird>"
563
+
564
+ def test_text_mode_is_unchanged(self, env, monkeypatch):
565
+ monkeypatch.delenv("BOOST_LOG_FORMAT", raising=False)
566
+ logs.configure()
567
+ logs.get_logger().info("plain line")
568
+ text = logs.log_path().read_text(encoding="utf-8")
569
+ assert "INFO" in text and "boost: plain line" in text
570
+ assert not text.lstrip().startswith("{")
571
+
572
+
573
+ class TestJsonConsoleOutput:
574
+ def test_the_console_handler_uses_the_same_format(self, env, monkeypatch,
575
+ capsys):
576
+ # A `--debug` stream that disagrees with the file it is showing would
577
+ # be its own bug report.
578
+ monkeypatch.setenv("BOOST_LOG_FORMAT", "json")
579
+ logs.configure(debug=True)
580
+ logs.get_logger().error("stderr line")
581
+ err = capsys.readouterr().err.strip().splitlines()[-1]
582
+ assert json.loads(err)["msg"] == "stderr line"
583
+
584
+
585
+ class TestDiagnosticsViewerReadsBothFormats:
586
+ """`boost log --diagnostics` is the human view of that same file."""
587
+
588
+ def _diag(self):
589
+ from boost_cli.commands import info
590
+ return info._diag_line
591
+
592
+ def test_a_json_line_is_rendered_back_as_text(self):
593
+ line = json.dumps({"ts": "2026-07-27T00:00:00Z", "level": "INFO",
594
+ "logger": "boost", "msg": "invoke: boost count"})
595
+ assert self._diag()(line) == \
596
+ "2026-07-27T00:00:00Z INFO boost: invoke: boost count"
597
+
598
+ def test_a_plain_text_line_passes_through(self):
599
+ line = "2026-07-27T00:00:00Z INFO boost: invoke: boost count"
600
+ assert self._diag()(line) == line
601
+
602
+ def test_a_line_that_only_looks_like_json_passes_through(self):
603
+ # A mixed file (the format changed mid-life) has to read end to end.
604
+ for line in ("{not json at all", json.dumps({"other": "shape"}),
605
+ json.dumps([1, 2, 3])):
606
+ assert self._diag()(line) == line
607
+
608
+ def test_the_command_renders_a_json_trail(self, boost, monkeypatch):
609
+ monkeypatch.setenv("BOOST_LOG_FORMAT", "json")
610
+ boost("count")
611
+ res = boost("log", "--diagnostics")
612
+ assert "invoke: boost count" in res.out
613
+ assert "{" not in res.out, "raw JSONL is not the human view"
@@ -0,0 +1,151 @@
1
+ """Committed roadmap HTML stays in lockstep with its item source files.
2
+
3
+ The roadmap boards are generated from ``docs/roadmap/items/*.md`` by
4
+ ``scripts/build_roadmap.py`` and injected into the marker regions of the
5
+ hand-authored pages. This test — the in-suite twin of the
6
+ ``build_roadmap.py --check`` CI step — fails if the committed HTML drifts from a
7
+ fresh render, so a stale board can't merge.
8
+
9
+ Skips when the repo-root files aren't reachable (e.g. the mutation sandbox,
10
+ which only copies ``boost_cli/``).
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import importlib.util
15
+ from pathlib import Path
16
+
17
+ import pytest
18
+
19
+ _ROOT = Path(__file__).resolve().parents[2]
20
+ _SCRIPT = _ROOT / "scripts" / "build_roadmap.py"
21
+ _ITEMS = _ROOT / "docs" / "roadmap" / "items"
22
+
23
+
24
+ def _load_builder():
25
+ spec = importlib.util.spec_from_file_location("build_roadmap", _SCRIPT)
26
+ assert spec and spec.loader
27
+ module = importlib.util.module_from_spec(spec)
28
+ spec.loader.exec_module(module)
29
+ return module
30
+
31
+
32
+ @pytest.mark.skipif(not (_SCRIPT.exists() and _ITEMS.exists()),
33
+ reason="repo-root files not reachable (e.g. mutation sandbox)")
34
+ def test_roadmap_html_is_regenerated():
35
+ builder = _load_builder()
36
+ path, fresh = builder.build_code()
37
+ committed = path.read_text(encoding="utf-8")
38
+ # Reuse the script's own diagnosis rather than restating "out of date".
39
+ # This assertion fires on all nine test legs at once, so what it says is
40
+ # what nine failures say — and the cause is a rebase far more often than a
41
+ # hand-edit.
42
+ assert committed == fresh, "\n".join(
43
+ ["docs/roadmap.html is stale — regenerate with",
44
+ " python3 scripts/build_roadmap.py",
45
+ "and commit the result (see CONTRIBUTING.md).",
46
+ *builder.diagnose(path, committed, fresh)])
47
+
48
+
49
+ @pytest.mark.skipif(not (_SCRIPT.exists() and _ITEMS.exists()),
50
+ reason="repo-root files not reachable (e.g. mutation sandbox)")
51
+ def test_design_roadmap_html_is_regenerated():
52
+ builder = _load_builder()
53
+ path, fresh = builder.build_design()
54
+ committed = path.read_text(encoding="utf-8")
55
+ assert committed == fresh, "\n".join(
56
+ ["docs/design-roadmap.html is stale — regenerate with",
57
+ " python3 scripts/build_roadmap.py",
58
+ "and commit the result (see CONTRIBUTING.md).",
59
+ *builder.diagnose(path, committed, fresh)])
60
+
61
+
62
+ @pytest.mark.skipif(not (_SCRIPT.exists() and _ITEMS.exists()),
63
+ reason="repo-root files not reachable (e.g. mutation sandbox)")
64
+ def test_check_flag_passes_on_fresh_tree():
65
+ builder = _load_builder()
66
+ assert builder.main(["--check"]) == 0
67
+
68
+
69
+ @pytest.mark.skipif(not (_SCRIPT.exists() and _ITEMS.exists()),
70
+ reason="repo-root files not reachable (e.g. mutation sandbox)")
71
+ def test_every_code_item_has_required_fields():
72
+ builder = _load_builder()
73
+ for item in builder.load_items("code"):
74
+ for field in ("id", "section", "status", "title"):
75
+ assert item.get(field), "%s: missing %r" % (item["_file"], field)
76
+ assert item["status"] in builder.STATUS_LABEL, (
77
+ "%s: bad status %r" % (item["_file"], item["status"]))
78
+
79
+
80
+ @pytest.mark.skipif(not (_SCRIPT.exists() and _ITEMS.exists()),
81
+ reason="repo-root files not reachable (e.g. mutation sandbox)")
82
+ def test_every_design_item_has_required_fields():
83
+ builder = _load_builder()
84
+ for item in builder.load_items("design"):
85
+ for field in ("id", "track", "status", "title"):
86
+ assert item.get(field), "%s: missing %r" % (item["_file"], field)
87
+ assert item["status"] in builder.DESIGN_STATUS, (
88
+ "%s: bad status %r" % (item["_file"], item["status"]))
89
+ assert str(item.get("impact", "")).lower() in builder.IMPACT_LABEL, (
90
+ "%s: bad impact %r" % (item["_file"], item.get("impact")))
91
+
92
+
93
+ # ── the diagnosis itself ─────────────────────────────────────────────────────
94
+ #
95
+ # The failure above lands on lint and on all nine test legs simultaneously, for
96
+ # a PR that may have changed no Python at all. Whether it reads as "the build is
97
+ # broken" or as "regenerate the board after your rebase" is entirely down to
98
+ # what these strings say, so they are tested rather than trusted.
99
+
100
+ CARD = '<article class="cap rcard" id="%s">body</article>'
101
+
102
+
103
+ @pytest.mark.skipif(not _SCRIPT.exists(), reason="repo-root files not reachable")
104
+ class TestDiagnose:
105
+ def _lines(self, committed, fresh):
106
+ return _load_builder().diagnose(Path("docs/roadmap.html"),
107
+ committed, fresh)
108
+
109
+ def test_a_card_missing_from_the_html_names_it_and_blames_the_rebase(self):
110
+ # THE case this exists for: another PR's item file merged in cleanly,
111
+ # the generated HTML merged textually, and the card is simply absent.
112
+ lines = self._lines(CARD % "old-one",
113
+ (CARD % "old-one") + (CARD % "someone-elses-card"))
114
+ text = "\n".join(lines)
115
+ assert "someone-elses-card" in text
116
+ assert "rebase" in text
117
+ assert "missing 1 card" in text
118
+
119
+ def test_several_missing_cards_are_summarised_not_dumped(self):
120
+ fresh = "".join(CARD % ("card-%d" % i) for i in range(20))
121
+ text = "\n".join(self._lines("", fresh))
122
+ assert "missing 20 card(s)" in text
123
+ assert text.count("card-") <= 9, "8 named plus the ellipsis"
124
+ assert "…" in text
125
+
126
+ def test_a_card_with_no_item_file_is_called_out_separately(self):
127
+ lines = self._lines(CARD % "deleted-item", "")
128
+ text = "\n".join(lines)
129
+ assert "no item file" in text
130
+ assert "deleted-item" in text
131
+ assert "rebase" not in text, "nothing is missing — different cause"
132
+
133
+ def test_same_cards_rendered_differently_says_so(self):
134
+ # A field or body edit, or a generator change — not a rebase.
135
+ lines = self._lines('<article class="cap rcard" id="a">old</article>',
136
+ '<article class="cap rcard" id="a">new</article>')
137
+ text = "\n".join(lines)
138
+ assert "rendered differently" in text
139
+ assert "missing" not in text
140
+
141
+ def test_the_design_board_shape_is_recognised_too(self):
142
+ # design-roadmap.html uses <article class="ritem" …>, not "cap rcard".
143
+ fresh = ('<article class="ritem" id="BOOST-D99" data-track="x" '
144
+ 'data-impact="y">body</article>')
145
+ assert "BOOST-D99" in "\n".join(self._lines("", fresh))
146
+
147
+ def test_it_never_returns_nothing(self):
148
+ # An empty diagnosis would leave the assertion message ending on a
149
+ # colon with no explanation — worse than the message it replaced.
150
+ for committed, fresh in (("", ""), ("x", "y"), (CARD % "a", CARD % "a")):
151
+ assert self._lines(committed, fresh)