boost-skill-cli 1.0.153__tar.gz → 1.0.155__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 (317) hide show
  1. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/Makefile +1 -0
  2. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/PKG-INFO +1 -1
  3. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/_version.py +2 -2
  4. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/cli.py +5 -6
  5. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/cliparse.py +1 -1
  6. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/commands/bmad.py +1 -1
  7. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/commands/configuration.py +20 -14
  8. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/commands/discovery.py +17 -12
  9. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/commands/info.py +9 -7
  10. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/commands/intelligence.py +4 -6
  11. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/commands/pkg.py +7 -7
  12. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/commands/quality.py +12 -12
  13. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/commands/team.py +1 -1
  14. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/claude_settings.py +2 -3
  15. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/frontmatter.py +1 -2
  16. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/gitutil.py +2 -2
  17. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/injectscan.py +6 -4
  18. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/logs.py +4 -9
  19. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/mcp.py +1 -1
  20. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/output.py +3 -4
  21. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/policy.py +2 -3
  22. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/rag.py +2 -2
  23. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/serve.py +5 -6
  24. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/staleness.py +2 -3
  25. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/store.py +1 -1
  26. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/updatediff.py +1 -4
  27. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/util.py +2 -3
  28. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_skill_cli.egg-info/PKG-INFO +1 -1
  29. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_skill_cli.egg-info/SOURCES.txt +2 -0
  30. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +3 -3
  31. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +3 -3
  32. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap.html +2 -2
  33. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/pyproject.toml +17 -4
  34. boost_skill_cli-1.0.155/scripts/import_budget.py +156 -0
  35. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/functional/test_cli_configuration.py +2 -3
  36. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/functional/test_cli_discovery.py +1 -2
  37. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/functional/test_cli_intelligence.py +1 -2
  38. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/functional/test_cli_taps.py +1 -1
  39. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/functional/test_property_parsers.py +3 -3
  40. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_adapters.py +2 -1
  41. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_catalog.py +1 -1
  42. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_config.py +1 -1
  43. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_dense_fallback.py +3 -2
  44. boost_skill_cli-1.0.155/tests/unit/test_import_budget.py +135 -0
  45. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_mcp.py +4 -4
  46. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_output.py +2 -2
  47. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_rag.py +3 -3
  48. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_serve.py +4 -4
  49. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_store.py +2 -1
  50. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_typosquat.py +3 -1
  51. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/.gitattributes +0 -0
  52. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/.gitignore +0 -0
  53. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/CLAUDE.md +0 -0
  54. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/CONTRIBUTING.md +0 -0
  55. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/LICENSE +0 -0
  56. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/MANIFEST.in +0 -0
  57. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/README.md +0 -0
  58. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/SECURITY.md +0 -0
  59. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost +0 -0
  60. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/__init__.py +0 -0
  61. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/__main__.py +0 -0
  62. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/commands/__init__.py +0 -0
  63. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/commands/hooks.py +0 -0
  64. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/commands/taps.py +0 -0
  65. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/__init__.py +0 -0
  66. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/adapters.py +0 -0
  67. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/agents.py +0 -0
  68. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/ai.py +0 -0
  69. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/catalog.py +0 -0
  70. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/config.py +0 -0
  71. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/dense.py +0 -0
  72. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/embed.py +0 -0
  73. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/imperative.py +0 -0
  74. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/journal.py +0 -0
  75. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/lockfile.py +0 -0
  76. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/nethttp.py +0 -0
  77. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/paths.py +0 -0
  78. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/registry.py +0 -0
  79. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/rules.py +0 -0
  80. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/secretscan.py +0 -0
  81. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/stackprobe.py +0 -0
  82. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/typosquat.py +0 -0
  83. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/core/workflows.py +0 -0
  84. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/data/registries.json +0 -0
  85. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/errors.py +0 -0
  86. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_cli/spin.py +0 -0
  87. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
  88. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_skill_cli.egg-info/entry_points.txt +0 -0
  89. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_skill_cli.egg-info/requires.txt +0 -0
  90. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/boost_skill_cli.egg-info/top_level.txt +0 -0
  91. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/.claude/settings.local.json +0 -0
  92. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/DEBUGGING.md +0 -0
  93. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/adapters.html +0 -0
  94. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/demo.gif +0 -0
  95. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/demo.tape +0 -0
  96. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/design-roadmap.html +0 -0
  97. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/eval.html +0 -0
  98. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/index.html +0 -0
  99. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/mcp-hub.html +0 -0
  100. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/rag-architecture.md +0 -0
  101. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D01.md +0 -0
  102. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D02.md +0 -0
  103. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D03.md +0 -0
  104. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D04.md +0 -0
  105. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D05.md +0 -0
  106. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D06.md +0 -0
  107. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D07.md +0 -0
  108. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D08.md +0 -0
  109. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D09.md +0 -0
  110. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D10.md +0 -0
  111. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D11.md +0 -0
  112. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D12.md +0 -0
  113. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D13.md +0 -0
  114. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D14.md +0 -0
  115. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D15.md +0 -0
  116. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D16.md +0 -0
  117. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D17.md +0 -0
  118. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D18.md +0 -0
  119. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D19.md +0 -0
  120. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D20.md +0 -0
  121. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D21.md +0 -0
  122. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D22.md +0 -0
  123. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D23.md +0 -0
  124. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D24.md +0 -0
  125. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D25.md +0 -0
  126. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/BOOST-D26.md +0 -0
  127. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
  128. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
  129. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
  130. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
  131. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/boost-run-live-agents.md +0 -0
  132. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
  133. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
  134. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
  135. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
  136. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
  137. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
  138. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
  139. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/command-reference-docs-site.md +0 -0
  140. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
  141. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
  142. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
  143. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
  144. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
  145. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
  146. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
  147. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
  148. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
  149. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
  150. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
  151. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
  152. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
  153. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
  154. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
  155. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/framework-adapter-multi-agent.md +0 -0
  156. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
  157. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
  158. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
  159. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
  160. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
  161. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/html-validation-html-validate.md +0 -0
  162. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/install-scope-user-or-project.md +0 -0
  163. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
  164. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
  165. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
  166. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
  167. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
  168. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
  169. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
  170. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
  171. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
  172. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
  173. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
  174. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
  175. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
  176. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
  177. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
  178. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
  179. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
  180. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
  181. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
  182. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
  183. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
  184. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
  185. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
  186. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
  187. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
  188. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
  189. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
  190. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
  191. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
  192. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
  193. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
  194. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
  195. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
  196. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
  197. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
  198. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
  199. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
  200. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
  201. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
  202. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
  203. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
  204. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
  205. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
  206. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
  207. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
  208. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
  209. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
  210. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
  211. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
  212. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
  213. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
  214. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
  215. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
  216. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
  217. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
  218. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
  219. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
  220. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
  221. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/typo-detection-codespell.md +0 -0
  222. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
  223. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
  224. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
  225. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/update-diff-before-apply.md +0 -0
  226. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
  227. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
  228. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
  229. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
  230. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
  231. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
  232. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/docs/roadmap/items/workspace-scope-install.md +0 -0
  233. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/examples/README.md +0 -0
  234. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/examples/adapt-demo.sh +0 -0
  235. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/examples/boost-run-prototype.sh +0 -0
  236. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/index.html +0 -0
  237. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/scripts/bench_cli.sh +0 -0
  238. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/scripts/build_registries.py +0 -0
  239. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/scripts/build_roadmap.py +0 -0
  240. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/scripts/ensure_eval_corpus.sh +0 -0
  241. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/scripts/eval_explain.py +0 -0
  242. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/scripts/eval_recommend.py +0 -0
  243. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/scripts/eval_retrieval.py +0 -0
  244. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/scripts/mutation_gate.py +0 -0
  245. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/setup.cfg +0 -0
  246. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/style/README.md +0 -0
  247. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/style/boost.css +0 -0
  248. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/style/boost.js +0 -0
  249. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/style/demo.html +0 -0
  250. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/bdd/features/adapt.feature +0 -0
  251. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/bdd/features/browse.feature +0 -0
  252. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/bdd/features/count.feature +0 -0
  253. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/bdd/features/discover.feature +0 -0
  254. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/bdd/features/doctor.feature +0 -0
  255. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/bdd/features/environment.py +0 -0
  256. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/bdd/features/explain.feature +0 -0
  257. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/bdd/features/index.feature +0 -0
  258. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/bdd/features/install.feature +0 -0
  259. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/bdd/features/list.feature +0 -0
  260. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/bdd/features/mcp.feature +0 -0
  261. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/bdd/features/search.feature +0 -0
  262. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/bdd/features/steps/cli_steps.py +0 -0
  263. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/bdd/features/steps/discovery_steps.py +0 -0
  264. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/bdd/features/steps/mcp_steps.py +0 -0
  265. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/bdd/features/steps/quality_steps.py +0 -0
  266. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/conftest.py +0 -0
  267. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/eval/baseline.json +0 -0
  268. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/eval/explain.jsonl +0 -0
  269. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/eval/golden.jsonl +0 -0
  270. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/eval/recommend.jsonl +0 -0
  271. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/eval/taps.txt +0 -0
  272. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/functional/test_cli_adapt.py +0 -0
  273. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/functional/test_cli_bmad.py +0 -0
  274. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/functional/test_cli_hooks.py +0 -0
  275. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/functional/test_cli_info.py +0 -0
  276. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/functional/test_cli_pkg.py +0 -0
  277. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/functional/test_cli_quality.py +0 -0
  278. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/functional/test_cli_team.py +0 -0
  279. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/functional/test_everyday_loop.py +0 -0
  280. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/make_fixture.py +0 -0
  281. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/perf/test_benchmarks.py +0 -0
  282. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/smoke.sh +0 -0
  283. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_agents.py +0 -0
  284. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_ai.py +0 -0
  285. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_claude_settings.py +0 -0
  286. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_cliparse.py +0 -0
  287. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_dense.py +0 -0
  288. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_docs_pages_linked.py +0 -0
  289. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_embed.py +0 -0
  290. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_errors_and_cli_table.py +0 -0
  291. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_frontmatter.py +0 -0
  292. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_gitutil.py +0 -0
  293. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_imperative.py +0 -0
  294. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_injectscan.py +0 -0
  295. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_journal.py +0 -0
  296. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_lockfile.py +0 -0
  297. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_logs.py +0 -0
  298. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_mutation_hardening.py +0 -0
  299. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_nethttp.py +0 -0
  300. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_paths.py +0 -0
  301. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_pkg_confusions.py +0 -0
  302. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_pkg_injection.py +0 -0
  303. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_pkg_secrets.py +0 -0
  304. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_policy.py +0 -0
  305. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_registries_fresh.py +0 -0
  306. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_registry.py +0 -0
  307. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_roadmap_fresh.py +0 -0
  308. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_rules.py +0 -0
  309. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_secretscan.py +0 -0
  310. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_spin.py +0 -0
  311. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_stackprobe.py +0 -0
  312. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_staleness.py +0 -0
  313. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_token_parity.py +0 -0
  314. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_updatediff.py +0 -0
  315. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_util.py +0 -0
  316. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_version.py +0 -0
  317. {boost_skill_cli-1.0.153 → boost_skill_cli-1.0.155}/tests/unit/test_workflows.py +0 -0
