boost-skill-cli 1.0.207__tar.gz → 1.0.208__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.
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/.vale/styles/config/vocabularies/boost/accept.txt +1 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/CONTRIBUTING.md +22 -1
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/Makefile +11 -2
- {boost_skill_cli-1.0.207/boost_skill_cli.egg-info → boost_skill_cli-1.0.208}/PKG-INFO +1 -1
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/_version.py +2 -2
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/commands/info.py +6 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/commands/pkg.py +69 -0
- boost_skill_cli-1.0.208/boost_cli/core/mcpdecl.py +193 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/store.py +29 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208/boost_skill_cli.egg-info}/PKG-INFO +1 -1
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_skill_cli.egg-info/SOURCES.txt +13 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/commands.html +4 -3
- boost_skill_cli-1.0.208/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +31 -0
- boost_skill_cli-1.0.208/docs/roadmap/items/mcp-aware-skills.md +32 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap.html +33 -15
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/noxfile.py +15 -4
- boost_skill_cli-1.0.208/requirements/coverage-tools.in +11 -0
- boost_skill_cli-1.0.208/requirements/coverage-tools.txt +344 -0
- boost_skill_cli-1.0.207/requirements/lint-tools.txt → boost_skill_cli-1.0.208/requirements/lint-tools.in +12 -8
- boost_skill_cli-1.0.208/requirements/lint-tools.txt +593 -0
- boost_skill_cli-1.0.208/requirements/mutation-tools.in +16 -0
- boost_skill_cli-1.0.208/requirements/mutation-tools.txt +567 -0
- boost_skill_cli-1.0.208/requirements/release-tools.in +17 -0
- boost_skill_cli-1.0.208/requirements/release-tools.txt +773 -0
- boost_skill_cli-1.0.208/requirements/test-tools.in +16 -0
- boost_skill_cli-1.0.208/requirements/test-tools.txt +391 -0
- boost_skill_cli-1.0.208/scripts/lock_toolchain.py +153 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/setup.cfg +2 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_cli_pkg.py +151 -0
- boost_skill_cli-1.0.208/tests/unit/test_mcpdecl.py +355 -0
- boost_skill_cli-1.0.208/tests/unit/test_toolchain_lock.py +137 -0
- boost_skill_cli-1.0.207/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -20
- boost_skill_cli-1.0.207/docs/roadmap/items/mcp-aware-skills.md +0 -25
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/.gitattributes +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/.gitignore +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/.gitleaks.toml +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/.htmlvalidate.json +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/.lighthouserc.json +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/.lycheeignore +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/.markdownlint-cli2.jsonc +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/.pre-commit-config.yaml +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/.stylelintrc.json +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/.vale/styles/boost/Terminology.yml +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/.vale.ini +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/CLAUDE.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/LICENSE +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/MANIFEST.in +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/README.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/SECURITY.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/__init__.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/__main__.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/cli.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/cliparse.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/commands/__init__.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/commands/_common.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/commands/bmad.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/commands/configuration.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/commands/discovery.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/commands/hooks.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/commands/intelligence.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/commands/quality.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/commands/run.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/commands/safety.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/commands/taps.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/commands/team.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/__init__.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/adapters.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/agents.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/ai.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/capabilities.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/catalog.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/claude_settings.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/config.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/dense.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/ed25519.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/embed.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/faithfulness.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/frontmatter.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/gitutil.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/imperative.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/injectscan.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/integrity.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/journal.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/lockfile.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/logs.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/mcp.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/minisign.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/nethttp.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/output.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/paths.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/policy.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/projectlock.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/provenance.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/rag.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/registry.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/resolve.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/rules.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/scopes.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/secretscan.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/serve.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/stackprobe.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/staleness.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/trustaudit.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/typosquat.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/updatediff.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/util.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/core/workflows.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/data/registries.json +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/errors.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_cli/spin.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_skill_cli.egg-info/entry_points.txt +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_skill_cli.egg-info/requires.txt +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/boost_skill_cli.egg-info/top_level.txt +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/.claude/settings.local.json +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/DEBUGGING.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/adapters.html +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/demo.gif +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/demo.tape +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/design-roadmap.html +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/eval.html +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/index.html +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/mcp-hub.html +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/rag-architecture.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D01.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D02.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D03.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D04.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D05.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D06.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D07.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D08.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D09.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D10.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D11.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D12.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D13.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D14.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D15.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D16.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D17.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D18.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D19.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D20.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D21.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D22.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D23.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D24.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D25.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/BOOST-D26.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/boost-run-live-agents.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/command-reference-docs-site.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/docsite-chrome-and-content-audit.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/framework-adapter-multi-agent.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/html-validation-html-validate.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/install-resolves-skill-dependencies.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/install-scope-user-or-project.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/installed-skill-trust-audit.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/mcp-search-before-reinventing.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/pin-the-lint-toolchain.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/project-scope-across-every-command.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/project-scope-symlink-escape-on-write.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/typo-detection-codespell.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/update-diff-before-apply.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/docs/roadmap/items/workspace-scope-install.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/eslint.config.mjs +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/examples/README.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/examples/adapt-demo.sh +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/examples/boost-run-prototype.sh +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/index.html +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/pyproject.toml +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/scripts/bench_cli.sh +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/scripts/build_command_reference.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/scripts/build_registries.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/scripts/build_roadmap.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/scripts/check_anchors.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/scripts/ensure_eval_corpus.sh +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/scripts/eval_explain.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/scripts/eval_recommend.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/scripts/eval_retrieval.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/scripts/eval_stats_summary.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/scripts/import_budget.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/scripts/mutation_gate.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/scripts/perf_gate.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/style/README.md +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/style/boost.css +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/style/boost.js +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/style/demo.html +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/bdd/features/adapt.feature +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/bdd/features/browse.feature +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/bdd/features/count.feature +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/bdd/features/discover.feature +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/bdd/features/doctor.feature +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/bdd/features/environment.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/bdd/features/explain.feature +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/bdd/features/index.feature +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/bdd/features/install.feature +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/bdd/features/list.feature +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/bdd/features/mcp.feature +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/bdd/features/search.feature +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/bdd/features/steps/cli_steps.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/bdd/features/steps/discovery_steps.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/bdd/features/steps/mcp_steps.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/bdd/features/steps/quality_steps.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/conftest.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/eval/baseline.json +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/eval/explain.jsonl +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/eval/golden.jsonl +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/eval/recommend.jsonl +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/eval/taps.txt +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_capabilities_policy.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_cli_adapt.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_cli_bmad.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_cli_configuration.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_cli_discovery.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_cli_hooks.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_cli_info.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_cli_intelligence.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_cli_quality.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_cli_taps.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_cli_team.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_everyday_loop.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_integrity_enforce.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_property_parsers.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_run.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_tap_signing.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/functional/test_workspace_scope.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/make_fixture.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/perf/test_benchmarks.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/smoke.sh +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_adapters.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_adapters_multi.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_adapters_runner.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_agents.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_ai.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_capabilities.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_catalog.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_check_anchors.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_claude_settings.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_cliparse.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_command_reference_fresh.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_config.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_dense.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_dense_fallback.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_docs_pages_linked.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_docsite_chrome.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_ed25519.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_embed.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_errors_and_cli_table.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_eval_stats_summary.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_faithfulness.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_frontmatter.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_gitleaks_config.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_gitutil.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_imperative.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_import_budget.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_injectscan.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_integrity.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_journal.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_lockfile.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_logs.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_mcp.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_minisign.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_mutation_hardening.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_nethttp.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_output.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_paths.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_perf_gate.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_pkg_confusions.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_pkg_injection.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_pkg_secrets.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_policy.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_projectlock.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_provenance.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_rag.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_registries_fresh.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_registry.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_resolve.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_roadmap_fresh.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_rules.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_scopes.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_secretscan.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_serve.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_spin.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_stackprobe.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_staleness.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_store.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_token_parity.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_trustaudit.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_typosquat.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_updatediff.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_util.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_version.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/unit/test_workflows.py +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/visual/package.json +0 -0
- {boost_skill_cli-1.0.207 → boost_skill_cli-1.0.208}/tests/visual/visual_check.mjs +0 -0
|
@@ -7,12 +7,31 @@ so contributing is mostly about keeping the quality gates green.
|
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
9
|
git clone https://github.com/jonnyeclectic/boost && cd boost
|
|
10
|
-
make venv #
|
|
10
|
+
make venv # every gate tool, hash-pinned — runtime stays stdlib-only
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
Every test runs against a throwaway `$HOME`, so nothing touches your real
|
|
14
14
|
agent configs.
|
|
15
15
|
|
|
16
|
+
### The toolchain is hash-pinned
|
|
17
|
+
|
|
18
|
+
`make venv` and every CI job install from the generated
|
|
19
|
+
[`requirements/*.txt`](requirements/), which pin an exact version **and every
|
|
20
|
+
artifact's sha256** for the full transitive closure — pip enforces those hashes,
|
|
21
|
+
so a yanked or tampered dependency fails the install instead of silently
|
|
22
|
+
changing a build. Your venv and the CI runner get identical bytes.
|
|
23
|
+
|
|
24
|
+
To change a tool, edit the `.in` file and regenerate:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
python3 scripts/lock_toolchain.py # rewrite the .txt files
|
|
28
|
+
python3 scripts/lock_toolchain.py --upgrade # re-resolve to newest allowed
|
|
29
|
+
python3 scripts/lock_toolchain.py --check # what `make lint` runs
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Commit both the `.in` and the regenerated `.txt`; a stale lock fails `make lint`.
|
|
33
|
+
Regenerating needs `uv` (installed by `make venv`); *installing* never does.
|
|
34
|
+
|
|
16
35
|
### Reproduce the whole gate — `nox`
|
|
17
36
|
|
|
18
37
|
[`noxfile.py`](noxfile.py) runs the exact gate the CI jobs run, in isolated
|
|
@@ -58,6 +77,8 @@ auto-fixes straight back onto the branch.
|
|
|
58
77
|
| `lint-imports` | layering: `core/` imports no `commands/`/`cli`; CLI depends inward |
|
|
59
78
|
| `vulture` | dead-code radar: no unused imports / unreachable code (confidence ≥80) |
|
|
60
79
|
| `xenon` | complexity ratchet: aggregate cyclomatic complexity can't regress (avg ≤B) |
|
|
80
|
+
| `refurb boost_cli` | modernization smells the ruff families miss, zero findings |
|
|
81
|
+
| `scripts/lock_toolchain.py --check` | the hash-pinned toolchain matches its `.in` declarations |
|
|
61
82
|
|
|
62
83
|
## Ground rules
|
|
63
84
|
|
|
@@ -12,10 +12,18 @@ EVAL_HOME := $(CURDIR)/.eval-home
|
|
|
12
12
|
|
|
13
13
|
.PHONY: venv test unit functional smoke coverage patch-coverage mutation lint check demo clean-test eval eval-ai eval-rec eval-stats eval-explain audit dist-check bdd bench bench-cli
|
|
14
14
|
|
|
15
|
+
# Every tool comes from a hash-pinned requirements/*.txt — the same files CI
|
|
16
|
+
# installs (see scripts/lock_toolchain.py). pip enforces the hashes, so a dev
|
|
17
|
+
# venv and a CI runner resolve to identical bytes. mutation-tools.txt is a
|
|
18
|
+
# superset of test-tools.txt, so installing it alone covers both; the two are
|
|
19
|
+
# never layered because pip enforces hashes across the whole resolution.
|
|
15
20
|
venv:
|
|
16
21
|
python3 -m venv $(VENV)
|
|
17
|
-
$(VENV)/bin/pip -q install
|
|
18
|
-
$(VENV)/bin/pip -q install -r requirements/
|
|
22
|
+
$(VENV)/bin/pip -q install -r requirements/mutation-tools.txt
|
|
23
|
+
$(VENV)/bin/pip -q install -r requirements/coverage-tools.txt
|
|
24
|
+
$(VENV)/bin/pip -q install -r requirements/lint-tools.txt
|
|
25
|
+
$(VENV)/bin/pip -q install -r requirements/release-tools.txt
|
|
26
|
+
$(VENV)/bin/pip -q install uv # regenerates the locks; not itself locked
|
|
19
27
|
|
|
20
28
|
unit:
|
|
21
29
|
$(PYTEST) tests/unit -q
|
|
@@ -57,6 +65,7 @@ lint:
|
|
|
57
65
|
$(PY) scripts/build_registries.py --check
|
|
58
66
|
$(PY) scripts/build_roadmap.py --check
|
|
59
67
|
$(PY) scripts/build_command_reference.py --check
|
|
68
|
+
$(PY) scripts/lock_toolchain.py --check
|
|
60
69
|
$(PY) scripts/import_budget.py
|
|
61
70
|
$(PY) scripts/perf_gate.py
|
|
62
71
|
$(PY) scripts/check_anchors.py
|
|
@@ -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.
|
|
22
|
-
__version_tuple__ = version_tuple = (1, 0,
|
|
21
|
+
__version__ = version = '1.0.208'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 0, 208)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -239,6 +239,7 @@ def cmd_info(argv):
|
|
|
239
239
|
declared_caps = sorted(capabilities.declared(meta))
|
|
240
240
|
detected_extra = sorted(capabilities.detect(skill_text)
|
|
241
241
|
- set(declared_caps)) if skill_text else []
|
|
242
|
+
mcp_servers = store.declared_mcp_servers(skill_dir) if skill_dir else []
|
|
242
243
|
score = size = files = None
|
|
243
244
|
if skill_dir:
|
|
244
245
|
score, _notes = util.score_skill(skill_dir)
|
|
@@ -249,6 +250,7 @@ def cmd_info(argv):
|
|
|
249
250
|
"name": name, "description": desc,
|
|
250
251
|
"installed": lock, "project": plock,
|
|
251
252
|
"capabilities": declared_caps, "detected_capabilities": detected_extra,
|
|
253
|
+
"mcp_servers": [r["name"] for r in mcp_servers],
|
|
252
254
|
"latest": (cat or {}).get("version"),
|
|
253
255
|
"tap": (lock or plock or cat or {}).get("tap"),
|
|
254
256
|
"store": str(sdir) if lock and sdir.is_dir() else None,
|
|
@@ -322,6 +324,10 @@ def cmd_info(argv):
|
|
|
322
324
|
# under-declaration signal a reviewer wants to see.
|
|
323
325
|
out.kv("detected", out.role(", ".join(detected_extra) + " (not declared)",
|
|
324
326
|
"warn"))
|
|
327
|
+
if mcp_servers:
|
|
328
|
+
# A skill that needs an MCP server is useless without it, so this belongs
|
|
329
|
+
# next to capabilities: both answer "what does this expect of my setup?"
|
|
330
|
+
out.kv("mcp servers", ", ".join(r["name"] for r in mcp_servers))
|
|
325
331
|
if score is not None:
|
|
326
332
|
out.kv("quality", "%d/100" % score)
|
|
327
333
|
out.kv("size", util.human_size(size))
|
|
@@ -109,6 +109,67 @@ def _warn_secrets(res: store.InstallResult) -> None:
|
|
|
109
109
|
out.warn(" L%d [%s] %s" % (f.line, f.severity, f.description))
|
|
110
110
|
|
|
111
111
|
|
|
112
|
+
def _offer_mcp(res: store.InstallResult) -> None:
|
|
113
|
+
"""Surface the MCP servers a just-installed skill needs, and offer to wire them.
|
|
114
|
+
|
|
115
|
+
A skill that only works paired with an MCP server used to install "cleanly"
|
|
116
|
+
and then fail in the agent for a reason nothing surfaced. Now the requirement
|
|
117
|
+
is stated at install time, and boost offers to run the registration for the
|
|
118
|
+
servers that came with a runnable spec.
|
|
119
|
+
|
|
120
|
+
Advisory, never fatal: a declined prompt, a missing ``claude`` CLI or a failed
|
|
121
|
+
registration all leave the skill installed. Suppressed entirely by
|
|
122
|
+
``--no-mcp``, which sets ``BOOST_NO_MCP_OFFER``.
|
|
123
|
+
"""
|
|
124
|
+
rows = res.mcp_servers
|
|
125
|
+
if not rows or os.environ.get("BOOST_NO_MCP_OFFER"):
|
|
126
|
+
return
|
|
127
|
+
from ..core import mcpdecl
|
|
128
|
+
out.info("")
|
|
129
|
+
out.warn("%s needs %s to work:" % (res.name, _plural(len(rows), "MCP server")))
|
|
130
|
+
for row in rows:
|
|
131
|
+
how = ("`%s`" % row["spec"]["command"] if row["spec"]
|
|
132
|
+
and row["spec"].get("command") else "no command declared")
|
|
133
|
+
out.info(" %s %s" % (out.c(row["name"], out.BOLD),
|
|
134
|
+
out.role(how, "muted")))
|
|
135
|
+
wirable = mcpdecl.registrable(rows)
|
|
136
|
+
if not wirable:
|
|
137
|
+
# Name-only declarations: boost will not invent a command line.
|
|
138
|
+
out.dim(" install these yourself, then `boost mcp register`")
|
|
139
|
+
return
|
|
140
|
+
if not out.confirm("register %s with Claude Code now?"
|
|
141
|
+
% _plural(len(wirable), "server"), default=False):
|
|
142
|
+
out.dim(" skipped — `claude mcp add …` when you're ready")
|
|
143
|
+
return
|
|
144
|
+
for row in wirable:
|
|
145
|
+
_register_mcp_server(row["name"], row["spec"])
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _register_mcp_server(name: str, spec: dict) -> None:
|
|
149
|
+
"""Run one `claude mcp add` for a skill-declared server. Never raises."""
|
|
150
|
+
import subprocess
|
|
151
|
+
from ..core import mcpdecl
|
|
152
|
+
argv = mcpdecl.register_argv(name, spec)
|
|
153
|
+
if not shutil.which("claude"):
|
|
154
|
+
out.warn("`claude` CLI not found — run this yourself:")
|
|
155
|
+
out.info(" " + " ".join(argv))
|
|
156
|
+
return
|
|
157
|
+
try:
|
|
158
|
+
proc = subprocess.run(argv, capture_output=True, text=True, timeout=60)
|
|
159
|
+
except (OSError, subprocess.TimeoutExpired) as e:
|
|
160
|
+
out.warn("could not register %s: %s" % (name, e))
|
|
161
|
+
out.info(" run it yourself: " + " ".join(argv))
|
|
162
|
+
return
|
|
163
|
+
if proc.returncode != 0:
|
|
164
|
+
tail = (proc.stderr or "").strip().splitlines()
|
|
165
|
+
out.warn("could not register %s: %s"
|
|
166
|
+
% (name, tail[-1] if tail else "unknown error"))
|
|
167
|
+
out.info(" run it yourself: " + " ".join(argv))
|
|
168
|
+
return
|
|
169
|
+
out.ok("registered MCP server %s" % name)
|
|
170
|
+
journal.log("mcp-register", name)
|
|
171
|
+
|
|
172
|
+
|
|
112
173
|
def _report_result(res: store.InstallResult) -> None:
|
|
113
174
|
"""The canonical three-line install report."""
|
|
114
175
|
if res.kind in ("rule", "workflow"):
|
|
@@ -141,6 +202,7 @@ def _report_result(res: store.InstallResult) -> None:
|
|
|
141
202
|
out.ok("lock updated (.skill-lock.json)")
|
|
142
203
|
_warn_injection(res)
|
|
143
204
|
_warn_secrets(res)
|
|
205
|
+
_offer_mcp(res)
|
|
144
206
|
|
|
145
207
|
|
|
146
208
|
def _boostfile_text(skills: Dict[str, dict], via: str = "boost bundle dump") -> str:
|
|
@@ -238,8 +300,15 @@ def cmd_install(argv: List[str]) -> int:
|
|
|
238
300
|
help="show what would happen without changing anything")
|
|
239
301
|
ap.add_argument("--no-deps", action="store_true",
|
|
240
302
|
help="install only the named skills, not their `requires:`")
|
|
303
|
+
ap.add_argument("--no-mcp", action="store_true",
|
|
304
|
+
help="don't offer to register MCP servers a skill declares")
|
|
241
305
|
args = ap.parse_args(argv)
|
|
242
306
|
args.scope = args.scope or scopes.SCOPE_USER
|
|
307
|
+
if args.no_mcp:
|
|
308
|
+
# An env flag rather than threading a parameter through _report_result's
|
|
309
|
+
# eight call sites: the offer is a leaf-level side effect, and this keeps
|
|
310
|
+
# every other install path (update, reinstall, team, MCP tool) unchanged.
|
|
311
|
+
os.environ["BOOST_NO_MCP_OFFER"] = "1"
|
|
243
312
|
only = _check_agents(args.agent)
|
|
244
313
|
multi = len(args.names) > 1
|
|
245
314
|
entries, failed = [], 0
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"""What MCP servers does a skill need, and how do we wire them?
|
|
2
|
+
|
|
3
|
+
Mining boost's catalog surfaces a recurring shape: skills that only work paired
|
|
4
|
+
with a Model Context Protocol server (``manage-mcp-servers``, ``mcp-builder``,
|
|
5
|
+
``mcp-integration`` and dozens more). boost already *is* an MCP server and
|
|
6
|
+
registers itself with ``boost mcp register`` — but a skill had no way to say
|
|
7
|
+
"I need server Y," so installing one left the user to discover that by hand.
|
|
8
|
+
|
|
9
|
+
Two declaration forms, both deliberately **flat**:
|
|
10
|
+
|
|
11
|
+
* ``mcp: github, playwright`` in SKILL.md frontmatter (a comma string or a YAML
|
|
12
|
+
block list) — just the names, reusing the exact contract ``requires:`` and
|
|
13
|
+
``conflicts:`` already use.
|
|
14
|
+
* a bundled ``.mcp.json`` in the skill directory — the standard MCP shape
|
|
15
|
+
(``{"mcpServers": {name: {command, args, env}}}``), carrying full specs.
|
|
16
|
+
|
|
17
|
+
Why flat, and not the nested ``mcp:`` mapping the roadmap card sketched:
|
|
18
|
+
:mod:`boost_cli.core.frontmatter` is a stdlib-only YAML *subset* with no nested
|
|
19
|
+
mapping support, and it does not fail loudly on one — it hoists the inner keys to
|
|
20
|
+
top level and clobbers their siblings. A nested block parses to
|
|
21
|
+
``{'mcp': '', 'servers': [...], 'command': 'npx'}``, silently corrupting the
|
|
22
|
+
entry's metadata. Teaching the parser nested mappings would change the shape of
|
|
23
|
+
every catalog entry's ``meta`` (and every consumer of it), so the declaration
|
|
24
|
+
meets the parser where it already works and the full specs live in the standard
|
|
25
|
+
sidecar file that needs no parser at all.
|
|
26
|
+
|
|
27
|
+
Everything here is pure and I/O-free, like :mod:`boost_cli.core.resolve` and
|
|
28
|
+
:mod:`boost_cli.core.staleness`: callers read the files and pass text in, so
|
|
29
|
+
every branch of the *decision* is unit-testable and reachable by the mutation
|
|
30
|
+
gate.
|
|
31
|
+
"""
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import json
|
|
35
|
+
from typing import Dict, List, Optional, Tuple
|
|
36
|
+
|
|
37
|
+
# The frontmatter key a skill uses to name the servers it needs.
|
|
38
|
+
DECL_KEY = "mcp"
|
|
39
|
+
|
|
40
|
+
# The sidecar file a skill bundles to carry full server specs. Standard MCP
|
|
41
|
+
# filename and shape, so an author can lift the file straight from a server's
|
|
42
|
+
# own README.
|
|
43
|
+
SIDECAR = ".mcp.json"
|
|
44
|
+
|
|
45
|
+
# Top-level key inside .mcp.json, per the MCP config convention.
|
|
46
|
+
SERVERS_KEY = "mcpServers"
|
|
47
|
+
|
|
48
|
+
# Ownership tag written alongside a server boost registered, mirroring
|
|
49
|
+
# claude_settings.MARKER. Without it an uninstall could not tell a
|
|
50
|
+
# boost-registered server from one the user configured by hand, so it would
|
|
51
|
+
# either strip the user's config or leak boost's.
|
|
52
|
+
MARKER_KEY = "x-boost-skill"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def declared_names(meta: Optional[dict]) -> List[str]:
|
|
56
|
+
"""Server names a skill's frontmatter declares, de-duped, order preserved.
|
|
57
|
+
|
|
58
|
+
Accepts a YAML list or a comma-separated string and drops blanks — the same
|
|
59
|
+
contract ``requires:``/``conflicts:`` use, so an author who knows one knows
|
|
60
|
+
this one. A missing/empty/``False`` value means "declares nothing".
|
|
61
|
+
"""
|
|
62
|
+
val = (meta or {}).get(DECL_KEY)
|
|
63
|
+
if val in (None, "", False):
|
|
64
|
+
return []
|
|
65
|
+
raw = ([str(x) for x in val] if isinstance(val, list)
|
|
66
|
+
else str(val).split(","))
|
|
67
|
+
out: List[str] = []
|
|
68
|
+
for item in raw:
|
|
69
|
+
name = item.strip()
|
|
70
|
+
if name and name not in out:
|
|
71
|
+
out.append(name)
|
|
72
|
+
return out
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def parse_sidecar(text: Optional[str]) -> Dict[str, dict]:
|
|
76
|
+
"""``{name: spec}`` from a bundled ``.mcp.json``'s text.
|
|
77
|
+
|
|
78
|
+
Tolerant by design: unreadable JSON, a non-object document, a missing or
|
|
79
|
+
non-object ``mcpServers`` key, and non-object individual specs all read as
|
|
80
|
+
"no specs". A malformed sidecar must never make an otherwise-fine install
|
|
81
|
+
fail — the skill still works, the user just does not get the wiring offer.
|
|
82
|
+
"""
|
|
83
|
+
if not text:
|
|
84
|
+
return {}
|
|
85
|
+
try:
|
|
86
|
+
doc = json.loads(text)
|
|
87
|
+
except (ValueError, TypeError):
|
|
88
|
+
return {}
|
|
89
|
+
if not isinstance(doc, dict):
|
|
90
|
+
return {}
|
|
91
|
+
servers = doc.get(SERVERS_KEY)
|
|
92
|
+
if not isinstance(servers, dict):
|
|
93
|
+
return {}
|
|
94
|
+
return {str(k): v for k, v in servers.items()
|
|
95
|
+
if k and isinstance(v, dict)}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def servers_for(meta: Optional[dict], sidecar_text: Optional[str] = None,
|
|
99
|
+
) -> List[dict]:
|
|
100
|
+
"""Every MCP server a skill needs, as ``{"name", "spec", "source"}`` rows.
|
|
101
|
+
|
|
102
|
+
Merges the two declaration forms. A name in *both* uses the sidecar's spec —
|
|
103
|
+
the frontmatter only names a server, so a bundled spec is strictly more
|
|
104
|
+
information. ``spec`` is ``None`` for a name-only declaration, which the
|
|
105
|
+
caller renders as "you need this, here is no command to run it" rather than
|
|
106
|
+
offering a registration it cannot perform.
|
|
107
|
+
|
|
108
|
+
``source`` is ``"sidecar"`` or ``"frontmatter"``, so output can tell the user
|
|
109
|
+
where a requirement came from when the two disagree. Rows are sorted by name
|
|
110
|
+
for deterministic output.
|
|
111
|
+
"""
|
|
112
|
+
specs = parse_sidecar(sidecar_text)
|
|
113
|
+
rows: Dict[str, dict] = {
|
|
114
|
+
name: {"name": name, "spec": spec, "source": "sidecar"}
|
|
115
|
+
for name, spec in specs.items()}
|
|
116
|
+
for name in declared_names(meta):
|
|
117
|
+
if name not in rows:
|
|
118
|
+
rows[name] = {"name": name, "spec": None, "source": "frontmatter"}
|
|
119
|
+
return [rows[k] for k in sorted(rows)]
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def registrable(rows) -> List[dict]:
|
|
123
|
+
"""The rows boost can actually wire up — those carrying a runnable spec.
|
|
124
|
+
|
|
125
|
+
A spec is runnable when it names a ``command``. Anything else (a name-only
|
|
126
|
+
frontmatter declaration, or a sidecar entry describing a remote/URL server
|
|
127
|
+
boost has no launcher for) is reported to the user but never auto-registered:
|
|
128
|
+
boost will not invent a command line on an author's behalf.
|
|
129
|
+
"""
|
|
130
|
+
return [r for r in rows
|
|
131
|
+
if isinstance(r.get("spec"), dict)
|
|
132
|
+
and str(r["spec"].get("command") or "").strip()]
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def register_argv(name: str, spec: dict, *, scope: str = "user") -> List[str]:
|
|
136
|
+
"""The ``claude mcp add`` argv that registers one declared server.
|
|
137
|
+
|
|
138
|
+
Mirrors ``cmd_mcp``'s invariant exactly: the server **name** precedes every
|
|
139
|
+
``-e`` flag, and a bare ``--`` separates boost's flags from the server's own
|
|
140
|
+
command and arguments. Getting that order wrong makes the CLI read the
|
|
141
|
+
command as another flag value, which is why it is pinned by a test.
|
|
142
|
+
"""
|
|
143
|
+
argv = ["claude", "mcp", "add", name, "--scope", scope]
|
|
144
|
+
env = spec.get("env")
|
|
145
|
+
if isinstance(env, dict):
|
|
146
|
+
for key in sorted(env):
|
|
147
|
+
argv += ["-e", "%s=%s" % (key, env[key])]
|
|
148
|
+
argv.extend(("--", str(spec["command"])))
|
|
149
|
+
args = spec.get("args")
|
|
150
|
+
if isinstance(args, list):
|
|
151
|
+
argv += [str(a) for a in args]
|
|
152
|
+
return argv
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def merge_into(existing: Optional[dict], rows, skill: str) -> Tuple[dict, List[str]]:
|
|
156
|
+
"""Add ``rows``' specs to an ``.mcp.json`` document -> ``(doc, added)``.
|
|
157
|
+
|
|
158
|
+
Returns a **new** document rather than mutating the caller's, and never
|
|
159
|
+
overwrites a server the user already configured: a name already present is
|
|
160
|
+
left exactly as-is and omitted from ``added``. Each entry boost does add
|
|
161
|
+
carries a :data:`MARKER_KEY` naming the skill that asked for it, so a later
|
|
162
|
+
uninstall can remove precisely what boost wrote and nothing else.
|
|
163
|
+
"""
|
|
164
|
+
doc = dict(existing) if isinstance(existing, dict) else {}
|
|
165
|
+
servers = dict(doc.get(SERVERS_KEY) or {})
|
|
166
|
+
added: List[str] = []
|
|
167
|
+
for row in registrable(rows):
|
|
168
|
+
name = row["name"]
|
|
169
|
+
if name in servers:
|
|
170
|
+
continue
|
|
171
|
+
entry = dict(row["spec"])
|
|
172
|
+
entry[MARKER_KEY] = skill
|
|
173
|
+
servers[name] = entry
|
|
174
|
+
added.append(name)
|
|
175
|
+
doc[SERVERS_KEY] = servers
|
|
176
|
+
return doc, added
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def strip_owned(existing: Optional[dict], skill: str) -> Tuple[dict, List[str]]:
|
|
180
|
+
"""Remove the servers boost registered for ``skill`` -> ``(doc, removed)``.
|
|
181
|
+
|
|
182
|
+
Only entries whose :data:`MARKER_KEY` names this skill are removed, so a
|
|
183
|
+
server the user configured by hand — or one another skill still needs —
|
|
184
|
+
survives an uninstall untouched.
|
|
185
|
+
"""
|
|
186
|
+
doc = dict(existing) if isinstance(existing, dict) else {}
|
|
187
|
+
servers = dict(doc.get(SERVERS_KEY) or {})
|
|
188
|
+
removed = [name for name, spec in servers.items()
|
|
189
|
+
if isinstance(spec, dict) and spec.get(MARKER_KEY) == skill]
|
|
190
|
+
for name in removed:
|
|
191
|
+
del servers[name]
|
|
192
|
+
doc[SERVERS_KEY] = servers
|
|
193
|
+
return doc, sorted(removed)
|
|
@@ -5,6 +5,7 @@ install(): copy skill dir from a tap clone -> store, symlink into every
|
|
|
5
5
|
"""
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
|
+
import contextlib
|
|
8
9
|
import os
|
|
9
10
|
import re
|
|
10
11
|
import shutil
|
|
@@ -33,6 +34,10 @@ class InstallResult:
|
|
|
33
34
|
# CLAUDE.md block), not a SKILL.md tree — carry the raw source so the caller
|
|
34
35
|
# scans exactly what it installed instead of a non-existent SKILL.md.
|
|
35
36
|
scan_text: Optional[str] = None
|
|
37
|
+
# MCP servers the skill declares (mcpdecl.servers_for rows). Detected here
|
|
38
|
+
# but never acted on: core stays non-interactive, so the command layer owns
|
|
39
|
+
# the offer to register them — same split as `conflicts` and `score`.
|
|
40
|
+
mcp_servers: List[dict] = field(default_factory=list)
|
|
36
41
|
|
|
37
42
|
|
|
38
43
|
def skill_store_dir(name: str) -> Path:
|
|
@@ -149,6 +154,28 @@ def _remove_backup(backup: Path) -> None:
|
|
|
149
154
|
shutil.rmtree(backup, ignore_errors=True)
|
|
150
155
|
|
|
151
156
|
|
|
157
|
+
def declared_mcp_servers(skill_dir) -> List[dict]:
|
|
158
|
+
"""MCP servers an installed skill declares — ``mcpdecl.servers_for`` rows.
|
|
159
|
+
|
|
160
|
+
Reads the installed copy's ``SKILL.md`` frontmatter and its bundled
|
|
161
|
+
``.mcp.json`` sidecar, if either is present. Best-effort by design: an
|
|
162
|
+
unreadable file yields no rows rather than failing an install that has
|
|
163
|
+
otherwise already succeeded.
|
|
164
|
+
"""
|
|
165
|
+
from . import frontmatter, mcpdecl
|
|
166
|
+
skill_dir = Path(skill_dir)
|
|
167
|
+
meta: dict = {}
|
|
168
|
+
with contextlib.suppress(OSError):
|
|
169
|
+
text = (skill_dir / "SKILL.md").read_text(encoding="utf-8",
|
|
170
|
+
errors="replace")
|
|
171
|
+
meta, _body = frontmatter.parse(text)
|
|
172
|
+
sidecar = None
|
|
173
|
+
with contextlib.suppress(OSError):
|
|
174
|
+
sidecar = (skill_dir / mcpdecl.SIDECAR).read_text(encoding="utf-8",
|
|
175
|
+
errors="replace")
|
|
176
|
+
return mcpdecl.servers_for(meta, sidecar)
|
|
177
|
+
|
|
178
|
+
|
|
152
179
|
def _enforce_capability_policy(name: str, skill_md: Path) -> None:
|
|
153
180
|
"""Raise if the skill's declared/detected capabilities are denied by policy.
|
|
154
181
|
|
|
@@ -245,6 +272,7 @@ def install(entry: dict, force: bool = False,
|
|
|
245
272
|
res = link_agents(name, only=only_agents)
|
|
246
273
|
res.upgraded = existing is not None
|
|
247
274
|
res.score, _ = util.score_skill(dest)
|
|
275
|
+
res.mcp_servers = declared_mcp_servers(dest)
|
|
248
276
|
|
|
249
277
|
tap = registry.get(entry["tap"])
|
|
250
278
|
from . import gitutil
|
|
@@ -696,6 +724,7 @@ def install_from_path(src_dir: Path, name: Optional[str] = None,
|
|
|
696
724
|
_copy_skill(src_dir, dest)
|
|
697
725
|
res = link_agents(name, only=only_agents)
|
|
698
726
|
res.score, _ = util.score_skill(dest)
|
|
727
|
+
res.mcp_servers = declared_mcp_servers(dest)
|
|
699
728
|
now = util.now_iso()
|
|
700
729
|
existing = lockfile.get_skill(name)
|
|
701
730
|
lockfile.set_skill(name, {
|
|
@@ -65,6 +65,7 @@ boost_cli/core/journal.py
|
|
|
65
65
|
boost_cli/core/lockfile.py
|
|
66
66
|
boost_cli/core/logs.py
|
|
67
67
|
boost_cli/core/mcp.py
|
|
68
|
+
boost_cli/core/mcpdecl.py
|
|
68
69
|
boost_cli/core/minisign.py
|
|
69
70
|
boost_cli/core/nethttp.py
|
|
70
71
|
boost_cli/core/output.py
|
|
@@ -251,7 +252,16 @@ docs/roadmap/items/workspace-scope-install.md
|
|
|
251
252
|
examples/README.md
|
|
252
253
|
examples/adapt-demo.sh
|
|
253
254
|
examples/boost-run-prototype.sh
|
|
255
|
+
requirements/coverage-tools.in
|
|
256
|
+
requirements/coverage-tools.txt
|
|
257
|
+
requirements/lint-tools.in
|
|
254
258
|
requirements/lint-tools.txt
|
|
259
|
+
requirements/mutation-tools.in
|
|
260
|
+
requirements/mutation-tools.txt
|
|
261
|
+
requirements/release-tools.in
|
|
262
|
+
requirements/release-tools.txt
|
|
263
|
+
requirements/test-tools.in
|
|
264
|
+
requirements/test-tools.txt
|
|
255
265
|
scripts/bench_cli.sh
|
|
256
266
|
scripts/build_command_reference.py
|
|
257
267
|
scripts/build_registries.py
|
|
@@ -263,6 +273,7 @@ scripts/eval_recommend.py
|
|
|
263
273
|
scripts/eval_retrieval.py
|
|
264
274
|
scripts/eval_stats_summary.py
|
|
265
275
|
scripts/import_budget.py
|
|
276
|
+
scripts/lock_toolchain.py
|
|
266
277
|
scripts/mutation_gate.py
|
|
267
278
|
scripts/perf_gate.py
|
|
268
279
|
style/README.md
|
|
@@ -344,6 +355,7 @@ tests/unit/test_journal.py
|
|
|
344
355
|
tests/unit/test_lockfile.py
|
|
345
356
|
tests/unit/test_logs.py
|
|
346
357
|
tests/unit/test_mcp.py
|
|
358
|
+
tests/unit/test_mcpdecl.py
|
|
347
359
|
tests/unit/test_minisign.py
|
|
348
360
|
tests/unit/test_mutation_hardening.py
|
|
349
361
|
tests/unit/test_nethttp.py
|
|
@@ -370,6 +382,7 @@ tests/unit/test_stackprobe.py
|
|
|
370
382
|
tests/unit/test_staleness.py
|
|
371
383
|
tests/unit/test_store.py
|
|
372
384
|
tests/unit/test_token_parity.py
|
|
385
|
+
tests/unit/test_toolchain_lock.py
|
|
373
386
|
tests/unit/test_trustaudit.py
|
|
374
387
|
tests/unit/test_typosquat.py
|
|
375
388
|
tests/unit/test_updatediff.py
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
<input id="q" type="search" placeholder="Filter 78 commands…" autocomplete="off" aria-label="Filter commands">
|
|
100
100
|
<div class="group" data-group="pkg">
|
|
101
101
|
<div class="group-h">Install & lifecycle</div>
|
|
102
|
-
<a class="cmd-link" href="#cmd-install" data-search="install install a skill from a tap registry --force --agent a --scope {user,project} --local --global --dry-run --no-deps name">install</a>
|
|
102
|
+
<a class="cmd-link" href="#cmd-install" data-search="install install a skill from a tap registry --force --agent a --scope {user,project} --local --global --dry-run --no-deps --no-mcp name">install</a>
|
|
103
103
|
<a class="cmd-link" href="#cmd-uninstall" data-search="uninstall remove an installed skill, rule, workflow, or config --local name">uninstall</a>
|
|
104
104
|
<a class="cmd-link" href="#cmd-sync" data-search="sync reconcile installed skills & symlinks against the lock file --diff --prune --json">sync</a>
|
|
105
105
|
<a class="cmd-link" href="#cmd-update" data-search="update sync taps or update installed skills --taps-only tap">update</a>
|
|
@@ -206,10 +206,10 @@
|
|
|
206
206
|
<p class="lead">All <b>78</b> commands, generated from the CLI itself —
|
|
207
207
|
run <code>boost <command> --help</code> for the same in your terminal.</p>
|
|
208
208
|
<h2 class="group-h" id="grp-pkg">Install & lifecycle</h2>
|
|
209
|
-
<section class="cmd" id="cmd-install" data-search="install install a skill from a tap registry --force --agent a --scope {user,project} --local --global --dry-run --no-deps name">
|
|
209
|
+
<section class="cmd" id="cmd-install" data-search="install install a skill from a tap registry --force --agent a --scope {user,project} --local --global --dry-run --no-deps --no-mcp name">
|
|
210
210
|
<h3><span class="cname">install</span><span class="gtag">pkg</span></h3>
|
|
211
211
|
<p class="summary">Install a skill from a tap registry</p>
|
|
212
|
-
<pre class="syn">boost install [--force] [--agent A] [--scope {user,project}] [--local] [--global] [--dry-run] [--no-deps] NAME [NAME ...]</pre>
|
|
212
|
+
<pre class="syn">boost install [--force] [--agent A] [--scope {user,project}] [--local] [--global] [--dry-run] [--no-deps] [--no-mcp] NAME [NAME ...]</pre>
|
|
213
213
|
<div class="args-h">Arguments</div>
|
|
214
214
|
<div class="args">
|
|
215
215
|
<div class="arg"><code>NAME</code><span>skill name, optionally qualified as tap:skill</span></div>
|
|
@@ -223,6 +223,7 @@
|
|
|
223
223
|
<div class="arg"><code>--global</code><span>into your user config (= --scope user, default)</span></div>
|
|
224
224
|
<div class="arg"><code>--dry-run</code><span>show what would happen without changing anything</span></div>
|
|
225
225
|
<div class="arg"><code>--no-deps</code><span>install only the named skills, not their `requires:`</span></div>
|
|
226
|
+
<div class="arg"><code>--no-mcp</code><span>don't offer to register MCP servers a skill declares</span></div>
|
|
226
227
|
</div>
|
|
227
228
|
</section>
|
|
228
229
|
<section class="cmd" id="cmd-uninstall" data-search="uninstall remove an installed skill, rule, workflow, or config --local name">
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: hash-pinned-reproducible-toolchain-uv-lock
|
|
3
|
+
board: code
|
|
4
|
+
section: compat
|
|
5
|
+
status: shipped
|
|
6
|
+
category: Security · Repro
|
|
7
|
+
complexity: M
|
|
8
|
+
impact: Med
|
|
9
|
+
wow: 3
|
|
10
|
+
note: supply-chain repro
|
|
11
|
+
order: 7
|
|
12
|
+
owner: loop/hashed-toolchain
|
|
13
|
+
pr: 234
|
|
14
|
+
title: Hash-pinned, reproducible toolchain — <code>requirements/*.txt</code>
|
|
15
|
+
---
|
|
16
|
+
Every dev/CI tool was resolved at install time, so two runs of the same gate could
|
|
17
|
+
install different bytes — and only <code>requirements/lint-tools.txt</code> pinned
|
|
18
|
+
anything at all (added after ruff 0.16.0 reddened the gate with no code change).
|
|
19
|
+
Now every tool comes from a generated, hash-pinned
|
|
20
|
+
<code>requirements/*.txt</code>: exact versions <em>plus</em> a sha256 for every
|
|
21
|
+
artifact in the transitive closure, which pip enforces on install, so a yanked or
|
|
22
|
+
tampered dependency fails loudly instead of silently changing a build.
|
|
23
|
+
<code>scripts/lock_toolchain.py</code> regenerates from the <code>.in</code>
|
|
24
|
+
declarations and <code>--check</code> gates drift in <code>make lint</code>; a new
|
|
25
|
+
Dependabot <code>pip</code> entry keeps the locks from rotting. One file per
|
|
26
|
+
consumer, because pip enforces hashes across a whole resolution — and
|
|
27
|
+
<code>test-tools</code> resolves <em>universally</em>, so one file covers the
|
|
28
|
+
3 OS × 3 Python matrix without dragging 3.12/3.14 back to the 3.9 floor's
|
|
29
|
+
versions. The opt-in <code>[eval]</code> extra stays out on purpose: locking its
|
|
30
|
+
deliberately-old langchain stack into a scannable file would re-expose the pin
|
|
31
|
+
<code>osv-scanner.yml</code> is PR-diff-scoped to avoid.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: mcp-aware-skills
|
|
3
|
+
board: code
|
|
4
|
+
section: dx
|
|
5
|
+
status: shipped
|
|
6
|
+
category: Interop · MCP
|
|
7
|
+
complexity: L
|
|
8
|
+
impact: Med
|
|
9
|
+
wow: 4
|
|
10
|
+
note: skills that need a server
|
|
11
|
+
order: 46
|
|
12
|
+
owner: loop/mcp-aware-skills
|
|
13
|
+
pr: 235
|
|
14
|
+
title: MCP-aware skills — declare and wire an <code>.mcp.json</code> on install
|
|
15
|
+
---
|
|
16
|
+
Mining boost's catalog surfaces a recurring shape: skills that only work paired
|
|
17
|
+
with a Model Context Protocol server (<code>manage-mcp-servers</code>,
|
|
18
|
+
<code>mcp-integration</code>, <code>mcp-builder</code> and dozens more). boost
|
|
19
|
+
already <em>is</em> an MCP server and registers itself, but a skill could not say
|
|
20
|
+
"I need server Y", so it installed cleanly and then failed in the agent for a
|
|
21
|
+
reason nothing surfaced. Now a skill declares <code>mcp: github, playwright</code>
|
|
22
|
+
in frontmatter and/or bundles a standard <code>.mcp.json</code>; on install boost
|
|
23
|
+
states the requirement and offers to register the servers that came with a
|
|
24
|
+
runnable spec, the same way <code>boost mcp register</code> wires boost itself.
|
|
25
|
+
<code>boost info</code> lists them beside <code>capabilities:</code>, and
|
|
26
|
+
<code>--no-mcp</code> opts out. Deliberately <em>flat</em>, not the nested
|
|
27
|
+
<code>mcp:</code> block first sketched: boost's frontmatter parser is a stdlib
|
|
28
|
+
YAML subset that does not fail loudly on a nested mapping — it hoists the inner
|
|
29
|
+
keys to top level and clobbers their siblings — so the declaration meets the
|
|
30
|
+
parser where it already works and full specs live in the sidecar that needs no
|
|
31
|
+
parser at all. The decision layer is <code>core/mcpdecl.py</code>, pure and
|
|
32
|
+
I/O-free like <code>core/resolve.py</code>.
|