boost-skill-cli 1.0.230__tar.gz → 1.0.232__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.230 → boost_skill_cli-1.0.232}/PKG-INFO +1 -1
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/_version.py +2 -2
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/configuration.py +44 -4
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/pkg.py +8 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/catalog.py +9 -2
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/registry.py +17 -3
- boost_skill_cli-1.0.232/boost_cli/core/selfupdate.py +138 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/store.py +65 -5
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_skill_cli.egg-info/PKG-INFO +1 -1
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_skill_cli.egg-info/SOURCES.txt +2 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/commands.html +7 -3
- boost_skill_cli-1.0.232/docs/roadmap/items/ambiguous-tap-short-name-resolution.md +23 -0
- boost_skill_cli-1.0.232/docs/roadmap/items/self-update-broken-for-pip-pipx-installs.md +31 -0
- boost_skill_cli-1.0.232/docs/roadmap/items/sync-deletes-unowned-broken-symlinks.md +35 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap.html +29 -6
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_configuration.py +114 -6
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_pkg.py +19 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_catalog.py +24 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_registry.py +41 -0
- boost_skill_cli-1.0.232/tests/unit/test_selfupdate.py +265 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_store.py +91 -0
- boost_skill_cli-1.0.230/docs/roadmap/items/ambiguous-tap-short-name-resolution.md +0 -22
- boost_skill_cli-1.0.230/docs/roadmap/items/self-update-broken-for-pip-pipx-installs.md +0 -22
- boost_skill_cli-1.0.230/docs/roadmap/items/sync-deletes-unowned-broken-symlinks.md +0 -22
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.gitattributes +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.gitignore +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.gitleaks.toml +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.htmlvalidate.json +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.lighthouserc.json +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.lycheeignore +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.markdownlint-cli2.jsonc +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.pre-commit-config.yaml +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.stylelintrc.json +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.vale/styles/boost/Terminology.yml +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.vale/styles/config/vocabularies/boost/accept.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/.vale.ini +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/CLAUDE.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/CONTRIBUTING.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/LICENSE +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/MANIFEST.in +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/Makefile +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/README.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/SECURITY.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/__init__.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/__main__.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/cli.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/cliparse.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/__init__.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/_common.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/bmad.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/discovery.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/hooks.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/info.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/intelligence.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/quality.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/run.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/safety.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/taps.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/commands/team.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/__init__.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/adapters.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/agents.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/ai.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/capabilities.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/claude_settings.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/config.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/dense.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/ed25519.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/embed.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/faithfulness.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/frontmatter.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/gitutil.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/imperative.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/injectscan.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/integrity.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/journal.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/lockfile.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/logs.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/mcp.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/mcpdecl.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/minisign.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/nethttp.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/output.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/paths.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/policy.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/projectlock.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/provenance.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/rag.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/resolve.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/rules.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/scopes.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/secretscan.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/serve.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/stackprobe.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/staleness.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/trustaudit.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/typosquat.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/updatediff.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/util.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/core/workflows.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/data/registries.json +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/errors.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_cli/spin.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_skill_cli.egg-info/entry_points.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_skill_cli.egg-info/requires.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/boost_skill_cli.egg-info/top_level.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/codecov.yml +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/.claude/settings.local.json +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/DEBUGGING.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/adapters.html +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/gifs/distill.gif +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/gifs/doctor.gif +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/gifs/explain.gif +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/gifs/hooks.gif +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/gifs/install.gif +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/gifs/pulse.gif +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/gifs/search.gif +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/gifs/tap.gif +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/tapes/distill.tape +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/tapes/doctor.tape +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/tapes/explain.tape +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/tapes/hooks.tape +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/tapes/install.tape +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/tapes/pulse.tape +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/tapes/search.tape +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel/tapes/tap.tape +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/carousel.html +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/demo.gif +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/demo.tape +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/design-roadmap.html +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/eval.html +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/index.html +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/mcp-hub.html +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/rag-architecture.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D01.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D02.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D03.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D04.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D05.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D06.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D07.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D08.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D09.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D10.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D11.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D12.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D13.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D14.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D15.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D16.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D17.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D18.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D19.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D20.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D21.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D22.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D23.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D24.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D25.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/BOOST-D26.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/ai-bridge-silent-failure-logging.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/boost-run-live-agents.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/ci-job-timeout-minutes.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/command-carousel-page.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/command-reference-docs-site.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/crash-listing-branch-untested.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/dense-search-fallback-and-stale-tap-pruning.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/dependabot-missing-pip-ecosystem.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/docsite-chrome-and-content-audit.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/framework-adapter-multi-agent.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/github-community-health-files.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/html-validation-html-validate.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/install-from-path-bypasses-policy-and-pin-checks.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/install-resolves-skill-dependencies.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/install-scope-user-or-project.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/installed-skill-trust-audit.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/journal-rotation-race-and-handle-leak.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/license-compliance-scanning.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/lint-tap-misscopes-rule-workflow-entries.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/lock-invariant-cannot-parse-extras-pins.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/main-has-no-branch-protection.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mcp-aware-skills.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mcp-search-before-reinventing.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/mypy-strict-mode-for-commands.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/negative-limit-inverts-log-pulse-output.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/onboard-overwrites-generated-files-without-confirm.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/path-traversal-unsanitized-rule-workflow-name.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/pin-the-lint-toolchain.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/project-scope-across-every-command.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/project-scope-symlink-escape-on-write.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/publish-gate-ignores-pip-audit-and-metadata.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/pytest-tmpdir-cve-blocked-by-py39-floor.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/rel-time-tests-race-the-wall-clock.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/required-checks-can-declare-a-check-that-deadlocks-prs.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/required-checks-config-drift.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/ruff-016-widens-the-default-rule-set.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/scorecard-findings-triage.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/serve-py-traversal-guards-untested.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/structured-json-log-output-mode.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/typo-detection-codespell.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/uninstall-has-no-confirmation-prompt.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/update-diff-before-apply.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/update-reinstall-widens-agent-scope.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/wire-bdd-suite-into-ci.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/docs/roadmap/items/workspace-scope-install.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/eslint.config.mjs +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/examples/README.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/examples/adapt-demo.sh +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/examples/boost-run-prototype.sh +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/index.html +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/noxfile.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/pyproject.toml +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/coverage-tools.in +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/coverage-tools.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/lint-tools.in +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/lint-tools.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/mutation-tools.in +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/mutation-tools.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/release-tools.in +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/release-tools.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/test-tools.in +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/requirements/test-tools.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/a11y_check.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/bench_cli.sh +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/build_command_reference.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/build_registries.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/build_roadmap.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/check_anchors.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/check_required_checks.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/ensure_eval_corpus.sh +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/eval_explain.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/eval_recommend.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/eval_retrieval.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/eval_stats_summary.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/import_budget.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/lock_toolchain.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/mutation_gate.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/perf_gate.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/post_deploy_smoke.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/scripts/release_preflight.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/setup.cfg +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/sonar-project.properties +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/style/README.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/style/boost.css +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/style/boost.js +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/style/demo.html +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/adapt.feature +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/browse.feature +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/count.feature +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/discover.feature +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/doctor.feature +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/environment.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/explain.feature +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/index.feature +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/install.feature +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/list.feature +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/mcp.feature +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/search.feature +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/steps/cli_steps.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/steps/discovery_steps.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/steps/mcp_steps.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/bdd/features/steps/quality_steps.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/conftest.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/eval/baseline.json +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/eval/explain.jsonl +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/eval/golden.jsonl +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/eval/recommend.jsonl +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/eval/taps.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_capabilities_policy.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_adapt.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_bmad.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_discovery.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_hooks.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_info.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_intelligence.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_quality.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_taps.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_cli_team.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_everyday_loop.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_integrity_enforce.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_property_parsers.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_run.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_tap_signing.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/functional/test_workspace_scope.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/README.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/01-typical.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/02-lossy-version.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/03-lossy-numbers.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/04-lists.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/05-nested.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/06-empty-block.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/07-unterminated.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/08-none.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/09-unbalanced-quote.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/10-keywords.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/11-crlf.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/frontmatter/12-bom.md +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/registry/01-shorthand.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/registry/02-https.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/registry/03-ssh.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/registry/04-traversal.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/registry/05-empty.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/registry/06-space.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/registry/07-slash.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/corpus/registry/08-bare-host.txt +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/fuzz_frontmatter.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/fuzz/fuzz_registry.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/make_fixture.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/perf/test_benchmarks.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/smoke.sh +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_a11y_check.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_adapters.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_adapters_multi.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_adapters_runner.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_agents.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_ai.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_capabilities.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_check_anchors.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_claude_settings.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_cliparse.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_command_reference_fresh.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_config.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_dense.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_dense_fallback.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_docs_pages_linked.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_docsite_chrome.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_ed25519.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_embed.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_errors_and_cli_table.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_eval_stats_summary.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_faithfulness.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_frontmatter.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_fuzz_targets.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_gitleaks_config.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_gitutil.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_imperative.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_import_budget.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_injectscan.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_integrity.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_journal.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_lockfile.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_logs.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_marketing_counts.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_mcp.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_mcpdecl.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_minisign.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_mutation_hardening.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_nethttp.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_output.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_paths.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_perf_gate.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_pkg_confusions.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_pkg_injection.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_pkg_secrets.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_policy.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_post_deploy_smoke.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_projectlock.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_provenance.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_rag.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_registries_fresh.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_release_preflight.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_required_checks.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_resolve.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_roadmap_fresh.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_rules.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_scopes.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_secretscan.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_serve.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_spin.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_stackprobe.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_staleness.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_token_parity.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_toolchain_lock.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_trustaudit.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_typosquat.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_updatediff.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_util.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_version.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/unit/test_workflows.py +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/visual/a11y_check.mjs +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/visual/console_check.mjs +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/tests/visual/package.json +0 -0
- {boost_skill_cli-1.0.230 → boost_skill_cli-1.0.232}/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.232'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 0, 232)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -26,6 +26,7 @@ from ..core import (
|
|
|
26
26
|
policy,
|
|
27
27
|
rag,
|
|
28
28
|
registry,
|
|
29
|
+
selfupdate,
|
|
29
30
|
serve,
|
|
30
31
|
store,
|
|
31
32
|
util,
|
|
@@ -119,10 +120,14 @@ def cmd_clean(argv) -> int:
|
|
|
119
120
|
adir = spec["dir"]
|
|
120
121
|
if not adir.is_dir():
|
|
121
122
|
continue
|
|
123
|
+
# Same ownership rule as `boost sync`: a broken symlink is only ours to
|
|
124
|
+
# remove if it pointed into the canonical store. A user's own dangling
|
|
125
|
+
# link in ~/.claude/skills is not boost's to clean up.
|
|
122
126
|
items.extend(
|
|
123
127
|
(link, "broken symlink", 0)
|
|
124
128
|
for link in sorted(adir.iterdir())
|
|
125
129
|
if link.is_symlink() and not link.exists()
|
|
130
|
+
and store.points_into_store(link)
|
|
126
131
|
)
|
|
127
132
|
|
|
128
133
|
configured = {t.safe_name for t in registry.list_taps()}
|
|
@@ -1000,12 +1005,47 @@ def cmd_self_update(argv) -> int:
|
|
|
1000
1005
|
p = cliparse.parser(
|
|
1001
1006
|
prog="boost self-update",
|
|
1002
1007
|
description="Update boost itself to the latest version")
|
|
1003
|
-
p.
|
|
1008
|
+
p.add_argument("--dry-run", action="store_true",
|
|
1009
|
+
help="show how boost would update itself, change nothing")
|
|
1010
|
+
args = p.parse_args(argv)
|
|
1011
|
+
|
|
1012
|
+
method = selfupdate.detect()
|
|
1013
|
+
if method != selfupdate.GIT:
|
|
1014
|
+
return _self_update_package(method, dry_run=args.dry_run)
|
|
1015
|
+
return _self_update_git(dry_run=args.dry_run)
|
|
1016
|
+
|
|
1017
|
+
|
|
1018
|
+
def _self_update_package(method: str, dry_run: bool) -> int:
|
|
1019
|
+
"""Upgrade a pip / pipx / uv-tool install by driving its own manager."""
|
|
1020
|
+
old = __version__
|
|
1021
|
+
cmd = selfupdate.upgrade_command(method) # errors if the manager is gone
|
|
1022
|
+
if dry_run:
|
|
1023
|
+
out.info("installed with: %s" % method)
|
|
1024
|
+
out.info("would run: %s" % " ".join(cmd))
|
|
1025
|
+
return 0
|
|
1026
|
+
out.info("updating via %s: %s" % (method, " ".join(cmd)))
|
|
1027
|
+
selfupdate.run_upgrade(cmd)
|
|
1028
|
+
# This process imported its version before the upgrade, so ask a fresh one.
|
|
1029
|
+
new = selfupdate.observed_version()
|
|
1030
|
+
journal.log("self-update", new or old, previous=old, method=method)
|
|
1031
|
+
if new and new != old:
|
|
1032
|
+
out.ok("boost v%s → v%s" % (old, new))
|
|
1033
|
+
elif new:
|
|
1034
|
+
out.ok("already up to date (v%s)" % new)
|
|
1035
|
+
else:
|
|
1036
|
+
# The upgrade succeeded but we never saw a version — say exactly that
|
|
1037
|
+
# rather than claim one.
|
|
1038
|
+
out.ok("upgraded via %s; run `boost --version` to confirm" % method)
|
|
1039
|
+
return 0
|
|
1040
|
+
|
|
1004
1041
|
|
|
1042
|
+
def _self_update_git(dry_run: bool) -> int:
|
|
1043
|
+
"""Fast-forward the source checkout boost is running from."""
|
|
1005
1044
|
root = paths.repo_root()
|
|
1006
|
-
if
|
|
1007
|
-
|
|
1008
|
-
|
|
1045
|
+
if dry_run:
|
|
1046
|
+
out.info("installed with: git checkout (%s)" % _tilde(root))
|
|
1047
|
+
out.info("would run: git -C %s pull --ff-only" % root)
|
|
1048
|
+
return 0
|
|
1009
1049
|
old = __version__
|
|
1010
1050
|
before = gitutil.head_commit(root)
|
|
1011
1051
|
gitutil.run(["-C", str(root), "pull", "--ff-only"], timeout=120)
|
|
@@ -864,6 +864,14 @@ def _bundle_install(file: Optional[str]) -> int:
|
|
|
864
864
|
% (sname, (" in tap %s" % tapq) if tapq else ""))
|
|
865
865
|
failed += 1
|
|
866
866
|
continue
|
|
867
|
+
if len({e["tap"] for e in matches}) > 1:
|
|
868
|
+
# A Boostfile is meant to be reproducible, so guessing which tap
|
|
869
|
+
# `skills:brainstorming` meant is the one thing this must not do.
|
|
870
|
+
out.warn("%s is ambiguous — in %s; qualify it as owner/repo:%s"
|
|
871
|
+
% (sname, ", ".join(sorted({e["tap"] for e in matches})),
|
|
872
|
+
sname))
|
|
873
|
+
failed += 1
|
|
874
|
+
continue
|
|
867
875
|
entry = matches[0]
|
|
868
876
|
if sver and str(entry.get("version")) != sver:
|
|
869
877
|
out.warn("%s: Boostfile wants @%s, tap has %s — installing that"
|
|
@@ -248,8 +248,15 @@ def find(name: str, tap: Optional[str] = None) -> List[dict]:
|
|
|
248
248
|
tap, name = name.rsplit(":", 1)
|
|
249
249
|
matches = [e for e in all_entries() if e["name"] == name]
|
|
250
250
|
if tap:
|
|
251
|
-
|
|
252
|
-
|
|
251
|
+
# Same tiering as registry.get: a qualified owner/repo beats a bare
|
|
252
|
+
# repo tail, so `angular/skills:x` never picks up `microsoft/skills:x`.
|
|
253
|
+
# Without this the two resolvers disagreed — `boost untap skills`
|
|
254
|
+
# errored on the ambiguity while `boost bundle apply` with
|
|
255
|
+
# `skills:brainstorming` silently took matches[0] from whichever tap
|
|
256
|
+
# sorted first.
|
|
257
|
+
exact = [e for e in matches if e["tap"] == tap]
|
|
258
|
+
matches = exact or [e for e in matches
|
|
259
|
+
if e["tap"].split("/")[-1] == tap]
|
|
253
260
|
return matches
|
|
254
261
|
|
|
255
262
|
|
|
@@ -80,12 +80,26 @@ def list_taps() -> List[Tap]:
|
|
|
80
80
|
def get(name: str) -> Tap:
|
|
81
81
|
"""Look up a tap by name, safe_name, or bare repo name.
|
|
82
82
|
|
|
83
|
+
Tiered so a qualified name always beats a short one: exact ``owner/repo``
|
|
84
|
+
first, then ``safe_name``, then the bare repo tail. Within a tier a name
|
|
85
|
+
that matches more than one tap is an error rather than a guess — with
|
|
86
|
+
``angular/skills`` and ``microsoft/skills`` both tapped, ``boost untap
|
|
87
|
+
skills`` used to act on whichever came first in config.json, which for a
|
|
88
|
+
destructive command is the wrong answer half the time.
|
|
89
|
+
|
|
83
90
|
Raises BoostError (with a did-you-mean hint) if none match.
|
|
84
91
|
"""
|
|
85
92
|
taps = list_taps()
|
|
86
|
-
for
|
|
87
|
-
|
|
88
|
-
|
|
93
|
+
for key in (lambda t: t.name, lambda t: t.safe_name,
|
|
94
|
+
lambda t: t.name.split("/")[-1]):
|
|
95
|
+
hits = [t for t in taps if key(t) == name]
|
|
96
|
+
if len(hits) == 1:
|
|
97
|
+
return hits[0]
|
|
98
|
+
if len(hits) > 1:
|
|
99
|
+
raise BoostError(
|
|
100
|
+
"%r is ambiguous — it matches %d taps: %s"
|
|
101
|
+
% (name, len(hits), ", ".join(sorted(t.name for t in hits))),
|
|
102
|
+
hint="use the full owner/repo name")
|
|
89
103
|
close = difflib.get_close_matches(name, [t.name for t in taps], n=1)
|
|
90
104
|
raise BoostError("no such tap: %s" % name,
|
|
91
105
|
hint=("did you mean %s?" % close[0]) if close
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""How this boost was installed, and the command that upgrades it in place.
|
|
2
|
+
|
|
3
|
+
`boost self-update` assumed a git checkout and told everyone else to abandon
|
|
4
|
+
their install method — but the documented way in is `pipx install
|
|
5
|
+
boost-skill-cli` or `pip install boost-skill-cli`, where the package lives in
|
|
6
|
+
site-packages and there is nothing to `git pull`. This resolves the install
|
|
7
|
+
method from evidence on disk and hands the command layer the exact argv that
|
|
8
|
+
upgrades *this* copy.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import re
|
|
13
|
+
import shutil
|
|
14
|
+
import subprocess
|
|
15
|
+
import sys
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import List, Optional
|
|
18
|
+
|
|
19
|
+
from ..errors import BoostError
|
|
20
|
+
from . import gitutil, paths
|
|
21
|
+
|
|
22
|
+
DIST = "boost-skill-cli"
|
|
23
|
+
|
|
24
|
+
GIT = "git"
|
|
25
|
+
PIPX = "pipx"
|
|
26
|
+
UV_TOOL = "uv-tool"
|
|
27
|
+
PIP = "pip"
|
|
28
|
+
UNKNOWN = "unknown"
|
|
29
|
+
|
|
30
|
+
# `boost --version` prints "boost <version>"; anything else means we did not
|
|
31
|
+
# actually observe a version and must not report one.
|
|
32
|
+
_VERSION_LINE = re.compile(r"^boost\s+(\S+)$", re.MULTILINE)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def installed_version() -> Optional[str]:
|
|
36
|
+
"""Version recorded in installed package metadata, or None.
|
|
37
|
+
|
|
38
|
+
None is the useful answer, not a failure: it means no Python package
|
|
39
|
+
manager has a record of this boost, so none of them can upgrade it.
|
|
40
|
+
"""
|
|
41
|
+
try:
|
|
42
|
+
from importlib.metadata import version
|
|
43
|
+
return version(DIST)
|
|
44
|
+
except Exception:
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def detect(root: Optional[Path] = None, prefix: Optional[Path] = None,
|
|
49
|
+
metadata_version=None) -> str:
|
|
50
|
+
"""Resolve how this boost was installed.
|
|
51
|
+
|
|
52
|
+
Order matters. A source checkout wins first — that includes `pip install
|
|
53
|
+
-e .`, where the package metadata exists too but `git pull` is what the
|
|
54
|
+
user means. Then the two managers that own a private venv and leave a
|
|
55
|
+
receipt inside it. Then plain pip, but only if pip actually has a record
|
|
56
|
+
of the distribution: telling someone to `pip install --upgrade` a boost
|
|
57
|
+
that pip never installed sends them chasing a package that isn't there.
|
|
58
|
+
"""
|
|
59
|
+
root = paths.repo_root() if root is None else Path(root)
|
|
60
|
+
if gitutil.is_repo(root):
|
|
61
|
+
return GIT
|
|
62
|
+
prefix = Path(sys.prefix) if prefix is None else Path(prefix)
|
|
63
|
+
if (prefix / "pipx_metadata.json").is_file():
|
|
64
|
+
return PIPX
|
|
65
|
+
if (prefix / "uv-receipt.toml").is_file():
|
|
66
|
+
return UV_TOOL
|
|
67
|
+
# Resolved here, not as a default argument: a default binds the function
|
|
68
|
+
# object once at import, which silently defeats every attempt to swap it —
|
|
69
|
+
# including a test's, which is how a test of the "nothing installed this"
|
|
70
|
+
# branch ended up running a real `pip install` against PyPI.
|
|
71
|
+
lookup = installed_version if metadata_version is None else metadata_version
|
|
72
|
+
return PIP if lookup() else UNKNOWN
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _require(tool: str) -> str:
|
|
76
|
+
"""Absolute path to `tool`, or a BoostError naming what is missing.
|
|
77
|
+
|
|
78
|
+
Falling back to another manager here would upgrade a different copy of
|
|
79
|
+
boost — or none at all — while reporting success.
|
|
80
|
+
"""
|
|
81
|
+
found = shutil.which(tool)
|
|
82
|
+
if not found:
|
|
83
|
+
raise BoostError(
|
|
84
|
+
"boost was installed with %s, but %s is not on PATH" % (tool, tool),
|
|
85
|
+
hint="install %s, or upgrade manually with `%s upgrade %s`"
|
|
86
|
+
% (tool, tool, DIST))
|
|
87
|
+
return found
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def upgrade_command(method: str) -> List[str]:
|
|
91
|
+
"""The argv that upgrades boost for `method`."""
|
|
92
|
+
if method == PIPX:
|
|
93
|
+
return [_require("pipx"), "upgrade", DIST]
|
|
94
|
+
if method == UV_TOOL:
|
|
95
|
+
return [_require("uv"), "tool", "upgrade", DIST]
|
|
96
|
+
if method == PIP:
|
|
97
|
+
# sys.executable, never a bare `pip`: the pip first on PATH can belong
|
|
98
|
+
# to a different interpreter than the one running boost, and upgrading
|
|
99
|
+
# that one leaves this install exactly where it was while printing
|
|
100
|
+
# every sign of success.
|
|
101
|
+
return [sys.executable, "-m", "pip", "install", "--upgrade", DIST]
|
|
102
|
+
raise BoostError(
|
|
103
|
+
"cannot work out how boost was installed, so it cannot update itself",
|
|
104
|
+
hint="upgrade with your package manager, e.g. `pipx upgrade %s`" % DIST)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def run_upgrade(cmd: List[str], timeout: float = 300.0):
|
|
108
|
+
"""Run the upgrade, raising BoostError with the manager's own last words."""
|
|
109
|
+
try:
|
|
110
|
+
proc = subprocess.run(cmd, capture_output=True, text=True,
|
|
111
|
+
timeout=timeout)
|
|
112
|
+
except (OSError, subprocess.SubprocessError) as err:
|
|
113
|
+
raise BoostError("could not run %s" % " ".join(cmd),
|
|
114
|
+
hint=str(err)) from err
|
|
115
|
+
if proc.returncode != 0:
|
|
116
|
+
detail = ((proc.stderr or "") + (proc.stdout or "")).strip().splitlines()
|
|
117
|
+
raise BoostError(
|
|
118
|
+
"upgrade failed (%s exited %d)" % (Path(cmd[0]).name, proc.returncode),
|
|
119
|
+
hint=detail[-1] if detail else "re-run the command by hand to see why")
|
|
120
|
+
return proc
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def observed_version(timeout: float = 30.0) -> Optional[str]:
|
|
124
|
+
"""Ask a freshly-spawned boost what version it is now, or None.
|
|
125
|
+
|
|
126
|
+
This process imported its own version before the upgrade ran, so it cannot
|
|
127
|
+
answer the question. None means "we did not see one" — better to say
|
|
128
|
+
nothing than to report a version we never observed.
|
|
129
|
+
"""
|
|
130
|
+
try:
|
|
131
|
+
proc = subprocess.run([str(paths.launcher()), "--version"],
|
|
132
|
+
capture_output=True, text=True, timeout=timeout)
|
|
133
|
+
except (OSError, subprocess.SubprocessError):
|
|
134
|
+
return None
|
|
135
|
+
if proc.returncode != 0:
|
|
136
|
+
return None
|
|
137
|
+
match = _VERSION_LINE.search(proc.stdout or "")
|
|
138
|
+
return match.group(1) if match else None
|
|
@@ -810,6 +810,65 @@ def uninstall(name: str) -> dict:
|
|
|
810
810
|
return {"name": name, "unlinked": removed_links, "entry": entry}
|
|
811
811
|
|
|
812
812
|
|
|
813
|
+
def strip_extended_prefix(text: str) -> str:
|
|
814
|
+
"""Drop Windows' ``\\\\?\\`` extended-length prefix from a raw path string.
|
|
815
|
+
|
|
816
|
+
Since 3.8, `os.readlink()` on Windows returns the reparse point's
|
|
817
|
+
substitution path, which typically carries that prefix — so boost's own
|
|
818
|
+
link into the store reads back as
|
|
819
|
+
``\\\\?\\C:\\Users\\...\\.agents\\skills\\x``. Compared by path components
|
|
820
|
+
that is a *different drive* from ``C:\\Users\\...``, and every Windows leg
|
|
821
|
+
of the matrix went red on exactly this. The check it replaced was a
|
|
822
|
+
substring test, which the prefix sailed straight through; comparing
|
|
823
|
+
properly is what exposed it.
|
|
824
|
+
"""
|
|
825
|
+
if text.startswith("\\\\?\\UNC\\"):
|
|
826
|
+
return "\\\\" + text[len("\\\\?\\UNC\\"):]
|
|
827
|
+
if text.startswith("\\\\?\\"):
|
|
828
|
+
return text[len("\\\\?\\"):]
|
|
829
|
+
return text
|
|
830
|
+
|
|
831
|
+
|
|
832
|
+
def normalize_link_target(path: Path) -> str:
|
|
833
|
+
"""A comparable string form of a `readlink()` result.
|
|
834
|
+
|
|
835
|
+
Normalizes separators and case as well as the prefix: Windows paths
|
|
836
|
+
compare case-insensitively, and POSIX `normcase` is a no-op.
|
|
837
|
+
"""
|
|
838
|
+
return os.path.normcase(os.path.normpath(strip_extended_prefix(str(path))))
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
def points_into_store(link: Path) -> bool:
|
|
842
|
+
"""True if `link`'s target lands inside boost's canonical store.
|
|
843
|
+
|
|
844
|
+
Reads the raw `readlink()` target rather than `resolve()`, because the
|
|
845
|
+
links this has to judge are usually broken — `resolve()` cannot tell us
|
|
846
|
+
where a dangling link was aiming. A relative target is resolved against
|
|
847
|
+
the link's own directory, and containment is decided by `commonpath`
|
|
848
|
+
(the same guard `scopes.contains` uses): a substring test on the store
|
|
849
|
+
path also matches siblings like `~/.agents/skills-backup`, which boost
|
|
850
|
+
does not own either.
|
|
851
|
+
|
|
852
|
+
Everything boost deletes under an agent's skills dir is gated on this.
|
|
853
|
+
A user's own broken symlink sitting in `~/.claude/skills` is not ours.
|
|
854
|
+
Fails closed — an unreadable link is not boost's to delete.
|
|
855
|
+
"""
|
|
856
|
+
try:
|
|
857
|
+
target = link.readlink()
|
|
858
|
+
except OSError:
|
|
859
|
+
return False
|
|
860
|
+
if not target.is_absolute():
|
|
861
|
+
target = link.parent / target
|
|
862
|
+
target_s = normalize_link_target(target)
|
|
863
|
+
root_s = normalize_link_target(paths.store_dir())
|
|
864
|
+
try:
|
|
865
|
+
# ValueError for paths with no common root — on Windows, two different
|
|
866
|
+
# drives — which means "outside", not "crash out of the delete guard".
|
|
867
|
+
return os.path.commonpath([target_s, root_s]) == root_s
|
|
868
|
+
except ValueError:
|
|
869
|
+
return False
|
|
870
|
+
|
|
871
|
+
|
|
813
872
|
def sync_plan() -> Dict[str, list]:
|
|
814
873
|
"""Compare lock file <-> store <-> agent symlinks.
|
|
815
874
|
|
|
@@ -843,11 +902,12 @@ def sync_plan() -> Dict[str, list]:
|
|
|
843
902
|
if not adir.is_dir():
|
|
844
903
|
continue
|
|
845
904
|
for link in adir.iterdir():
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
905
|
+
# Ownership first, for broken links too: the old test short-circuited
|
|
906
|
+
# on `not link.exists()`, so any dangling symlink a user happened to
|
|
907
|
+
# keep in ~/.claude/skills was swept up by `boost sync`.
|
|
908
|
+
if (link.is_symlink() and points_into_store(link)
|
|
909
|
+
and (not link.exists() or link.name not in lock)):
|
|
910
|
+
plan["stale_links"].append(str(link))
|
|
851
911
|
# Rules/workflows don't live in the store — they materialize into agent dirs.
|
|
852
912
|
# A materialization whose file (or CLAUDE.md block) is gone can be repaired
|
|
853
913
|
# by re-materializing from the tap, same as a missing skill store dir.
|
|
@@ -81,6 +81,7 @@ boost_cli/core/resolve.py
|
|
|
81
81
|
boost_cli/core/rules.py
|
|
82
82
|
boost_cli/core/scopes.py
|
|
83
83
|
boost_cli/core/secretscan.py
|
|
84
|
+
boost_cli/core/selfupdate.py
|
|
84
85
|
boost_cli/core/serve.py
|
|
85
86
|
boost_cli/core/stackprobe.py
|
|
86
87
|
boost_cli/core/staleness.py
|
|
@@ -460,6 +461,7 @@ tests/unit/test_roadmap_fresh.py
|
|
|
460
461
|
tests/unit/test_rules.py
|
|
461
462
|
tests/unit/test_scopes.py
|
|
462
463
|
tests/unit/test_secretscan.py
|
|
464
|
+
tests/unit/test_selfupdate.py
|
|
463
465
|
tests/unit/test_serve.py
|
|
464
466
|
tests/unit/test_spin.py
|
|
465
467
|
tests/unit/test_stackprobe.py
|
|
@@ -188,7 +188,7 @@
|
|
|
188
188
|
<a class="cmd-link" href="#cmd-mcp" data-search="mcp register boost as an mcp server for claude code --stdio {register,unregister}">mcp</a>
|
|
189
189
|
<a class="cmd-link" href="#cmd-hooks" data-search="hooks manage claude code hooks (scope-aware) in settings.json -c, --command command -n, --name name -s, --scope {global,project} -m, --matcher matcher --timeout timeout {add,remove,list} event">hooks</a>
|
|
190
190
|
<a class="cmd-link" href="#cmd-bmad" data-search="bmad install & manage the bmad method (scope-aware, toggleable) -s, --scope {project,global} --modules modules -y, --yes --startup {install,init,startup,orient,uninstall,disable,enable,doctor,status} value">bmad</a>
|
|
191
|
-
<a class="cmd-link" href="#cmd-self-update" data-search="self-update update boost itself to the latest version
|
|
191
|
+
<a class="cmd-link" href="#cmd-self-update" data-search="self-update update boost itself to the latest version --dry-run">self-update</a>
|
|
192
192
|
</div>
|
|
193
193
|
<div class="group" data-group="team">
|
|
194
194
|
<div class="group-h">Team & sharing</div>
|
|
@@ -1083,10 +1083,14 @@
|
|
|
1083
1083
|
<div class="arg"><code>--startup</code><span>enable the startup toggle right after install</span></div>
|
|
1084
1084
|
</div>
|
|
1085
1085
|
</section>
|
|
1086
|
-
<section class="cmd" id="cmd-self-update" data-search="self-update update boost itself to the latest version
|
|
1086
|
+
<section class="cmd" id="cmd-self-update" data-search="self-update update boost itself to the latest version --dry-run">
|
|
1087
1087
|
<h3><span class="cname">self-update</span><span class="gtag">cfg</span></h3>
|
|
1088
1088
|
<p class="summary">Update boost itself to the latest version</p>
|
|
1089
|
-
<pre class="syn">boost self-update</pre>
|
|
1089
|
+
<pre class="syn">boost self-update [--dry-run]</pre>
|
|
1090
|
+
<div class="args-h">Options</div>
|
|
1091
|
+
<div class="args">
|
|
1092
|
+
<div class="arg"><code>--dry-run</code><span>show how boost would update itself, change nothing</span></div>
|
|
1093
|
+
</div>
|
|
1090
1094
|
</section>
|
|
1091
1095
|
<h2 class="group-h" id="grp-team">Team & sharing</h2>
|
|
1092
1096
|
<section class="cmd" id="cmd-cohort" data-search="cohort controlled skill rollouts & team a/b testing --skills skills --percent percent --json {list,create,delete,status,apply} name">
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: ambiguous-tap-short-name-resolution
|
|
3
|
+
board: code
|
|
4
|
+
section: internals
|
|
5
|
+
status: shipped
|
|
6
|
+
category: Bug
|
|
7
|
+
complexity: S
|
|
8
|
+
impact: High
|
|
9
|
+
wow: 3
|
|
10
|
+
note:
|
|
11
|
+
order: 28
|
|
12
|
+
owner: loop/tap-name-ambiguity
|
|
13
|
+
pr:
|
|
14
|
+
title: Ambiguous tap short-name resolution silently picks the wrong tap
|
|
15
|
+
---
|
|
16
|
+
<code>registry.get(name)</code> matches on full name, safe-name, or trailing path segment and returns
|
|
17
|
+
the <em>first</em> hit with no ambiguity check — unlike <code>catalog.resolve_one</code>, which
|
|
18
|
+
explicitly errors on a multi-tap ambiguous match. Three of the five default taps end in
|
|
19
|
+
<code>/skills</code>, so after <code>boost tap --defaults</code>, <code>boost untap skills</code> or
|
|
20
|
+
<code>boost update skills</code> silently resolves to whichever tap sorts first and the others
|
|
21
|
+
become unreachable by short name. Raise on an ambiguous short-name match, mirroring
|
|
22
|
+
<code>resolve_one</code>.
|
|
23
|
+
<b>Shipped.</b> <code>registry.get()</code> is now tiered — exact <code>owner/repo</code>, then <code>safe_name</code>, then the bare repo tail — and refuses a short name that matches more than one tap instead of taking the first. Two corrections while fixing it: there is no <i>sort</i>, the winner was whichever came first in <code>config.json</code>; and the fix was <b>half a fix</b> as originally scoped. <code>catalog.find()</code> carried an independent, untiered <code>tap in (e["tap"], tail)</code> membership test, so with both taps configured <code>angular/skills:brainstorming</code> also matched <code>microsoft/skills</code>, and <code>boost bundle apply</code> took <code>matches[0]</code> — silently installing from the wrong tap, verbatim the defect this item exists to fix. Fixing only <code>registry.get</code> would have left the CLI self-contradictory: <code>boost untap skills</code> erroring while a Boostfile silently guessed. Both resolvers are tiered now and <code>bundle apply</code> refuses an ambiguous entry rather than picking one.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: self-update-broken-for-pip-pipx-installs
|
|
3
|
+
board: code
|
|
4
|
+
section: compat
|
|
5
|
+
status: shipped
|
|
6
|
+
category: Bug
|
|
7
|
+
complexity: M
|
|
8
|
+
impact: High
|
|
9
|
+
wow: 3
|
|
10
|
+
note:
|
|
11
|
+
order: 10
|
|
12
|
+
owner: loop/self-update
|
|
13
|
+
pr: 272
|
|
14
|
+
title: <code>self-update</code> is non-functional for pip/pipx installs
|
|
15
|
+
---
|
|
16
|
+
<code>boost self-update</code> only works when boost runs from a git checkout: <code>paths.repo_root()</code>
|
|
17
|
+
resolves inside <code>site-packages</code> for a pip/pipx install, <code>gitutil.is_repo()</code> is
|
|
18
|
+
False, and <code>cmd_self_update</code> raises "boost is not running from a git checkout" with a hint
|
|
19
|
+
to clone the repo — telling a normal PyPI user to abandon their install method. Detect the install
|
|
20
|
+
method and shell out to <code>pip install --upgrade boost-skill-cli</code> /
|
|
21
|
+
<code>pipx upgrade boost-skill-cli</code>, falling back to the git-pull path only for source
|
|
22
|
+
checkouts. Shipped as <code>core/selfupdate.py</code>: detection reads evidence on disk —
|
|
23
|
+
<code>.git</code>, then <code>pipx_metadata.json</code> or <code>uv-receipt.toml</code> in
|
|
24
|
+
<code>sys.prefix</code>, then installed package metadata — and a <code>--dry-run</code> flag
|
|
25
|
+
prints the exact command without running it. Two details carry the weight: the pip branch
|
|
26
|
+
invokes <code>sys.executable -m pip</code>, never a bare <code>pip</code>, because the pip
|
|
27
|
+
first on PATH can belong to another interpreter and would upgrade a different copy while
|
|
28
|
+
reporting success; and an install nothing has a record of reports that plainly instead of
|
|
29
|
+
guessing pip. The new version is read from a freshly spawned <code>boost --version</code>,
|
|
30
|
+
since the running process imported its own version before the upgrade — if that probe says
|
|
31
|
+
nothing, neither does boost.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: sync-deletes-unowned-broken-symlinks
|
|
3
|
+
board: code
|
|
4
|
+
section: internals
|
|
5
|
+
status: shipped
|
|
6
|
+
category: Bug
|
|
7
|
+
complexity: S
|
|
8
|
+
impact: Med
|
|
9
|
+
wow: 2
|
|
10
|
+
note:
|
|
11
|
+
order: 29
|
|
12
|
+
owner: loop/sync-symlink-ownership
|
|
13
|
+
pr: 273
|
|
14
|
+
title: <code>sync --apply</code> deletes any broken symlink, not just boost's own
|
|
15
|
+
---
|
|
16
|
+
<code>sync_plan</code> flags every broken symlink under an enabled agent dir as stale regardless of
|
|
17
|
+
whether it points into boost's store — the <code>points_into_store</code> check only runs on the
|
|
18
|
+
live-link branch — and <code>sync_apply</code> unconditionally unlinks everything in
|
|
19
|
+
<code>stale_links</code>. A user's own unrelated broken symlink sitting in
|
|
20
|
+
<code>~/.claude/skills</code> gets deleted by <code>boost sync --apply</code> with no ownership
|
|
21
|
+
check. Only treat a broken symlink as boost-managed if its raw <code>readlink()</code> target
|
|
22
|
+
resolves under the store dir. Shipped as <code>store.points_into_store()</code>, applied to
|
|
23
|
+
broken and live links alike. Two things turned up while fixing it. <code>boost clean</code>
|
|
24
|
+
carried the identical overreach — it unlinked every broken symlink under an agent dir with no
|
|
25
|
+
ownership test at all — so it now shares the same helper; fixing only <code>sync</code> would
|
|
26
|
+
have left boost contradicting itself. And the original check was a substring test
|
|
27
|
+
(<code>str(store_dir) in str(target)</code>), which also matches siblings like
|
|
28
|
+
<code>~/.agents/skills-backup</code>; the comparison is component-wise now, and a relative
|
|
29
|
+
<code>readlink()</code> target is resolved against the link's own directory before it is judged.
|
|
30
|
+
Comparing properly is what exposed a Windows bug the sloppy check had been hiding: since 3.8
|
|
31
|
+
<code>os.readlink()</code> there returns the reparse point's substitution path, which carries the
|
|
32
|
+
<code>\\?\</code> extended-length prefix, so boost's own link reads back as a
|
|
33
|
+
<em>different drive</em> and stopped matching the store at all. Every Windows leg of the matrix
|
|
34
|
+
went red on it. The prefix is stripped before comparison, and the behaviour is pinned on every
|
|
35
|
+
platform via <code>ntpath</code>, which imports fine on POSIX.
|
|
@@ -948,7 +948,7 @@ chunks instead cost ~70%.</p>
|
|
|
948
948
|
</article>
|
|
949
949
|
|
|
950
950
|
<article class="cap rcard" id="ambiguous-tap-short-name-resolution">
|
|
951
|
-
<div class="head"><span class="pill
|
|
951
|
+
<div class="head"><span class="pill shipped">Shipped</span><span class="cat">Bug</span></div>
|
|
952
952
|
<h3>Ambiguous tap short-name resolution silently picks the wrong tap</h3>
|
|
953
953
|
<p><code>registry.get(name)</code> matches on full name, safe-name, or trailing path segment and returns
|
|
954
954
|
the <em>first</em> hit with no ambiguity check — unlike <code>catalog.resolve_one</code>, which
|
|
@@ -956,7 +956,8 @@ explicitly errors on a multi-tap ambiguous match. Three of the five default taps
|
|
|
956
956
|
<code>/skills</code>, so after <code>boost tap --defaults</code>, <code>boost untap skills</code> or
|
|
957
957
|
<code>boost update skills</code> silently resolves to whichever tap sorts first and the others
|
|
958
958
|
become unreachable by short name. Raise on an ambiguous short-name match, mirroring
|
|
959
|
-
<code>resolve_one</code
|
|
959
|
+
<code>resolve_one</code>.
|
|
960
|
+
<b>Shipped.</b> <code>registry.get()</code> is now tiered — exact <code>owner/repo</code>, then <code>safe_name</code>, then the bare repo tail — and refuses a short name that matches more than one tap instead of taking the first. Two corrections while fixing it: there is no <i>sort</i>, the winner was whichever came first in <code>config.json</code>; and the fix was <b>half a fix</b> as originally scoped. <code>catalog.find()</code> carried an independent, untiered <code>tap in (e["tap"], tail)</code> membership test, so with both taps configured <code>angular/skills:brainstorming</code> also matched <code>microsoft/skills</code>, and <code>boost bundle apply</code> took <code>matches[0]</code> — silently installing from the wrong tap, verbatim the defect this item exists to fix. Fixing only <code>registry.get</code> would have left the CLI self-contradictory: <code>boost untap skills</code> erroring while a Boostfile silently guessed. Both resolvers are tiered now and <code>bundle apply</code> refuses an ambiguous entry rather than picking one.</p>
|
|
960
961
|
<div class="meta">
|
|
961
962
|
<span class="m">Complexity <b>S</b></span>
|
|
962
963
|
<span class="m hi">Impact <b>High</b></span>
|
|
@@ -965,7 +966,7 @@ become unreachable by short name. Raise on an ambiguous short-name match, mirror
|
|
|
965
966
|
</article>
|
|
966
967
|
|
|
967
968
|
<article class="cap rcard" id="sync-deletes-unowned-broken-symlinks">
|
|
968
|
-
<div class="head"><span class="pill
|
|
969
|
+
<div class="head"><span class="pill shipped">Shipped</span><span class="cat">Bug</span></div>
|
|
969
970
|
<h3><code>sync --apply</code> deletes any broken symlink, not just boost's own</h3>
|
|
970
971
|
<p><code>sync_plan</code> flags every broken symlink under an enabled agent dir as stale regardless of
|
|
971
972
|
whether it points into boost's store — the <code>points_into_store</code> check only runs on the
|
|
@@ -973,7 +974,20 @@ live-link branch — and <code>sync_apply</code> unconditionally unlinks everyth
|
|
|
973
974
|
<code>stale_links</code>. A user's own unrelated broken symlink sitting in
|
|
974
975
|
<code>~/.claude/skills</code> gets deleted by <code>boost sync --apply</code> with no ownership
|
|
975
976
|
check. Only treat a broken symlink as boost-managed if its raw <code>readlink()</code> target
|
|
976
|
-
resolves under the store dir
|
|
977
|
+
resolves under the store dir. Shipped as <code>store.points_into_store()</code>, applied to
|
|
978
|
+
broken and live links alike. Two things turned up while fixing it. <code>boost clean</code>
|
|
979
|
+
carried the identical overreach — it unlinked every broken symlink under an agent dir with no
|
|
980
|
+
ownership test at all — so it now shares the same helper; fixing only <code>sync</code> would
|
|
981
|
+
have left boost contradicting itself. And the original check was a substring test
|
|
982
|
+
(<code>str(store_dir) in str(target)</code>), which also matches siblings like
|
|
983
|
+
<code>~/.agents/skills-backup</code>; the comparison is component-wise now, and a relative
|
|
984
|
+
<code>readlink()</code> target is resolved against the link's own directory before it is judged.
|
|
985
|
+
Comparing properly is what exposed a Windows bug the sloppy check had been hiding: since 3.8
|
|
986
|
+
<code>os.readlink()</code> there returns the reparse point's substitution path, which carries the
|
|
987
|
+
<code>\\?\</code> extended-length prefix, so boost's own link reads back as a
|
|
988
|
+
<em>different drive</em> and stopped matching the store at all. Every Windows leg of the matrix
|
|
989
|
+
went red on it. The prefix is stripped before comparison, and the behaviour is pinned on every
|
|
990
|
+
platform via <code>ntpath</code>, which imports fine on POSIX.</p>
|
|
977
991
|
<div class="meta">
|
|
978
992
|
<span class="m">Complexity <b>S</b></span>
|
|
979
993
|
<span class="m">Impact <b>Med</b></span>
|
|
@@ -2814,7 +2828,7 @@ same nav and footer as every other page.</p>
|
|
|
2814
2828
|
</article>
|
|
2815
2829
|
|
|
2816
2830
|
<article class="cap rcard" id="self-update-broken-for-pip-pipx-installs">
|
|
2817
|
-
<div class="head"><span class="pill
|
|
2831
|
+
<div class="head"><span class="pill shipped">Shipped</span><span class="cat">Bug</span></div>
|
|
2818
2832
|
<h3><code>self-update</code> is non-functional for pip/pipx installs</h3>
|
|
2819
2833
|
<p><code>boost self-update</code> only works when boost runs from a git checkout: <code>paths.repo_root()</code>
|
|
2820
2834
|
resolves inside <code>site-packages</code> for a pip/pipx install, <code>gitutil.is_repo()</code> is
|
|
@@ -2822,7 +2836,16 @@ False, and <code>cmd_self_update</code> raises "boost is not running from a git
|
|
|
2822
2836
|
to clone the repo — telling a normal PyPI user to abandon their install method. Detect the install
|
|
2823
2837
|
method and shell out to <code>pip install --upgrade boost-skill-cli</code> /
|
|
2824
2838
|
<code>pipx upgrade boost-skill-cli</code>, falling back to the git-pull path only for source
|
|
2825
|
-
checkouts
|
|
2839
|
+
checkouts. Shipped as <code>core/selfupdate.py</code>: detection reads evidence on disk —
|
|
2840
|
+
<code>.git</code>, then <code>pipx_metadata.json</code> or <code>uv-receipt.toml</code> in
|
|
2841
|
+
<code>sys.prefix</code>, then installed package metadata — and a <code>--dry-run</code> flag
|
|
2842
|
+
prints the exact command without running it. Two details carry the weight: the pip branch
|
|
2843
|
+
invokes <code>sys.executable -m pip</code>, never a bare <code>pip</code>, because the pip
|
|
2844
|
+
first on PATH can belong to another interpreter and would upgrade a different copy while
|
|
2845
|
+
reporting success; and an install nothing has a record of reports that plainly instead of
|
|
2846
|
+
guessing pip. The new version is read from a freshly spawned <code>boost --version</code>,
|
|
2847
|
+
since the running process imported its own version before the upgrade — if that probe says
|
|
2848
|
+
nothing, neither does boost.</p>
|
|
2826
2849
|
<div class="meta">
|
|
2827
2850
|
<span class="m">Complexity <b>M</b></span>
|
|
2828
2851
|
<span class="m hi">Impact <b>High</b></span>
|