@@ -43,6 +43,7 @@ lint:
43
43
  @command -v actionlint >/dev/null 2>&1 && actionlint || echo "actionlint not on PATH — skipping (CI enforces it)"
44
44
  $(PY) scripts/build_registries.py --check
45
45
  $(PY) scripts/build_roadmap.py --check
46
+ $(PY) scripts/import_budget.py
46
47
 
47
48
  # Supply-chain CVE gate: fail on a known OSV/PyPI advisory in the project's
48
49
  # dependency closure. Mirrors the pip-audit CI workflow; run before releasing.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.153
3
+ Version: 1.0.155
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.153'
22
- __version_tuple__ = version_tuple = (1, 0, 153)
21
+ __version__ = version = '1.0.155'
22
+ __version_tuple__ = version_tuple = (1, 0, 155)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -17,6 +17,7 @@ from .core import logs
17
17
  from .core import nethttp
18
18
  from .core import output as out
19
19
  from .errors import BoostError
20
+ import contextlib
20
21
 
21
22
  # Global flags handled before dispatch, stripped from the command's own argv.
22
23
  _GLOBAL_FLAGS = {
@@ -174,7 +175,7 @@ def print_command_help(name: str) -> int:
174
175
  meta = resolve(name)
175
176
  if not meta:
176
177
  return _unknown(name)
177
- _group, module, summary = meta
178
+ _group, _module, summary = meta
178
179
  print(out.c("boost %s" % name, out.BOLD) + " — " + summary)
179
180
  # delegate to the command's own --help for flags
180
181
  return _dispatch(name, ["--help"], soft=True)
@@ -196,7 +197,7 @@ def _unknown(name: str) -> int:
196
197
 
197
198
 
198
199
  def _dispatch(name: str, argv: List[str], soft: bool = False) -> int:
199
- group, module, _summary = _BY_NAME[name]
200
+ _group, module, _summary = _BY_NAME[name]
200
201
  mod = importlib.import_module("boost_cli.commands.%s" % module)
201
202
  func = getattr(mod, "cmd_%s" % name.replace("-", "_"), None)
202
203
  if func is None:
@@ -264,13 +265,11 @@ def main(argv: List[str] | None = None) -> int:
264
265
  print()
265
266
  return rc
266
267
  except BrokenPipeError:
267
- try:
268
+ with contextlib.suppress(Exception):
268
269
  sys.stdout.close()
269
- except Exception:
270
- pass
271
270
  rc = 0
272
271
  return rc
273
- except Exception as e: # noqa: BLE001 — top-level safety net
272
+ except Exception as e:
274
273
  report = logs.write_crash_report(e, [name, *rest])
275
274
  if logs.is_debug():
276
275
  raise
@@ -19,7 +19,7 @@ from .core import output as out
19
19
 
20
20
 
21
21
  class BoostArgumentParser(argparse.ArgumentParser):
22
- def error(self, message: str): # noqa: D401 - argparse hook
22
+ def error(self, message: str):
23
23
  """Print a branded error + dimmed usage, then exit 2 (argparse's code)."""
24
24
  out.err(message)
25
25
  sys.stderr.write(out.c(self.format_usage(), out.DIM))
@@ -119,7 +119,7 @@ def _run_installer(directory: Path, modules: str) -> "subprocess.CompletedProces
119
119
  proc = subprocess.run(cmd, capture_output=True, text=True, timeout=900)
120
120
  except (OSError, subprocess.TimeoutExpired) as e:
121
121
  raise BoostError("bmad install failed: %s" % e,
122
- hint="run it yourself: " + " ".join(cmd))
122
+ hint="run it yourself: " + " ".join(cmd)) from e
123
123
  if proc.returncode != 0:
