boost-skill-cli 1.0.266__tar.gz → 1.0.268__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.266/boost_skill_cli.egg-info → boost_skill_cli-1.0.268}/PKG-INFO +1 -1
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/_version.py +2 -2
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/store.py +50 -1
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268/boost_skill_cli.egg-info}/PKG-INFO +1 -1
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_skill_cli.egg-info/SOURCES.txt +3 -0
- boost_skill_cli-1.0.268/docs/roadmap/items/sync-relinks-into-every-agent-ignoring-scope.md +36 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap.html +33 -1
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/requirements/release-tools.in +4 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/requirements/release-tools.txt +12 -0
- boost_skill_cli-1.0.268/scripts/check_licenses.py +108 -0
- boost_skill_cli-1.0.268/tests/unit/test_check_licenses.py +163 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_store.py +146 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/.gitattributes +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/.gitignore +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/.gitleaks.toml +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/.htmlvalidate.json +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/.lighthouserc.json +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/.lycheeignore +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/.markdownlint-cli2.jsonc +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/.pre-commit-config.yaml +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/.stylelintrc.json +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/.vale/styles/boost/Terminology.yml +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/.vale/styles/config/vocabularies/boost/accept.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/.vale.ini +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/CLAUDE.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/CODE_OF_CONDUCT.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/CONTRIBUTING.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/LICENSE +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/MANIFEST.in +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/Makefile +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/README.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/SECURITY.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/__init__.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/__main__.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/cli.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/cliparse.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/commands/__init__.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/commands/_common.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/commands/bmad.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/commands/configuration.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/commands/discovery.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/commands/hooks.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/commands/info.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/commands/intelligence.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/commands/pkg.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/commands/quality.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/commands/run.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/commands/safety.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/commands/taps.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/commands/team.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/__init__.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/adapters.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/agents.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/ai.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/capabilities.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/catalog.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/claude_settings.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/config.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/dense.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/ed25519.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/embed.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/faithfulness.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/frontmatter.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/gitutil.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/imperative.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/injectscan.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/integrity.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/journal.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/lockfile.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/logs.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/mcp.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/mcpdecl.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/minisign.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/nethttp.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/output.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/paths.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/policy.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/projectlock.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/provenance.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/rag.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/registry.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/resolve.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/rules.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/scopes.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/secretscan.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/selfupdate.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/serve.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/stackprobe.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/staleness.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/trustaudit.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/typosquat.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/updatediff.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/util.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/core/workflows.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/data/registries.json +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/errors.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_cli/spin.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_skill_cli.egg-info/entry_points.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_skill_cli.egg-info/requires.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/boost_skill_cli.egg-info/top_level.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/codecov.yml +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/.claude/settings.local.json +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/DEBUGGING.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/adapters.html +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/carousel/gifs/distill.gif +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/carousel/gifs/doctor.gif +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/carousel/gifs/explain.gif +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/carousel/gifs/hooks.gif +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/carousel/gifs/install.gif +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/carousel/gifs/pulse.gif +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/carousel/gifs/search.gif +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/carousel/gifs/tap.gif +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/carousel/tapes/distill.tape +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/carousel/tapes/doctor.tape +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/carousel/tapes/explain.tape +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/carousel/tapes/hooks.tape +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/carousel/tapes/install.tape +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/carousel/tapes/pulse.tape +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/carousel/tapes/search.tape +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/carousel/tapes/tap.tape +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/carousel.html +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/commands.html +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/demo.gif +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/demo.tape +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/design-roadmap.html +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/eval.html +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/index.html +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/mcp-hub.html +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/rag-architecture.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D01.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D02.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D03.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D04.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D05.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D06.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D07.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D08.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D09.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D10.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D11.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D12.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D13.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D14.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D15.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D16.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D17.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D18.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D19.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D20.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D21.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D22.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D23.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D24.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D25.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/BOOST-D26.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/adapter-conformance-langgraph-leg-never-ran.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/ai-bridge-silent-failure-logging.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/ambiguous-tap-short-name-resolution.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/boost-run-live-agents.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/ci-job-timeout-minutes.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/ci-summary-step-fails-itself.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/command-carousel-page.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/command-reference-docs-site.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/crash-listing-branch-untested.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/demo-gif-workflow-has-never-succeeded.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/dense-search-fallback-and-stale-tap-pruning.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/dependabot-missing-pip-ecosystem.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/docsite-chrome-and-content-audit.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/framework-adapter-multi-agent.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/github-community-health-files.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/html-validation-html-validate.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/install-docs-never-mentioned-upgrading.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/install-from-path-bypasses-policy-and-pin-checks.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/install-resolves-skill-dependencies.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/install-scope-user-or-project.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/installed-skill-trust-audit.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/journal-rotation-race-and-handle-leak.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/license-compliance-scanning.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/lint-tap-misscopes-rule-workflow-entries.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/lock-invariant-cannot-parse-extras-pins.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/main-has-no-branch-protection.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/main-ruleset-ref-pattern-has-literal-quotes.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/markdownlint-lints-the-fuzz-corpus.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/mcp-aware-skills.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/mcp-search-before-reinventing.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/merge-queue-would-deadlock-most-required-checks.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/mutation-gate-was-the-whole-critical-path.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/mypy-strict-mode-for-commands.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/negative-limit-inverts-log-pulse-output.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/onboard-overwrites-generated-files-without-confirm.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/path-traversal-unsanitized-rule-workflow-name.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/pin-the-lint-toolchain.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/post-deploy-always-defeated-by-skipped-setup.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/project-scope-across-every-command.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/project-scope-symlink-escape-on-write.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/publish-gate-ignores-pip-audit-and-metadata.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/publish-trigger-was-reachable-from-a-fork.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/pytest-tmpdir-cve-blocked-by-py39-floor.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/rel-time-tests-race-the-wall-clock.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/required-checks-can-declare-a-check-that-deadlocks-prs.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/required-checks-config-drift.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/roadmap-html-goes-stale-on-every-rebase.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/ruff-016-widens-the-default-rule-set.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/sbom-release-event-never-fires.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/scorecard-findings-triage.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/self-update-broken-for-pip-pipx-installs.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/serve-py-traversal-guards-untested.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/structured-json-log-output-mode.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/sync-deletes-unowned-broken-symlinks.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/typo-detection-codespell.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/uninstall-has-no-confirmation-prompt.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/update-diff-before-apply.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/update-reinstall-widens-agent-scope.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/wire-bdd-suite-into-ci.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/docs/roadmap/items/workspace-scope-install.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/eslint.config.mjs +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/examples/README.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/examples/adapt-demo.sh +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/examples/boost-run-prototype.sh +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/index.html +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/noxfile.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/pyproject.toml +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/requirements/coverage-tools.in +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/requirements/coverage-tools.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/requirements/lint-tools.in +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/requirements/lint-tools.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/requirements/mutation-tools.in +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/requirements/mutation-tools.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/requirements/test-tools.in +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/requirements/test-tools.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/a11y_check.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/bench_cli.sh +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/build_command_reference.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/build_registries.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/build_roadmap.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/check_anchors.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/check_required_checks.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/ensure_eval_corpus.sh +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/eval_explain.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/eval_recommend.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/eval_retrieval.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/eval_stats_summary.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/import_budget.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/lock_toolchain.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/mutation_gate.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/mutation_shards.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/mutation_weights.json +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/perf_gate.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/post_deploy_smoke.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/scripts/release_preflight.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/setup.cfg +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/sonar-project.properties +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/style/README.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/style/boost.css +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/style/boost.js +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/style/demo.html +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/bdd/features/adapt.feature +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/bdd/features/browse.feature +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/bdd/features/count.feature +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/bdd/features/discover.feature +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/bdd/features/doctor.feature +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/bdd/features/environment.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/bdd/features/explain.feature +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/bdd/features/index.feature +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/bdd/features/install.feature +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/bdd/features/list.feature +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/bdd/features/mcp.feature +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/bdd/features/search.feature +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/bdd/features/steps/cli_steps.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/bdd/features/steps/discovery_steps.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/bdd/features/steps/mcp_steps.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/bdd/features/steps/quality_steps.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/conftest.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/eval/baseline.json +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/eval/explain.jsonl +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/eval/golden.jsonl +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/eval/recommend.jsonl +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/eval/taps.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_capabilities_policy.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_cli_adapt.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_cli_bmad.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_cli_configuration.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_cli_discovery.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_cli_hooks.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_cli_info.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_cli_intelligence.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_cli_pkg.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_cli_quality.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_cli_taps.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_cli_team.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_everyday_loop.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_integrity_enforce.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_property_parsers.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_run.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_tap_signing.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/functional/test_workspace_scope.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/README.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/frontmatter/01-typical.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/frontmatter/02-lossy-version.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/frontmatter/03-lossy-numbers.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/frontmatter/04-lists.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/frontmatter/05-nested.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/frontmatter/06-empty-block.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/frontmatter/07-unterminated.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/frontmatter/08-none.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/frontmatter/09-unbalanced-quote.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/frontmatter/10-keywords.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/frontmatter/11-crlf.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/frontmatter/12-bom.md +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/registry/01-shorthand.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/registry/02-https.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/registry/03-ssh.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/registry/04-traversal.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/registry/05-empty.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/registry/06-space.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/registry/07-slash.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/corpus/registry/08-bare-host.txt +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/fuzz_frontmatter.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/fuzz/fuzz_registry.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/make_fixture.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/perf/test_benchmarks.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/smoke.sh +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_a11y_check.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_adapters.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_adapters_multi.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_adapters_runner.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_agents.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_ai.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_capabilities.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_catalog.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_check_anchors.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_claude_settings.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_cliparse.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_command_reference_fresh.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_community_health_files.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_config.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_dense.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_dense_fallback.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_dependabot_config.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_docs_pages_linked.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_docsite_chrome.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_ed25519.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_embed.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_errors_and_cli_table.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_eval_stats_summary.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_faithfulness.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_frontmatter.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_fuzz_targets.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_gitleaks_config.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_gitutil.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_imperative.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_import_budget.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_injectscan.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_integrity.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_journal.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_lockfile.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_logs.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_marketing_counts.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_mcp.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_mcpdecl.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_minisign.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_mutation_hardening.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_mutation_shards.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_mutmut_source_paths.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_nethttp.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_output.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_paths.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_perf_gate.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_pkg_confusions.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_pkg_injection.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_pkg_secrets.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_policy.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_post_deploy_smoke.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_projectlock.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_provenance.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_rag.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_registries_fresh.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_registry.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_release_preflight.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_required_checks.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_resolve.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_roadmap_fresh.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_rules.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_scopes.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_secretscan.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_selfupdate.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_serve.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_spin.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_stackprobe.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_staleness.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_token_parity.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_toolchain_lock.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_trustaudit.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_typosquat.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_updatediff.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_util.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_version.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_workflow_timeouts.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/unit/test_workflows.py +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/visual/a11y_check.mjs +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/visual/console_check.mjs +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/visual/package.json +0 -0
- {boost_skill_cli-1.0.266 → boost_skill_cli-1.0.268}/tests/visual/visual_check.mjs +0 -0
|
@@ -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.268'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 0, 268)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -126,6 +126,41 @@ def preserved_agent_scope(only_agents: Optional[List[str]],
|
|
|
126
126
|
return [a for a in recorded if a] or None
|
|
127
127
|
|
|
128
128
|
|
|
129
|
+
def declared_agent_scope(only_agents: Optional[List[str]],
|
|
130
|
+
existing: Optional[dict]) -> Optional[List[str]]:
|
|
131
|
+
"""The scope to RECORD in the lock: an explicit narrowing, or the last one.
|
|
132
|
+
|
|
133
|
+
Deliberately *not* :func:`preserved_agent_scope`. That one answers "which
|
|
134
|
+
agents should this install link into", and falls back to the lock's
|
|
135
|
+
``agents`` — which records what happens to be linked right now. Writing
|
|
136
|
+
that back as a declared scope would promote "these were the enabled agents
|
|
137
|
+
at install time" into "the user asked for exactly these", permanently
|
|
138
|
+
freezing a skill out of any agent enabled later. The two questions look
|
|
139
|
+
alike and are not, so they get separate functions.
|
|
140
|
+
|
|
141
|
+
Only an explicit ``--agent`` narrows. Absent that, an earlier declaration
|
|
142
|
+
is carried forward so ``update``/``reinstall`` don't drop it, and a skill
|
|
143
|
+
that was never narrowed keeps no scope at all (``None``).
|
|
144
|
+
"""
|
|
145
|
+
if only_agents is not None:
|
|
146
|
+
return list(only_agents)
|
|
147
|
+
return (existing or {}).get("only_agents")
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def scoped_agents(entry: dict, enabled: Dict[str, Path]) -> Dict[str, Path]:
|
|
151
|
+
"""The enabled agents a locked skill is supposed to be linked into.
|
|
152
|
+
|
|
153
|
+
Fails **open**: an entry with no ``only_agents`` — every entry written
|
|
154
|
+
before this field existed — means "not narrowed", so it gets every enabled
|
|
155
|
+
agent. That keeps ``boost sync`` doing its other job, which is linking
|
|
156
|
+
already-installed skills into an agent that was enabled afterwards.
|
|
157
|
+
"""
|
|
158
|
+
scope = entry.get("only_agents")
|
|
159
|
+
if not scope:
|
|
160
|
+
return enabled.copy()
|
|
161
|
+
return {a: d for a, d in enabled.items() if a in scope}
|
|
162
|
+
|
|
163
|
+
|
|
129
164
|
def unlink_agents(name: str) -> List[str]:
|
|
130
165
|
"""Remove the ``name`` symlink from every enabled agent dir.
|
|
131
166
|
|
|
@@ -326,6 +361,11 @@ def install(entry: dict, force: bool = False,
|
|
|
326
361
|
"pinned": bool((existing or {}).get("pinned")),
|
|
327
362
|
"quarantined": False,
|
|
328
363
|
"agents": res.linked,
|
|
364
|
+
# `agents` is what IS linked; `only_agents` is what the user ASKED for.
|
|
365
|
+
# sync needs the second: it links a skill into every enabled agent, and
|
|
366
|
+
# without a record of the request it cannot tell a deliberate `--agent`
|
|
367
|
+
# narrowing from a skill that simply predates a newly enabled agent.
|
|
368
|
+
"only_agents": declared_agent_scope(only_agents, existing),
|
|
329
369
|
"tags": (existing or {}).get("tags", []),
|
|
330
370
|
})
|
|
331
371
|
journal.log("install", name, tap=entry["tap"], version=entry.get("version"))
|
|
@@ -806,6 +846,10 @@ def install_from_path(src_dir: Path, name: Optional[str] = None,
|
|
|
806
846
|
"pinned": bool((existing or {}).get("pinned")),
|
|
807
847
|
"quarantined": False,
|
|
808
848
|
"agents": res.linked,
|
|
849
|
+
# `boost import --agent ...` narrows the same way `install` does, so it
|
|
850
|
+
# has to record the same declaration — otherwise the links are narrow
|
|
851
|
+
# but sync sees no scope and widens them right back.
|
|
852
|
+
"only_agents": declared_agent_scope(only_agents, existing),
|
|
809
853
|
"tags": (existing or {}).get("tags", []),
|
|
810
854
|
})
|
|
811
855
|
journal.log("import", name, source=str(src_dir))
|
|
@@ -922,7 +966,12 @@ def sync_plan() -> Dict[str, list]:
|
|
|
922
966
|
continue
|
|
923
967
|
if entry.get("quarantined"):
|
|
924
968
|
continue
|
|
925
|
-
|
|
969
|
+
# Only the agents this skill was installed for. Walking every enabled
|
|
970
|
+
# agent made `boost sync` a second path to the scope leak that
|
|
971
|
+
# `preserved_agent_scope` closed on the install side: it reported a
|
|
972
|
+
# missing_link for each agent outside the narrowing, and sync_apply
|
|
973
|
+
# dutifully linked them, undoing `install --agent` in one command.
|
|
974
|
+
for agent, adir in scoped_agents(entry, agents.enabled_agents()).items():
|
|
926
975
|
link = adir / name
|
|
927
976
|
if not link.is_symlink() or not link.exists():
|
|
928
977
|
plan["missing_links"].append((name, agent))
|
|
@@ -296,6 +296,7 @@ docs/roadmap/items/structured-json-log-output-mode.md
|
|
|
296
296
|
docs/roadmap/items/supply-chain-posture-openssf-scorecard.md
|
|
297
297
|
docs/roadmap/items/surface-every-docs-page-from-the-guide.md
|
|
298
298
|
docs/roadmap/items/sync-deletes-unowned-broken-symlinks.md
|
|
299
|
+
docs/roadmap/items/sync-relinks-into-every-agent-ignoring-scope.md
|
|
299
300
|
docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md
|
|
300
301
|
docs/roadmap/items/theme-asset-linting-stylelint-eslint.md
|
|
301
302
|
docs/roadmap/items/typo-detection-codespell.md
|
|
@@ -333,6 +334,7 @@ scripts/build_command_reference.py
|
|
|
333
334
|
scripts/build_registries.py
|
|
334
335
|
scripts/build_roadmap.py
|
|
335
336
|
scripts/check_anchors.py
|
|
337
|
+
scripts/check_licenses.py
|
|
336
338
|
scripts/check_required_checks.py
|
|
337
339
|
scripts/ensure_eval_corpus.sh
|
|
338
340
|
scripts/eval_explain.py
|
|
@@ -426,6 +428,7 @@ tests/unit/test_ai.py
|
|
|
426
428
|
tests/unit/test_capabilities.py
|
|
427
429
|
tests/unit/test_catalog.py
|
|
428
430
|
tests/unit/test_check_anchors.py
|
|
431
|
+
tests/unit/test_check_licenses.py
|
|
429
432
|
tests/unit/test_claude_settings.py
|
|
430
433
|
tests/unit/test_cliparse.py
|
|
431
434
|
tests/unit/test_command_reference_fresh.py
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: sync-relinks-into-every-agent-ignoring-scope
|
|
3
|
+
board: code
|
|
4
|
+
section: internals
|
|
5
|
+
status: shipped
|
|
6
|
+
category: Bug
|
|
7
|
+
complexity: S
|
|
8
|
+
impact: Med
|
|
9
|
+
wow: 2
|
|
10
|
+
note: the half of the scope leak PR #288 deliberately left open
|
|
11
|
+
order: 34
|
|
12
|
+
owner: loop/sync-agent-scope
|
|
13
|
+
pr:
|
|
14
|
+
title: <code>sync</code> relinks a narrowed skill into every agent
|
|
15
|
+
---
|
|
16
|
+
<code>store.preserved_agent_scope</code> (PR #288) stopped <code>update</code> and
|
|
17
|
+
<code>reinstall</code> widening a skill installed with <code>--agent</code> narrowing, but
|
|
18
|
+
<code>sync_plan()</code> was a second, independent path to the same leak: it walked
|
|
19
|
+
<code>agents.enabled_agents()</code> for <b>every</b> locked skill and reported a
|
|
20
|
+
<code>missing_link</code> for any agent the skill was not linked into — the lock's recorded
|
|
21
|
+
scope was never consulted. <code>sync_apply</code> then dutifully linked them, so a
|
|
22
|
+
single <code>boost sync</code> undid the narrowing that <code>install --agent</code> asked for and
|
|
23
|
+
rewrote the lock to match.
|
|
24
|
+
|
|
25
|
+
It was left out of #288 because the fix is a real trade-off, not an oversight:
|
|
26
|
+
<code>boost sync</code> is also how a <i>newly enabled</i> agent picks up skills installed
|
|
27
|
+
before it existed, and honouring the lock's <code>agents</code> list would silently break that —
|
|
28
|
+
<code>agents</code> records what is linked <i>right now</i>, so reading it as a scope would
|
|
29
|
+
freeze every existing skill out of any agent enabled later.
|
|
30
|
+
|
|
31
|
+
Resolved by separating the two questions. A new <code>only_agents</code> field records what the
|
|
32
|
+
user <i>asked</i> for, written only by an explicit <code>--agent</code> and carried forward across
|
|
33
|
+
<code>update</code>/<code>reinstall</code>; <code>agents</code> keeps meaning what is actually linked.
|
|
34
|
+
<code>sync_plan</code> filters through <code>scoped_agents()</code>, which <b>fails open</b> — an entry
|
|
35
|
+
with no declaration, which is every entry written before this field existed, still fans out to
|
|
36
|
+
every enabled agent. So narrowing is honoured and the newly-enabled-agent path is untouched.
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
<div class="stat"><b>16</b><span>Shipped</span></div>
|
|
111
111
|
<div class="stat"><b>1</b><span>Next up</span></div>
|
|
112
112
|
<div class="stat"><b>4</b><span>Planned</span></div>
|
|
113
|
-
<div class="stat"><b>
|
|
113
|
+
<div class="stat"><b>161</b><span>Loop finds</span></div>
|
|
114
114
|
<!-- /ROADMAP:stats -->
|
|
115
115
|
</div>
|
|
116
116
|
</section>
|
|
@@ -1102,6 +1102,38 @@ already used elsewhere in <code>pkg.py</code>.</p>
|
|
|
1102
1102
|
</div>
|
|
1103
1103
|
</article>
|
|
1104
1104
|
|
|
1105
|
+
<article class="cap rcard" id="sync-relinks-into-every-agent-ignoring-scope">
|
|
1106
|
+
<div class="head"><span class="pill shipped">Shipped</span><span class="cat">Bug</span></div>
|
|
1107
|
+
<h3><code>sync</code> relinks a narrowed skill into every agent</h3>
|
|
1108
|
+
<p><code>store.preserved_agent_scope</code> (PR #288) stopped <code>update</code> and
|
|
1109
|
+
<code>reinstall</code> widening a skill installed with <code>--agent</code> narrowing, but
|
|
1110
|
+
<code>sync_plan()</code> was a second, independent path to the same leak: it walked
|
|
1111
|
+
<code>agents.enabled_agents()</code> for <b>every</b> locked skill and reported a
|
|
1112
|
+
<code>missing_link</code> for any agent the skill was not linked into — the lock's recorded
|
|
1113
|
+
scope was never consulted. <code>sync_apply</code> then dutifully linked them, so a
|
|
1114
|
+
single <code>boost sync</code> undid the narrowing that <code>install --agent</code> asked for and
|
|
1115
|
+
rewrote the lock to match.
|
|
1116
|
+
|
|
1117
|
+
It was left out of #288 because the fix is a real trade-off, not an oversight:
|
|
1118
|
+
<code>boost sync</code> is also how a <i>newly enabled</i> agent picks up skills installed
|
|
1119
|
+
before it existed, and honouring the lock's <code>agents</code> list would silently break that —
|
|
1120
|
+
<code>agents</code> records what is linked <i>right now</i>, so reading it as a scope would
|
|
1121
|
+
freeze every existing skill out of any agent enabled later.
|
|
1122
|
+
|
|
1123
|
+
Resolved by separating the two questions. A new <code>only_agents</code> field records what the
|
|
1124
|
+
user <i>asked</i> for, written only by an explicit <code>--agent</code> and carried forward across
|
|
1125
|
+
<code>update</code>/<code>reinstall</code>; <code>agents</code> keeps meaning what is actually linked.
|
|
1126
|
+
<code>sync_plan</code> filters through <code>scoped_agents()</code>, which <b>fails open</b> — an entry
|
|
1127
|
+
with no declaration, which is every entry written before this field existed, still fans out to
|
|
1128
|
+
every enabled agent. So narrowing is honoured and the newly-enabled-agent path is untouched.</p>
|
|
1129
|
+
<div class="meta">
|
|
1130
|
+
<span class="m">Complexity <b>S</b></span>
|
|
1131
|
+
<span class="m">Impact <b>Med</b></span>
|
|
1132
|
+
<span class="m">Wow <b class="wow">★★</b></span>
|
|
1133
|
+
<span class="m">the half of the scope leak PR</span>
|
|
1134
|
+
</div>
|
|
1135
|
+
</article>
|
|
1136
|
+
|
|
1105
1137
|
<article class="cap rcard" id="onboard-overwrites-generated-files-without-confirm">
|
|
1106
1138
|
<div class="head"><span class="pill planned">Planned</span><span class="cat">UX · Bug</span></div>
|
|
1107
1139
|
<h3><code>boost onboard</code> silently overwrites existing generated files</h3>
|
|
@@ -15,3 +15,7 @@ twine
|
|
|
15
15
|
check-wheel-contents
|
|
16
16
|
pyroma
|
|
17
17
|
pip-audit
|
|
18
|
+
# SPDX license compliance of a resolved closure (licenses.yml). Pinned for the
|
|
19
|
+
# same reason as the rest: a verdict that changes on an upstream release of the
|
|
20
|
+
# scanner is a verdict about the scanner, not about the dependencies.
|
|
21
|
+
pip-licenses
|
|
@@ -483,6 +483,10 @@ pip-audit==2.10.1 \
|
|
|
483
483
|
--hash=sha256:1eb4565d19ebe5d48996f4b770b4d2b32887e12cb12cfa637f1a064011b55ffc \
|
|
484
484
|
--hash=sha256:99ef3f600a317c1945f1e89e227ef26e1c2d618429b8bd3fa6f4f7c440c4611a
|
|
485
485
|
# via -r requirements/release-tools.in
|
|
486
|
+
pip-licenses==5.5.5 \
|
|
487
|
+
--hash=sha256:60750c006adf7a0910347b726e8ee9fee3bc8d2e7c8307a5c4ec0776c8e2a276 \
|
|
488
|
+
--hash=sha256:f4c4c6d9e6a03612cf59f29f19dc8ab54904d82e055b8e191498f2279a224e14
|
|
489
|
+
# via -r requirements/release-tools.in
|
|
486
490
|
pip-requirements-parser==32.0.1 \
|
|
487
491
|
--hash=sha256:4659bc2a667783e7a15d190f6fccf8b2486685b6dba4c19c3876314769c57526 \
|
|
488
492
|
--hash=sha256:b4fa3a7a0be38243123cf9d1f3518da10c51bdb165a2b2985566247f9155a7d3
|
|
@@ -491,6 +495,10 @@ platformdirs==4.11.0 \
|
|
|
491
495
|
--hash=sha256:0555d18370482847566ffabcaa53ad7c6c1c29f195989ae1ed634a05f76ea1e0 \
|
|
492
496
|
--hash=sha256:360ccded2b7fce0af0ff80cc8f5942a1c5d99b0e856033acb030bfc634709e74
|
|
493
497
|
# via pip-audit
|
|
498
|
+
prettytable==3.18.0 \
|
|
499
|
+
--hash=sha256:439217116152244369caf3d9f1caf2f9fe29b03bd79e88d2928c8e718c95d680 \
|
|
500
|
+
--hash=sha256:b3346e0e6f79180833aebaac088ae926340586cf6d7d991b9eb125b65f72313a
|
|
501
|
+
# via pip-licenses
|
|
494
502
|
py-serializable==2.1.0 \
|
|
495
503
|
--hash=sha256:9d5db56154a867a9b897c0163b33a793c804c80cee984116d02d49e4578fc103 \
|
|
496
504
|
--hash=sha256:b56d5d686b5a03ba4f4db5e769dc32336e142fc3bd4d68a8c25579ebb0a67304
|
|
@@ -767,6 +775,10 @@ urllib3==2.7.0 \
|
|
|
767
775
|
# id
|
|
768
776
|
# requests
|
|
769
777
|
# twine
|
|
778
|
+
wcwidth==0.8.2 \
|
|
779
|
+
--hash=sha256:91fbef97204b96a3d4d421609b80340b760cf33e26da123ff243d76b1fda8dda \
|
|
780
|
+
--hash=sha256:d63947694a0539a1d51e01eda7caf800c291020e6cdd7e28ad7b14dd33ad4f85
|
|
781
|
+
# via prettytable
|
|
770
782
|
wheel-filename==1.4.2 \
|
|
771
783
|
--hash=sha256:3fa599046443d4ca830d06e3d180cd0a675d5871af0a68daa5623318bb4d17e3 \
|
|
772
784
|
--hash=sha256:87891c465dcbb40b40394a906f01a93214bdd51aa5d25e3a9a59cae62bc298fd
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Fail when a resolved dependency's licence is incompatible with GPL-3.0.
|
|
3
|
+
|
|
4
|
+
`pip-audit` gates known CVEs; nothing gated licence *terms*. boost's shipped
|
|
5
|
+
runtime is stdlib-only, so the exposure is entirely in the opt-in extras —
|
|
6
|
+
`[eval]` alone resolves to 94 packages, including the pinned langchain stack —
|
|
7
|
+
and none of them had ever been checked against the project's own GPL-3.0.
|
|
8
|
+
|
|
9
|
+
Reads ``pip-licenses --format=json`` (stdin, or a path) rather than shelling out,
|
|
10
|
+
so the check is a pure function of its input and can be unit-tested without a
|
|
11
|
+
resolved environment.
|
|
12
|
+
|
|
13
|
+
Why not ``pip-licenses --fail-on``: it compares the declared licence string
|
|
14
|
+
exactly, and that string is not a well-formed identifier. Real values observed
|
|
15
|
+
in boost's own `[eval]` closure:
|
|
16
|
+
|
|
17
|
+
ragas -> "UNKNOWN" (no licence metadata at all)
|
|
18
|
+
tiktoken -> "MIT License\\n\\nCopyright (c) 2022 OpenAI, …" (the whole text)
|
|
19
|
+
sqlite-vec -> "MIT License, Apache License, Version 2.0" (two, comma-joined)
|
|
20
|
+
|
|
21
|
+
so matching is done here by regex over the whole field instead.
|
|
22
|
+
|
|
23
|
+
Usage:
|
|
24
|
+
pip-licenses --format=json | python3 scripts/check_licenses.py
|
|
25
|
+
python3 scripts/check_licenses.py licenses.json
|
|
26
|
+
"""
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import json
|
|
30
|
+
import re
|
|
31
|
+
import sys
|
|
32
|
+
from typing import List, Tuple
|
|
33
|
+
|
|
34
|
+
# (pattern, why). Matched case-insensitively against the whole declared licence
|
|
35
|
+
# string. Deliberately short: the aim is high-confidence incompatibility, not a
|
|
36
|
+
# taxonomy. LGPL, MPL and EPL are all fine to *consume* from a GPL-3.0 project
|
|
37
|
+
# and are not listed.
|
|
38
|
+
DENIED: Tuple[Tuple[str, str], ...] = (
|
|
39
|
+
(r"affero|\bagpl\b",
|
|
40
|
+
"AGPL adds network-use copyleft that GPL-3.0 does not carry"),
|
|
41
|
+
# GPLv2-*only* cannot be combined with GPL-3.0. "v2 or later" / "GPLv2+"
|
|
42
|
+
# can (it permits taking v3), so both spellings are excluded explicitly.
|
|
43
|
+
(r"gplv2(?!\+)|gpl-2\.0(?!-or-later)|general public license v2 \(",
|
|
44
|
+
"GPLv2-only is incompatible with GPL-3.0"),
|
|
45
|
+
(r"proprietary|all rights reserved|\bsspl\b|commons clause|\bbusl\b",
|
|
46
|
+
"not an open-source licence"),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Packages whose *metadata* omits a licence even though the project has one.
|
|
50
|
+
# Each needs the upstream licence named, so the exception is auditable rather
|
|
51
|
+
# than a silence. Anything undeclared and unlisted fails.
|
|
52
|
+
UNDECLARED_OK = {
|
|
53
|
+
# https://github.com/explodinggradients/ragas — Apache-2.0 in the repo;
|
|
54
|
+
# the published wheel carries no License field or classifier.
|
|
55
|
+
"ragas": "Apache-2.0 upstream; wheel metadata omits it",
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
_UNDECLARED = re.compile(r"^\s*(unknown|none|)\s*$", re.IGNORECASE)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def is_undeclared(licence: str) -> bool:
|
|
62
|
+
"""True when the package declared no licence at all."""
|
|
63
|
+
return bool(_UNDECLARED.match(licence or ""))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def violations(rows: List[dict]) -> List[str]:
|
|
67
|
+
"""Human-readable problems in a ``pip-licenses --format=json`` payload."""
|
|
68
|
+
problems = []
|
|
69
|
+
for row in rows:
|
|
70
|
+
name = str(row.get("Name", "?"))
|
|
71
|
+
licence = str(row.get("License", ""))
|
|
72
|
+
if is_undeclared(licence):
|
|
73
|
+
if name.lower() not in UNDECLARED_OK:
|
|
74
|
+
problems.append(
|
|
75
|
+
"%s declares no licence — add it to UNDECLARED_OK with the "
|
|
76
|
+
"upstream licence, or drop the dependency" % name)
|
|
77
|
+
continue
|
|
78
|
+
for pattern, why in DENIED:
|
|
79
|
+
if re.search(pattern, licence, re.IGNORECASE):
|
|
80
|
+
problems.append("%s: %s (%s)" % (
|
|
81
|
+
name, why, licence.splitlines()[0][:60]))
|
|
82
|
+
break
|
|
83
|
+
return problems
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def main(argv: List[str]) -> int:
|
|
87
|
+
raw = (open(argv[0], encoding="utf-8").read() if argv
|
|
88
|
+
else sys.stdin.read())
|
|
89
|
+
try:
|
|
90
|
+
rows = json.loads(raw)
|
|
91
|
+
except ValueError as e:
|
|
92
|
+
print("::error::could not parse pip-licenses JSON: %s" % e)
|
|
93
|
+
return 2
|
|
94
|
+
if not isinstance(rows, list) or not rows:
|
|
95
|
+
# An empty scan is not a pass: it means the environment was never
|
|
96
|
+
# populated, which is how a licence gate quietly stops gating.
|
|
97
|
+
print("::error::no packages in the licence report — nothing was scanned")
|
|
98
|
+
return 2
|
|
99
|
+
|
|
100
|
+
problems = violations(rows)
|
|
101
|
+
for p in problems:
|
|
102
|
+
print("::error::%s" % p)
|
|
103
|
+
print("checked %d package(s): %d problem(s)" % (len(rows), len(problems)))
|
|
104
|
+
return 1 if problems else 0
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
if __name__ == "__main__":
|
|
108
|
+
sys.exit(main(sys.argv[1:]))
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""Unit tests: scripts/check_licenses.py — the SPDX compatibility gate.
|
|
2
|
+
|
|
3
|
+
Driven against the licence strings dependencies *actually* publish, not against
|
|
4
|
+
tidy identifiers. Every awkward value below was observed in boost's own
|
|
5
|
+
resolved closures, which is the whole reason the check matches by regex instead
|
|
6
|
+
of using ``pip-licenses --fail-on``.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import importlib.util
|
|
11
|
+
import json
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
import pytest
|
|
15
|
+
|
|
16
|
+
SCRIPT = Path(__file__).resolve().parents[2] / "scripts" / "check_licenses.py"
|
|
17
|
+
|
|
18
|
+
# Verbatim from `pip-licenses --format=json` over `pip install .[eval]`.
|
|
19
|
+
TIKTOKEN = ("MIT License\n\nCopyright (c) 2022 OpenAI, Shantanu Jain\n\n"
|
|
20
|
+
"Permission is hereby granted, free of charge, …")
|
|
21
|
+
SQLITE_VEC = "MIT License, Apache License, Version 2.0"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@pytest.fixture(scope="module")
|
|
25
|
+
def mod():
|
|
26
|
+
spec = importlib.util.spec_from_file_location("check_licenses", SCRIPT)
|
|
27
|
+
m = importlib.util.module_from_spec(spec)
|
|
28
|
+
assert spec.loader is not None
|
|
29
|
+
spec.loader.exec_module(m)
|
|
30
|
+
return m
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def rows(*pairs):
|
|
34
|
+
return [{"Name": n, "Version": "1.0", "License": lic} for n, lic in pairs]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class TestPermissiveLicencesPass:
|
|
38
|
+
@pytest.mark.parametrize("licence", [
|
|
39
|
+
"MIT", "MIT License", "BSD License", "BSD-3-Clause", "Apache-2.0",
|
|
40
|
+
"Apache Software License", "Python Software Foundation License",
|
|
41
|
+
"PSF-2.0", "MIT-CMU", "Apache-2.0 OR BSD-2-Clause",
|
|
42
|
+
"BSD-3-Clause AND 0BSD AND MIT AND Zlib AND CC0-1.0",
|
|
43
|
+
"MPL-2.0 AND (Apache-2.0 OR MIT)",
|
|
44
|
+
"Mozilla Public License 2.0 (MPL 2.0)",
|
|
45
|
+
SQLITE_VEC, TIKTOKEN,
|
|
46
|
+
])
|
|
47
|
+
def test_no_violation(self, mod, licence):
|
|
48
|
+
assert mod.violations(rows(("pkg", licence))) == []
|
|
49
|
+
|
|
50
|
+
def test_lgpl_and_mpl_are_fine_to_consume(self, mod):
|
|
51
|
+
# Weak copyleft is not a problem for a GPL-3.0 project, and banning it
|
|
52
|
+
# would fail builds for no reason.
|
|
53
|
+
assert mod.violations(rows(
|
|
54
|
+
("a", "GNU Lesser General Public License v3 (LGPLv3)"),
|
|
55
|
+
("b", "GNU Lesser General Public License v2 or later (LGPLv2+)"),
|
|
56
|
+
("c", "Mozilla Public License 2.0 (MPL 2.0)"),
|
|
57
|
+
("d", "Eclipse Public License 2.0"))) == []
|
|
58
|
+
|
|
59
|
+
def test_gplv3_and_gplv2_or_later_pass(self, mod):
|
|
60
|
+
# GPL-3.0 is the project's own licence; "v2 or later" permits taking
|
|
61
|
+
# v3, so both combine cleanly. Only v2-*only* does not.
|
|
62
|
+
assert mod.violations(rows(
|
|
63
|
+
("a", "GNU General Public License v3 (GPLv3)"),
|
|
64
|
+
("b", "GNU General Public License v2 or later (GPLv2+)"),
|
|
65
|
+
("c", "GPL-2.0-or-later"))) == []
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class TestIncompatibleLicencesFail:
|
|
69
|
+
@pytest.mark.parametrize("licence", [
|
|
70
|
+
"GNU Affero General Public License v3",
|
|
71
|
+
"AGPL-3.0", "AGPL-3.0-only", "agpl-3.0-or-later",
|
|
72
|
+
])
|
|
73
|
+
def test_agpl(self, mod, licence):
|
|
74
|
+
[problem] = mod.violations(rows(("pkg", licence)))
|
|
75
|
+
assert "network-use copyleft" in problem
|
|
76
|
+
assert problem.startswith("pkg: ")
|
|
77
|
+
|
|
78
|
+
@pytest.mark.parametrize("licence", [
|
|
79
|
+
"GNU General Public License v2 (GPLv2)", "GPL-2.0", "GPL-2.0-only",
|
|
80
|
+
])
|
|
81
|
+
def test_gplv2_only(self, mod, licence):
|
|
82
|
+
[problem] = mod.violations(rows(("pkg", licence)))
|
|
83
|
+
assert "GPLv2-only" in problem
|
|
84
|
+
|
|
85
|
+
@pytest.mark.parametrize("licence", [
|
|
86
|
+
"Other/Proprietary License", "Proprietary", "All Rights Reserved",
|
|
87
|
+
"SSPL-1.0", "BUSL-1.1", "MIT with Commons Clause",
|
|
88
|
+
])
|
|
89
|
+
def test_non_open_source(self, mod, licence):
|
|
90
|
+
[problem] = mod.violations(rows(("pkg", licence)))
|
|
91
|
+
assert "not an open-source licence" in problem
|
|
92
|
+
|
|
93
|
+
def test_a_multi_line_licence_reports_only_its_first_line(self, mod):
|
|
94
|
+
# A whole licence text in the failure message would bury the finding.
|
|
95
|
+
[problem] = mod.violations(rows(
|
|
96
|
+
("pkg", "Other/Proprietary License\n\nblah\n" * 40)))
|
|
97
|
+
assert "\n" not in problem
|
|
98
|
+
assert len(problem) < 200
|
|
99
|
+
|
|
100
|
+
def test_every_offender_is_reported_not_just_the_first(self, mod):
|
|
101
|
+
problems = mod.violations(rows(("a", "AGPL-3.0"), ("b", "MIT"),
|
|
102
|
+
("c", "Other/Proprietary License")))
|
|
103
|
+
assert len(problems) == 2
|
|
104
|
+
assert problems[0].startswith("a: ") and problems[1].startswith("c: ")
|
|
105
|
+
|
|
106
|
+
def test_a_package_is_reported_once_even_if_it_trips_twice(self, mod):
|
|
107
|
+
[problem] = mod.violations(rows(("pkg", "AGPL-3.0 AND Proprietary")))
|
|
108
|
+
assert problem.startswith("pkg: ")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class TestUndeclaredLicences:
|
|
112
|
+
@pytest.mark.parametrize("licence", ["UNKNOWN", "unknown", "", " ", "None"])
|
|
113
|
+
def test_recognised_as_undeclared(self, mod, licence):
|
|
114
|
+
assert mod.is_undeclared(licence) is True
|
|
115
|
+
|
|
116
|
+
@pytest.mark.parametrize("licence", ["MIT", "Unknown Software License"])
|
|
117
|
+
def test_not_undeclared(self, mod, licence):
|
|
118
|
+
assert mod.is_undeclared(licence) is False
|
|
119
|
+
|
|
120
|
+
def test_an_undeclared_package_fails_by_default(self, mod):
|
|
121
|
+
[problem] = mod.violations(rows(("mystery", "UNKNOWN")))
|
|
122
|
+
assert "declares no licence" in problem
|
|
123
|
+
|
|
124
|
+
def test_the_documented_exception_passes(self, mod):
|
|
125
|
+
# ragas is Apache-2.0 upstream; its wheel carries no License field.
|
|
126
|
+
assert mod.violations(rows(("ragas", "UNKNOWN"))) == []
|
|
127
|
+
assert "ragas" in mod.UNDECLARED_OK
|
|
128
|
+
|
|
129
|
+
def test_every_exception_names_the_upstream_licence(self, mod):
|
|
130
|
+
# An allowlist entry with no reason is indistinguishable from silence.
|
|
131
|
+
for pkg, reason in mod.UNDECLARED_OK.items():
|
|
132
|
+
assert reason.strip(), pkg
|
|
133
|
+
assert pkg == pkg.lower(), "keys are matched lowercased"
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class TestMain:
|
|
137
|
+
def test_a_clean_report_exits_zero(self, mod, tmp_path, capsys):
|
|
138
|
+
p = tmp_path / "l.json"
|
|
139
|
+
p.write_text(json.dumps(rows(("a", "MIT"))), encoding="utf-8")
|
|
140
|
+
assert mod.main([str(p)]) == 0
|
|
141
|
+
assert "1 package(s): 0 problem(s)" in capsys.readouterr().out
|
|
142
|
+
|
|
143
|
+
def test_a_violation_exits_one_with_an_annotation(self, mod, tmp_path,
|
|
144
|
+
capsys):
|
|
145
|
+
p = tmp_path / "l.json"
|
|
146
|
+
p.write_text(json.dumps(rows(("a", "AGPL-3.0"))), encoding="utf-8")
|
|
147
|
+
assert mod.main([str(p)]) == 1
|
|
148
|
+
assert "::error::a: AGPL" in capsys.readouterr().out
|
|
149
|
+
|
|
150
|
+
def test_an_empty_report_is_a_failure_not_a_pass(self, mod, tmp_path,
|
|
151
|
+
capsys):
|
|
152
|
+
# This is how a licence gate quietly stops gating: the environment was
|
|
153
|
+
# never populated, every package passes, the step goes green.
|
|
154
|
+
p = tmp_path / "l.json"
|
|
155
|
+
p.write_text("[]", encoding="utf-8")
|
|
156
|
+
assert mod.main([str(p)]) == 2
|
|
157
|
+
assert "nothing was scanned" in capsys.readouterr().out
|
|
158
|
+
|
|
159
|
+
def test_unparseable_input_is_a_failure(self, mod, tmp_path, capsys):
|
|
160
|
+
p = tmp_path / "l.json"
|
|
161
|
+
p.write_text("not json", encoding="utf-8")
|
|
162
|
+
assert mod.main([str(p)]) == 2
|
|
163
|
+
assert "could not parse" in capsys.readouterr().out
|