124
124
  tail = (proc.stderr or proc.stdout or "").strip().splitlines()
125
125
  raise BoostError(
@@ -72,7 +72,7 @@ def cmd_config(argv) -> int:
72
72
  except TypeError as e:
73
73
  raise BoostError(str(e),
74
74
  hint="the parent key holds a plain value — "
75
- "`boost config unset` it first")
75
+ "`boost config unset` it first") from e
76
76
  val = config.get(args.key)
77
77
  journal.log("config", args.key, op="set")
78
78
  out.ok("set %s = %s"
@@ -101,25 +101,31 @@ def cmd_clean(argv) -> int:
101
101
  help="also remove snapshots older than 90 days")
102
102
  args = p.parse_args(argv)
103
103
 
104
- items = [] # (path, kind, bytes)
105
- for _agent, spec in agents.known_agents().items():
104
+ items: list[tuple[Path, str, int]] = [] # (path, kind, bytes)
105
+ for spec in agents.known_agents().values():
106
106
  adir = spec["dir"]
107
107
  if not adir.is_dir():
108
108
  continue
109
- for link in sorted(adir.iterdir()):
110
- if link.is_symlink() and not link.exists():
111
- items.append((link, "broken symlink", 0))
109
+ items.extend(
110
+ (link, "broken symlink", 0)
111
+ for link in sorted(adir.iterdir())
112
+ if link.is_symlink() and not link.exists()
113
+ )
112
114
 
113
115
  configured = {t.safe_name for t in registry.list_taps()}
114
116
  if paths.cache_dir().is_dir():
115
- for f in sorted(paths.cache_dir().glob("*.json")):
116
- if f.stem not in configured:
117
- items.append((f, "stale tap cache", f.stat().st_size))
117
+ items.extend(
118
+ (f, "stale tap cache", f.stat().st_size)
119
+ for f in sorted(paths.cache_dir().glob("*.json"))
120
+ if f.stem not in configured
121
+ )
118
122
 
119
123
  if paths.lock_history_dir().is_dir():
120
124
  snaps = sorted(paths.lock_history_dir().glob("lock-*.json"))
121
- for old in snaps[:-50]:
122
- items.append((old, "old lock history", old.stat().st_size))
125
+ items.extend(
126
+ (old, "old lock history", old.stat().st_size)
127
+ for old in snaps[:-50]
128
+ )
123
129
 
124
130
  if paths.store_dir().is_dir():
125
131
  for pth in sorted(paths.store_dir().rglob("*")):
@@ -442,7 +448,7 @@ def cmd_onboard(argv) -> int:
442
448
  text=True, timeout=120)
443
449
  except (subprocess.TimeoutExpired, OSError) as e:
444
450
  raise BoostError("gh pr create failed: %s" % e,
445
- hint="branch %s is committed — push it and open the PR manually" % branch)
451
+ hint="branch %s is committed — push it and open the PR manually" % branch) from e
446
452
  if proc.returncode != 0:
447
453
  tail = (proc.stderr or proc.stdout or "").strip().splitlines()
448
454
  raise BoostError("gh pr create failed: %s" % (tail[-1] if tail else "unknown error"),
@@ -669,7 +675,7 @@ def cmd_schedule(argv) -> int:
669
675
  kept = [ln for ln in lines if not ln.rstrip().endswith(_CRON_MARK)]
670
676
  try:
671
677
  proc = subprocess.run(["crontab", "-"],
672
- input="\n".join(kept + [entry]) + "\n",
678
+ input="\n".join([*kept, entry]) + "\n",
673
679
  capture_output=True, text=True, timeout=30)
674
680
  except (OSError, subprocess.TimeoutExpired):
675
681
  proc = None
@@ -943,7 +949,7 @@ def cmd_mcp(argv) -> int:
943
949
  proc = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
944
950
  except (OSError, subprocess.TimeoutExpired) as e:
945
951
  raise BoostError("claude mcp %s failed: %s" % (args.action, e),
946
- hint="run it yourself: " + " ".join(cmd))
952
+ hint="run it yourself: " + " ".join(cmd)) from e
947
953
  for ln in (proc.stdout or "").strip().splitlines():
948
954
  out.info(ln)
949
955
  if proc.returncode != 0:
@@ -17,11 +17,12 @@ import urllib.parse
17
17
  from pathlib import Path
18
18
 
19
19
  from .. import cliparse, spin
20
- from ..core import (agents, ai, catalog, config, dense, embed, gitutil,
20
+ from ..core import (agents, ai, catalog, config, gitutil,
21
21
  journal, lockfile, paths, rag, registry, store, util)
22
22
  from ..core import output as out
23
23
  from ..core.stackprobe import detect_stack # re-exported: shared with Quality
24
24
  from ..errors import BoostError
25
+ import contextlib
25
26
 
26
27
  __all__ = ["detect_stack"]
27
28
 
@@ -31,7 +32,7 @@ def _positive_int(s: str) -> int:
31
32
  try:
32
33
  v = int(s)
33
34
  except ValueError:
34
- raise argparse.ArgumentTypeError("invalid int value: %r" % s)
35
+ raise argparse.ArgumentTypeError("invalid int value: %r" % s) from None
35
36
  if v < 1:
36
37
  raise argparse.ArgumentTypeError("must be >= 1")
37
38
  return v
@@ -164,6 +165,11 @@ def cmd_reindex(argv):
164
165
  stats = rag.build(force=args.force)
165
166
  dense_stats = None
166
167
  if args.dense:
168
+ # Imported lazily (only on `--dense`) so the optional dense/embedding
169
+ # stack never loads for the common offline commands this module also
170
+ # holds — count, stats, trending, plain search. See the import-budget
171
+ # gate (scripts/import_budget.py).
172
+ from ..core import embed
167
173
  with spin.Spinner("embedding chunks into the dense store"):
168
174
  dense_stats = _reindex_dense(args.force)
169
175
  if args.as_json:
@@ -191,6 +197,9 @@ def cmd_reindex(argv):
191
197
 
192
198
  def _reindex_dense(force):
193
199
  """Build the dense vector store; returns stats or None when unavailable."""
200
+ # Local import: the dense/embedding engines are opt-in (`search --dense`),
201
+ # so they stay out of startup for every other command in this module.
202
+ from ..core import dense, embed
194
203
  if not dense.have_backend() or not embed.available():
195
204
  return None
196
205
  return dense.build(force=force)
@@ -219,7 +228,7 @@ def cmd_index(argv):
219
228
  "search/code?q=filename:SKILL.md&per_page=100&page=%d" % page],
220
229
  capture_output=True, text=True, timeout=120)
221
230
  except (subprocess.TimeoutExpired, OSError) as e:
222
- raise BoostError("gh api timed out on page %d" % page, hint=str(e))
231
+ raise BoostError("gh api timed out on page %d" % page, hint=str(e)) from e
223
232
  if proc.returncode != 0:
224
233
  tail = "\n".join((proc.stderr or proc.stdout or "").strip()
225
234
  .splitlines()[-3:])
@@ -233,7 +242,7 @@ def cmd_index(argv):
233
242
  data = json.loads(proc.stdout)
234
243
  except json.JSONDecodeError:
235
244
  raise BoostError("gh api returned unparseable JSON",
236
- hint="try `boost index` again, or `gh auth status`")
245
+ hint="try `boost index` again, or `gh auth status`") from None
237
246
  if page == 1:
238
247
  total = int(data.get("total_count") or 0)
239
248
  batch = data.get("items") or []
@@ -328,7 +337,7 @@ def cmd_discover(argv):
328
337
  data = json.loads(dpath.read_text(encoding="utf-8"))
329
338
  except (json.JSONDecodeError, OSError):
330
339
  raise BoostError("the discovery index is corrupt",
331
- hint="rebuild it with `boost index`")
340
+ hint="rebuild it with `boost index`") from None
332
341
  all_items = data.get("items") or []
333
342
  tokens = [t.lower() for t in args.query if t.strip()]
334
343
  items = [it for it in all_items
@@ -598,7 +607,7 @@ def _aurora_pairs(curses):
598
607
  """Allocate Aurora curses colour pairs; token-name -> attr int (0 if none)."""
599
608
  names = ("cyan", "violet", "pink", "green", "yellow")
600
609
  try:
601
- custom = curses.can_change_color() and curses.COLORS >= 16 + len(names)
610
+ custom = curses.can_change_color() and 16 + len(names) <= curses.COLORS
602
611
  except curses.error:
603
612
  custom = False
604
613
  fg = dict(_nearest_base(curses))
@@ -695,19 +704,15 @@ def _browse_tui(curses, entries):
695
704
  return "loading description…"
696
705
 
697
706
  def ui(scr):
698
- try:
707
+ with contextlib.suppress(curses.error):
699
708
  curses.curs_set(0)
700
- except curses.error:
701
- pass
702
709
  scr.timeout(80) # short poll so a finished lazy-load redraws promptly
703
710
  th = _aurora_theme(curses)
704
711
 
705
712
  def put(y, x, s, attr=0): # clip-safe cell writer
706
713
  if 0 <= y < _h and 0 <= x < _w - 1 and s:
707
- try:
714
+ with contextlib.suppress(curses.error):
708
715
  scr.addnstr(y, x, s, _w - 1 - x, attr)
709
- except curses.error:
710
- pass
711
716
 
712
717
  filt, sel, detail = "", 0, False
713
718
  selected: set = set()
@@ -31,7 +31,7 @@ def _read(p: Path) -> str:
31
31
  try:
32
32
  return Path(p).read_text(encoding="utf-8", errors="replace")
33
33
  except OSError as e:
34
- raise BoostError("cannot read %s: %s" % (_tilde(p), e))
34
+ raise BoostError("cannot read %s: %s" % (_tilde(p), e)) from e
35
35
 
36
36
 
37
37
  def _resolve_skill_md(name: str):
@@ -115,7 +115,7 @@ def _kind_table(heading, items, extra=None):
115
115
  row.append(str(e.get(extra[1], "") or ""))
116
116
  rows.append(tuple(row))
117
117
  if extra:
118
- headers = headers + (extra[0],)
118
+ headers = (*headers, extra[0])
119
119
  out.table(rows, headers=headers)
120
120
  noun = heading.split()[-1][:-1] # "installed rules" -> "rule"
121
121
  print(" " + out.aurora("%d %s%s installed"
@@ -319,10 +319,10 @@ def cmd_edit(argv):
319
319
  editor = os.environ.get("VISUAL") or os.environ.get("EDITOR") or "vi"
320
320
  cmd = shlex.split(editor) or ["vi"] # support EDITOR="code -w" etc.
321
321
  try:
322
- rc = subprocess.call(cmd + [str(path)])
322
+ rc = subprocess.call([*cmd, str(path)])
323
323
  except OSError as e:
324
324
  raise BoostError("cannot launch editor %r: %s" % (editor, e),
325
- hint="set $VISUAL or $EDITOR to a valid command")
325
+ hint="set $VISUAL or $EDITOR to a valid command") from e
326
326
  if rc != 0:
327
327
  out.warn("editor exited with status %d" % rc)
328
328
  sha = util.sha256_dir(sdir)
@@ -595,9 +595,11 @@ def cmd_deps(argv):
595
595
  unmet, pairs, seen = [], [], set()
596
596
  for name in sorted(inst):
597
597
  meta = _skill_meta(name) or {}
598
- for r in _as_list(meta.get("requires")):
599
- if r not in inst:
600
- unmet.append({"skill": name, "requires": r})
598
+ unmet.extend(
599
+ {"skill": name, "requires": r}
600
+ for r in _as_list(meta.get("requires"))
601
+ if r not in inst
602
+ )
601
603
  for c_name in _as_list(meta.get("conflicts")):
602
604
  if c_name in inst:
603
605
  key = tuple(sorted((name, c_name)))
@@ -22,6 +22,7 @@ from ..core import (ai, catalog, frontmatter, gitutil, imperative, journal,
22
22
  lockfile, paths, store, util)
23
23
  from ..core import output as out
24
24
  from ..errors import BoostError
25
+ import contextlib
25
26
 
26
27
  # ---------------------------------------------------------------- helpers
27
28
 
@@ -777,9 +778,8 @@ def cmd_context(argv: List[str]) -> int:
777
778
  inst = lockfile.installed()
778
779
  for name in sorted(_mentioned_skills(state)):
779
780
  entry = inst.get(name)
780
- if entry and not entry.get("quarantined"):
781
- if store.link_agents(name).linked:
782
- restored += 1
781
+ if entry and not entry.get("quarantined") and store.link_agents(name).linked:
782
+ restored += 1
783
783
  state["enabled"] = False
784
784
  _save_state(_CONTEXT_STATE, state)
785
785
  journal.log("context", "disable", restored=restored)
@@ -1005,10 +1005,8 @@ def _repo_activity(since: str) -> Tuple[Optional[int], Optional[int]]:
1005
1005
  proc = gitutil.run(["rev-list", "--count", "--since=" + since, "HEAD"],
1006
1006
  cwd=Path.cwd(), check=False)
1007
1007
  if proc.returncode == 0:
1008
- try:
1008
+ with contextlib.suppress(ValueError):
1009
1009
  commits = int(proc.stdout.strip() or 0)
1010
- except ValueError:
1011
- pass
1012
1010
  proc = gitutil.run(["log", "--name-only", "--since=" + since,
1013
1011
  "--pretty=format:"], cwd=Path.cwd(), check=False)
1014
1012
  if proc.returncode == 0:
@@ -568,7 +568,7 @@ def _bundle_dump(file: Optional[str]) -> int:
568
568
  dest.write_text(text, encoding="utf-8")
569
569
  except OSError as e:
570
570
  raise BoostError("cannot write %s: %s" % (_tilde(dest), e.strerror or e),
571
- hint="check the path exists and is writable")
571
+ hint="check the path exists and is writable") from e
572
572
  n_taps = sum(1 for ln in text.splitlines() if ln.startswith("tap "))
573
573
  n_skills = sum(1 for ln in text.splitlines() if ln.startswith("skill "))
574
574
  out.ok("wrote %s (%s, %s)" % (_tilde(dest), _plural(n_taps, "tap"),
@@ -591,7 +591,7 @@ def _bundle_install(file: Optional[str]) -> int:
591
591
  try:
592
592
  text, label = path.read_text(encoding="utf-8"), str(path)
593
593
  except OSError as e:
594
- raise BoostError("cannot read %s: %s" % (_tilde(path), e.strerror or e))
594
+ raise BoostError("cannot read %s: %s" % (_tilde(path), e.strerror or e)) from e
595
595
  taps_added = installed_n = present = failed = 0
596
596
  have_taps = {t.name for t in registry.list_taps()}
597
597
  have_skills = set(lockfile.installed())
@@ -929,18 +929,18 @@ def _snapshot_restore(snap_id: str) -> int:
929
929
  # Read the whole archive BEFORE touching the store, so a corrupt
930
930
  # snapshot can never leave us with an emptied environment.
931
931
  try:
932
- tf = tarfile.open(str(tar_path), "r:gz")
932
+ tf = tarfile.open(str(tar_path), "r:gz") # noqa: SIM115 (opened in a try to translate the error; used via `with tf:` below)
933
933
  except (tarfile.TarError, OSError, EOFError) as e:
934
934
  raise BoostError("snapshot %s is unreadable: %s" % (snap_id, e),
935
935
  hint="the store was left untouched — "
936
- "see `boost snapshot list` for other snapshots")
936
+ "see `boost snapshot list` for other snapshots") from e
937
937
  with tf:
938
938
  try:
939
939
  members = tf.getmembers()
940
940
  except (tarfile.TarError, OSError, EOFError) as e:
941
941
  raise BoostError("snapshot %s is corrupt: %s" % (snap_id, e),
942
942
  hint="the store was left untouched — "
943
- "see `boost snapshot list` for other snapshots")
943
+ "see `boost snapshot list` for other snapshots") from e
944
944
  for child in root.iterdir():
945
945
  if child.is_dir() and not child.is_symlink():
946
946
  util.rmtree(child)
@@ -1012,7 +1012,7 @@ def cmd_export(argv: List[str]) -> int:
1012
1012
  tf.add(str(store.skill_store_dir(name)), arcname=name)
1013
1013
  except OSError as e:
1014
1014
  raise BoostError("cannot write %s: %s" % (_tilde(dest), e.strerror or e),
1015
- hint="check the output path exists and is writable")
1015
+ hint="check the output path exists and is writable") from e
1016
1016
  out.ok("exported %s → %s (%s)" % (_plural(len(chosen), "skill"),
1017
1017
  _tilde(dest.resolve()),
1018
1018
  util.human_size(dest.stat().st_size)))
@@ -1063,7 +1063,7 @@ def cmd_adapt(argv: List[str]) -> int:
1063
1063
  util.atomic_write_text(dest, source)
1064
1064
  except OSError as e:
1065
1065
  raise BoostError("cannot write %s: %s" % (_tilde(dest), e.strerror or e),
1066
- hint="check the output path exists and is writable")
1066
+ hint="check the output path exists and is writable") from e
1067
1067
  out.ok("adapted %s → %s (%s · %s)" % (display, _tilde(dest.resolve()),
1068
1068
  args.to, model or "framework default"))
1069
1069
  else:
@@ -96,9 +96,10 @@ def _broken_links() -> List[Path]:
96
96
  for adir in agents.enabled_agents().values():
97
97
  if not adir.is_dir():
98
98
  continue
99
- for link in sorted(adir.iterdir()):
100
- if link.is_symlink() and not link.exists():
101
- broken.append(link)
99
+ broken.extend(
100
+ link for link in sorted(adir.iterdir())
101
+ if link.is_symlink() and not link.exists()
102
+ )
102
103
  return broken
103
104
 
104
105
 
@@ -353,7 +354,7 @@ def cmd_doctor(argv):
353
354
  bad("%d broken symlink%s in agent dirs — run `boost heal`"
354
355
  % (len(broken), _s(len(broken))))
355
356
 
356
- for agent, adir in enabled.items():
357
+ for adir in enabled.values():
357
358
  if adir.is_dir() and not os.access(str(adir), os.W_OK):
358
359
  bad("agent dir %s is not writable" % _tilde(adir))
359
360
 
@@ -776,10 +777,7 @@ def cmd_heal(argv):
776
777
  dry = args.dry_run
777
778
  actions: List[str] = []
778
779
 
779
- wanted = [paths.boost_home(), paths.repos_dir(), paths.cache_dir(),
780
- paths.logs_dir(), paths.state_dir(), paths.snapshots_dir(),
781
- paths.lock_history_dir(), paths.profiles_dir(),
782
- paths.store_dir()] + list(agents.enabled_agents().values())
780
+ wanted = [paths.boost_home(), paths.repos_dir(), paths.cache_dir(), paths.logs_dir(), paths.state_dir(), paths.snapshots_dir(), paths.lock_history_dir(), paths.profiles_dir(), paths.store_dir(), *list(agents.enabled_agents().values())]
783
781
  missing = [d for d in wanted if not d.is_dir()]
784
782
  if missing:
785
783
  if dry:
@@ -859,9 +857,11 @@ def cmd_conflict(argv):
859
857
  for name, _entry in installed:
860
858
  meta, body = _read_skill(store.skill_store_dir(name))
861
859
  conflicts = meta.get("conflicts") or []
862
- for other in (conflicts if isinstance(conflicts, list) else [conflicts]):
863
- if str(other) in installed_names and str(other) != name:
864
- declared.append((name, str(other)))
860
+ declared.extend(
861
+ (name, str(other))
862
+ for other in (conflicts if isinstance(conflicts, list) else [conflicts])
863
+ if str(other) in installed_names and str(other) != name
864
+ )
865
865
  for raw in body.splitlines():
866
866
  m = imperative.RULE_RE.match(raw)
867
867
  if not m:
@@ -879,7 +879,7 @@ def cmd_conflict(argv):
879
879
 
880
880
  pairs, seen = [], set()
881
881
  for da, db in declared:
882
- key = tuple(sorted((da, db))) + ("declared",)
882
+ key = (*tuple(sorted((da, db))), "declared")
883
883
  if key in seen:
884
884
  continue
885
885
  seen.add(key)
@@ -183,7 +183,7 @@ def _load_profile(name: str) -> dict:
183
183
  try:
184
184
  return json.loads(p.read_text(encoding="utf-8"))
185
185
  except (json.JSONDecodeError, OSError) as e:
186
- raise BoostError("profile %s is unreadable: %s" % (name, e))
186
+ raise BoostError("profile %s is unreadable: %s" % (name, e)) from e
187
187
 
188
188
 
189
189
  def _profile_diff(profile: dict):
@@ -26,6 +26,7 @@ from typing import List, Optional
26
26
 
27
27
  from . import paths, util
28
28
  from ..errors import BoostError
29
+ import contextlib
29
30
 
30
31
  SCOPES = ("global", "project")
31
32
  MARKER = "# boost:"
@@ -87,10 +88,8 @@ def _prune_history() -> None:
87
88
  snaps = sorted(_history_dir().glob("*.json"),
88
89
  key=lambda f: (f.stat().st_mtime, f.name))
89
90
  for old in snaps[:-HISTORY_KEEP]:
90
- try:
91
+ with contextlib.suppress(OSError):
91
92
  old.unlink()
92
- except OSError:
93
- pass
94
93
 
95
94
 
96
95
  # --------------------------------------------------------------- marker helpers
@@ -150,8 +150,7 @@ def dump(meta: dict) -> str:
150
150
  for k, v in meta.items():
151
151
  if isinstance(v, list):
152
152
  lines.append("%s:" % k)
153
- for item in v:
154
- lines.append(" - %s" % item)
153
+ lines.extend(" - %s" % item for item in v)
155
154
  elif isinstance(v, bool):
156
155
  lines.append("%s: %s" % (k, "true" if v else "false"))
157
156
  elif v is None:
@@ -20,11 +20,11 @@ def run(args: List[str], cwd: Optional[Path] = None, check: bool = True,
20
20
  hint="install git, e.g. `xcode-select --install` or `brew install git`")
21
21
  try:
22
22
  proc = subprocess.run(
23
- ["git"] + args, cwd=str(cwd) if cwd else None,
23
+ ["git", *args], cwd=str(cwd) if cwd else None,
24
24
  capture_output=True, text=True, timeout=timeout,
25
25
  )
26
26
  except subprocess.TimeoutExpired:
27
- raise BoostError("git %s timed out after %ds" % (args[0], timeout))
27
+ raise BoostError("git %s timed out after %ds" % (args[0], timeout)) from None
28
28
  if check and proc.returncode != 0:
29
29
  detail = (proc.stderr or proc.stdout or "").strip().splitlines()
30
30
  raise BoostError("git %s failed: %s" % (args[0], detail[-1] if detail else "unknown error"))
@@ -107,10 +107,12 @@ def scan_text(text: str) -> List[Finding]:
107
107
  """
108
108
  findings: List[Finding] = []
109
109
  for lineno, raw in enumerate(text.splitlines(), start=1):
110
- for rule in RULES:
111
- if rule.pattern.search(raw):
112
- findings.append(Finding(rule.id, rule.severity, lineno,
113
- raw.strip()[:200], rule.description))
110
+ findings.extend(
111
+ Finding(rule.id, rule.severity, lineno,
112
+ raw.strip()[:200], rule.description)
113
+ for rule in RULES
114
+ if rule.pattern.search(raw)
115
+ )
114
116
  findings.sort(key=lambda f: (-_SEVERITY_RANK[f.severity], f.line,
115
117
  f.rule_id))
116
118
  return findings
@@ -43,6 +43,7 @@ from pathlib import Path
43
43
  from typing import List, Optional
44
44
 
45
45
  from . import paths
46
+ import contextlib
46
47
 
47
48
  LOGGER_NAME = "boost"
48
49
  MAX_BYTES = 1_000_000 # ~1 MB per file …
@@ -117,10 +118,8 @@ def reset() -> None:
117
118
  global _configured, _debug_console
118
119
  logger = logging.getLogger(LOGGER_NAME)
119
120
  for h in list(logger.handlers):
120
- try:
121
+ with contextlib.suppress(Exception):
121
122
  h.close()
122
- except Exception:
123
- pass
124
123
  logger.removeHandler(h)
125
124
  _configured = False
126
125
  _debug_console = False
@@ -236,10 +235,8 @@ def write_crash_report(exc: BaseException, argv: List[str]) -> Optional[Path]:
236
235
  "",
237
236
  ])
238
237
  # Always try to get it into the rotating trail, even if the file write fails.
239
- try:
238
+ with contextlib.suppress(Exception):
240
239
  get_logger().error("crash: %s: %s", type(exc).__name__, exc)
241
- except Exception:
242
- pass
243
240
  try:
244
241
  paths.logs_dir().mkdir(parents=True, exist_ok=True)
245
242
  report = paths.logs_dir() / ("crash-%s.log" % _file_stamp())
@@ -257,7 +254,5 @@ def _prune_crash_reports() -> None:
257
254
  except OSError:
258
255
  return
259
256
  for stale in reports[:-KEEP_CRASH_REPORTS]:
260
- try:
257
+ with contextlib.suppress(OSError):
261
258
  stale.unlink()
262
- except OSError:
263
- pass
@@ -110,7 +110,7 @@ def handle_request(req: dict, *, version: str,
110
110
  except BoostError as e:
111
111
  text = "Error: %s" % e.message + ("\nhint: %s" % e.hint if e.hint else "")
112
112
  is_err = True
113
- except Exception as e: # noqa: BLE001 — server must not die
113
+ except Exception as e:
114
114
  text, is_err = "Error: %s" % e, True
115
115
  if text is None:
116
116
  resp["error"] = {"code": -32602, "message": "unknown tool %r" % tool}
@@ -13,6 +13,7 @@ import os
13
13
  import re
14
14
  import shutil
15
15
  import sys
16
+ import contextlib
16
17
 
17
18
  RESET = "\033[0m"
18
19
  BOLD = "\033[1m"
@@ -36,10 +37,8 @@ def harden_console_encoding() -> None:
36
37
  """
37
38
  for stream in (sys.stdout, sys.stderr):
38
39
  if hasattr(stream, "reconfigure"):
39
- try:
40
+ with contextlib.suppress(OSError, ValueError):
40
41
  stream.reconfigure(encoding="utf-8", errors="replace")
41
- except (OSError, ValueError):
42
- pass
43
42
 
44
43
 
45
44
  def use_color(stream=None) -> bool:
@@ -273,7 +272,7 @@ def panel(lines, title: str | None = None, hue: str = "cyan") -> str:
273
272
  lines = [lines]
274
273
  widths = [visible_len(x) for x in lines]
275
274
  tw = visible_len(title) if title else 0
276
- inner = max(widths + [tw + 2]) # a titled rule needs a space each side
275
+ inner = max([*widths, tw + 2]) # a titled rule needs a space each side
277
276
 
278
277
  def b(s: str) -> str:
279
278
  return aurora(s, hue)
@@ -9,6 +9,7 @@ import json
9
9
  from typing import List
10
10
 
11
11
  from . import config, paths
12
+ import contextlib
12
13
 
13
14
  DEFAULTS = {
14
15
  "blocked_skills": [], # names never allowed
@@ -26,10 +27,8 @@ def load() -> dict:
26
27
  p = paths.policy_path()
27
28
  base = dict(DEFAULTS)
28
29
  if p.exists():
29
- try:
30
+ with contextlib.suppress(json.JSONDecodeError, OSError):
30
31
  base.update(json.loads(p.read_text(encoding="utf-8")))
31
- except (json.JSONDecodeError, OSError):
32
- pass
33
32
  return base
34
33
 
35
34