boost-skill-cli 1.0.402__tar.gz → 1.0.404__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.402 → boost_skill_cli-1.0.404}/PKG-INFO +1 -1
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/_version.py +2 -2
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/pkg.py +19 -1
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/quality.py +131 -13
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_skill_cli.egg-info/PKG-INFO +1 -1
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_skill_cli.egg-info/SOURCES.txt +3 -0
- boost_skill_cli-1.0.404/docs/roadmap/items/dry-run-promised-a-link-nobody-makes.md +43 -0
- boost_skill_cli-1.0.404/docs/roadmap/items/heal-deleted-links-it-never-made.md +54 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap.html +92 -1
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_pkg.py +37 -4
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_quality.py +39 -0
- boost_skill_cli-1.0.404/tests/unit/test_link_ownership.py +108 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.gitattributes +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.gitignore +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.gitleaks.toml +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.htmlvalidate.json +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.lighthouserc.json +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.lycheeignore +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.markdownlint-cli2.jsonc +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.pre-commit-config.yaml +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.stylelintrc.json +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.vale/styles/boost/Terminology.yml +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.vale/styles/config/vocabularies/boost/accept.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/.vale.ini +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/CLAUDE.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/CODE_OF_CONDUCT.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/CONTRIBUTING.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/LICENSE +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/MANIFEST.in +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/Makefile +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/README.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/SECURITY.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/__init__.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/__main__.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/cli.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/cliparse.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/__init__.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/_common.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/bmad.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/configuration.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/discovery.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/hooks.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/info.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/intelligence.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/run.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/safety.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/taps.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/commands/team.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/__init__.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/adapters.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/agents.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/ai.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/capabilities.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/catalog.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/chat.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/claude_settings.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/complete.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/config.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/dense.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/ed25519.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/embed.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/faithfulness.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/frontmatter.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/gitutil.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/imperative.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/injectscan.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/installscan.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/integrity.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/journal.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/localembed.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/lockfile.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/logs.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/mcp.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/mcpdecl.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/mcphost.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/minisign.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/nethttp.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/output.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/paths.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/policy.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/projectlock.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/provenance.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/rag.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/registry.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/resolve.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/rules.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/scopes.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/secretscan.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/selfupdate.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/serve.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/stackprobe.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/staleness.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/store.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/trustaudit.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/typosquat.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/updatediff.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/util.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/core/workflows.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/data/registries.json +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/errors.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_cli/spin.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_skill_cli.egg-info/entry_points.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_skill_cli.egg-info/requires.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/boost_skill_cli.egg-info/top_level.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/codecov.yml +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/.claude/settings.local.json +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/DEBUGGING.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/adapters.html +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/architecture/README.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/architecture/c4-components-core.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/architecture/c4-containers.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/architecture/c4-context.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/architecture/c4-dynamic-install.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/gifs/distill.gif +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/gifs/doctor.gif +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/gifs/explain.gif +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/gifs/hooks.gif +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/gifs/install.gif +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/gifs/pulse.gif +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/gifs/search.gif +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/gifs/tap.gif +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/tapes/distill.tape +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/tapes/doctor.tape +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/tapes/explain.tape +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/tapes/hooks.tape +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/tapes/install.tape +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/tapes/pulse.tape +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/tapes/search.tape +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel/tapes/tap.tape +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/carousel.html +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/chat.html +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/commands.html +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/demo-index.json +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/demo.gif +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/demo.html +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/demo.tape +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/design-roadmap.html +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/eval-latest.json +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/eval.html +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/index.html +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/mcp-hub.html +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/rag-architecture.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D01.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D02.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D03.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D04.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D05.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D06.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D07.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D08.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D09.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D10.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D11.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D12.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D13.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D14.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D15.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D16.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D17.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D18.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D19.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D20.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D21.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D22.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D23.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D24.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D25.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/BOOST-D26.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/a11y-sweep-flakes-on-color-contrast.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/actionlint-skips-shellcheck-silently.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/adapter-conformance-langgraph-leg-never-ran.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/agents-field-records-the-request-not-the-links.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/ai-bridge-silent-failure-logging.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/ambiguous-tap-short-name-resolution.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/bm25-index-is-one-json-blob.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/boost-run-live-agents.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/chat-cites-sources-by-a-number-it-never-prints.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/chat-command-grounded-conversational-search.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/ci-job-timeout-minutes.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/ci-summary-step-fails-itself.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/ci-time-is-now-runner-queueing.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/code-scanning-rule-can-be-restored.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/codeql-job-rename-stranded-merge-protection.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/command-carousel-page.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/command-reference-docs-site.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/completions-complete-only-command-names.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/crash-listing-branch-untested.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/demo-cannot-open-its-own-pr.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/demo-gif-workflow-has-never-succeeded.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/dense-search-fallback-and-stale-tap-pruning.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/dependabot-missing-pip-ecosystem.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/dependabot-regeneration-drops-platform-pins.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/dependabot-root-pip-entry-duplicates-requirements.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/docsite-chrome-and-content-audit.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/eval-corpus-cannot-see-real-retrieval.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/eval-corpus-is-96x-smaller-than-a-real-install.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/eval-corpus-is-one-strangers-repo.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/eval-corpus-pins-have-no-refresh-path.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/eval-corpus-was-not-actually-pinned.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/eval-deduped-ranked-lists-by-name.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/framework-adapter-multi-agent.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/gemini-cli-agent-target.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/github-community-health-files.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/golden-set-grades-by-name-not-by-skill.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/html-validation-html-validate.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/info-rejects-the-qualified-name-it-recommends.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/install-docs-never-mentioned-upgrading.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/install-from-path-bypasses-policy-and-pin-checks.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/install-resolves-skill-dependencies.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/install-scope-user-or-project.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/installed-skill-trust-audit.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/internal-architecture-diagrams.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/journal-rotation-race-and-handle-leak.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/keyless-dense-tier-local-static-embeddings.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/keyless-semantic-search-for-everyone.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/langchain-integration-explainer-page.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/langchain-langgraph-langsmith-integration.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/license-compliance-scanning.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/lighthouse-scored-a-page-nobody-is-served.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/lint-tap-misscopes-rule-workflow-entries.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/lock-invariant-cannot-parse-extras-pins.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/main-has-no-branch-protection.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/main-ruleset-ref-pattern-has-literal-quotes.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/make-lint-masks-actionlint-failures.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/markdownlint-lints-the-fuzz-corpus.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-aware-skills.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-check-skills-before-starting-a-task.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-install-skips-the-injection-scan.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-one-benefit-nameable-task.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-search-before-reinventing.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-search-cost-was-understated.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-servers-ignore-install-scope.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/merge-queue-would-deadlock-most-required-checks.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/merged-loop-branches-are-never-pruned.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mutation-gate-was-the-whole-critical-path.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mutation-shard-floor-is-one-file.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/mypy-strict-mode-for-commands.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/near-duplicate-items-eat-the-result-slots.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/negative-limit-inverts-log-pulse-output.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/onboard-overwrites-generated-files-without-confirm.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/one-commit-can-cut-two-releases.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/one-dead-tap-broke-every-update.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/path-traversal-unsanitized-rule-workflow-name.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/pep585-604-modernization-sweep.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/pin-the-lint-toolchain.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/post-deploy-always-defeated-by-skipped-setup.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/prerequisites-and-semantic-search-setup.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/project-scope-across-every-command.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/project-scope-symlink-escape-on-write.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/publish-gate-ignores-pip-audit-and-metadata.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/publish-trigger-was-reachable-from-a-fork.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/pytest-tmpdir-cve-blocked-by-py39-floor.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/python-floor-moves-to-312.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/rel-time-tests-race-the-wall-clock.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/release-verifies-the-wrong-commit.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/required-checks-can-declare-a-check-that-deadlocks-prs.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/required-checks-config-drift.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/resolve-vendored-duplicate-copies.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/roadmap-html-goes-stale-on-every-rebase.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/roadmap-page-weight-grows-without-bound.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/roadmap-perf-budget-has-no-local-guard.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/ruff-016-widens-the-default-rule-set.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/rules-install-but-cannot-be-governed.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/sbom-declares-the-wrong-version.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/sbom-release-event-never-fires.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/scheduled-toolchain-lock-regeneration.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/scorecard-findings-triage.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/search-never-notices-a-new-tap.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/self-update-broken-for-pip-pipx-installs.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/serve-py-traversal-guards-untested.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/structured-json-log-output-mode.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/sync-deletes-unowned-broken-symlinks.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/sync-relinks-into-every-agent-ignoring-scope.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/typo-detection-codespell.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/uninstall-has-no-confirmation-prompt.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/update-advertises-a-flag-it-rejects.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/update-diff-before-apply.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/update-refreshed-rules-without-a-gate.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/update-reinstall-widens-agent-scope.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/wire-bdd-suite-into-ci.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/workspace-scope-install.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/zip-strict-audit.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/docs/roadmap/items/zizmor-pin-is-a-yanked-release.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/eslint.config.mjs +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/README.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/__init__.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/baseline.json +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/faithfulness.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/golden_set.json +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/make_corpus.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/make_golden.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/metrics.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/evals/run_evals.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/examples/README.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/examples/adapt-demo.sh +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/examples/boost-run-prototype.sh +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/index.html +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/noxfile.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/pyproject.toml +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/coverage-tools.in +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/coverage-tools.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/lint-tools.in +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/lint-tools.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/mutation-tools.in +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/mutation-tools.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/platform-pins.lock +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/release-tools.in +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/release-tools.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/test-tools.in +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/requirements/test-tools.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/a11y_check.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/bench_cli.sh +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/build_command_reference.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/build_demo_index.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/build_registries.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/build_roadmap.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/build_scale_corpus.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/check_anchors.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/check_licenses.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/check_required_checks.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/ensure_eval_corpus.sh +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/eval_corpus.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/eval_explain.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/eval_gate.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/eval_recommend.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/eval_retrieval.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/eval_stats_summary.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/import_budget.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/lock_toolchain.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/mutation_gate.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/mutation_shards.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/mutation_weights.json +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/page_budget.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/perf_gate.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/post_deploy_smoke.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/publish_eval_json.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/release_guard.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/release_preflight.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/scripts/serve_docs.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/setup.cfg +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/sonar-project.properties +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/style/README.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/style/boost.css +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/style/boost.js +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/style/demo.html +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/adapt.feature +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/browse.feature +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/count.feature +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/discover.feature +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/doctor.feature +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/environment.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/explain.feature +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/index.feature +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/install.feature +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/list.feature +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/mcp.feature +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/search.feature +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/steps/cli_steps.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/steps/discovery_steps.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/steps/mcp_steps.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/bdd/features/steps/quality_steps.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/conftest.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/eval/baseline.json +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/eval/explain.jsonl +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/eval/golden-natural.jsonl +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/eval/golden.jsonl +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/eval/recommend.jsonl +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/eval/taps-scale.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/eval/taps.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_capabilities_policy.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_adapt.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_bmad.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_chat.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_configuration.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_discovery.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_hooks.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_info.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_intelligence.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_taps.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_cli_team.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_everyday_loop.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_integrity_enforce.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_property_parsers.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_run.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_tap_signing.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/functional/test_workspace_scope.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/README.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/01-typical.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/02-lossy-version.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/03-lossy-numbers.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/04-lists.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/05-nested.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/06-empty-block.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/07-unterminated.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/08-none.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/09-unbalanced-quote.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/10-keywords.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/11-crlf.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/frontmatter/12-bom.md +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/registry/01-shorthand.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/registry/02-https.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/registry/03-ssh.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/registry/04-traversal.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/registry/05-empty.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/registry/06-space.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/registry/07-slash.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/corpus/registry/08-bare-host.txt +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/fuzz_frontmatter.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/fuzz/fuzz_registry.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/make_fixture.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/perf/test_benchmarks.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/smoke.sh +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_a11y_check.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_adapters.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_adapters_multi.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_adapters_runner.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_agents.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_ai.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_capabilities.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_catalog.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_chat.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_check_anchors.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_check_licenses.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_claude_settings.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_cliparse.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_codeql_analysis_key.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_command_reference_fresh.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_community_health_files.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_complete.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_config.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_content_dedupe.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_dedup_trust.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_demo_index.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_dense.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_dense_fallback.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_dense_fix_hint.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_dense_shards.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_dense_status.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_dependabot_config.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_docs_pages_linked.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_docsite_chrome.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_ed25519.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_embed.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_embed_local.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_entry_key.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_errors_and_cli_table.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_eval_baseline.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_eval_corpus.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_eval_faithfulness.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_eval_gate.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_eval_grading.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_eval_metrics.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_eval_stats_summary.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_faithfulness.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_frontmatter.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_fuzz_targets.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_gitleaks_config.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_gitutil.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_imperative.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_import_budget.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_injectscan.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_installscan.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_integrity.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_journal.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_localembed.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_localembed_e2e.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_lockfile.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_logs.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_marketing_counts.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_mcp.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_mcp_install_scan.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_mcpdecl.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_mcphost.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_minisign.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_mutation_hardening.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_mutation_shards.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_mutation_subfile_shards.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_mutmut_source_paths.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_nethttp.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_output.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_page_budget.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_paths.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_perf_gate.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_pkg_confusions.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_pkg_injection.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_pkg_secrets.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_platform_pins.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_policy.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_post_deploy_smoke.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_project_mcp_sidecar.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_projectlock.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_provenance.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_rag.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_rag_fusion.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_registries_fresh.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_registry.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_registry_categories.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_release_guard.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_release_preflight.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_required_checks.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_resolve.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_roadmap_fresh.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_rules.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_scale_corpus.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_scopes.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_secretscan.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_selfupdate.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_serve.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_serve_docs.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_spin.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_stackprobe.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_staleness.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_store.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_token_parity.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_toolchain_lock.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_trustaudit.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_typosquat.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_updatediff.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_util.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_version.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_workflow_concurrency.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_workflow_timeouts.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/unit/test_workflows.py +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/visual/a11y_check.mjs +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/visual/console_check.mjs +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/visual/package-lock.json +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/tests/visual/package.json +0 -0
- {boost_skill_cli-1.0.402 → boost_skill_cli-1.0.404}/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.404'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 0, 404)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -388,7 +388,18 @@ def cmd_install(argv: List[str]) -> int:
|
|
|
388
388
|
multi = multi or len(entries) > 1
|
|
389
389
|
|
|
390
390
|
if args.dry_run:
|
|
391
|
+
# TWO lists, because the three kinds do not reach the same agents.
|
|
392
|
+
# Rules and workflows materialize into every enabled agent's dotdir,
|
|
393
|
+
# Gemini included. A skill is symlinked only into the agents that take
|
|
394
|
+
# links — Gemini reads the canonical store directly and is deliberately
|
|
395
|
+
# never linked (see agents.linking_agents). One list for both is how
|
|
396
|
+
# `--dry-run` came to promise a `~/.gemini/skills` symlink that the real
|
|
397
|
+
# install has never created.
|
|
391
398
|
targets = [a for a in agents.enabled_agents() if not only or a in only]
|
|
399
|
+
link_targets = [a for a in agents.linking_agents()
|
|
400
|
+
if not only or a in only]
|
|
401
|
+
native_targets = [a for a in agents.native_store_agents()
|
|
402
|
+
if not only or a in only]
|
|
392
403
|
pbase = scopes.resolve_base(args.scope)
|
|
393
404
|
if args.scope == scopes.SCOPE_PROJECT and pbase is None:
|
|
394
405
|
raise BoostError(
|
|
@@ -423,7 +434,14 @@ def cmd_install(argv: List[str]) -> int:
|
|
|
423
434
|
e["version"], e["tap"]))
|
|
424
435
|
out.info(" copy %s → %s" % (_tilde(store.source_dir_for(e)),
|
|
425
436
|
_tilde(store.skill_store_dir(e["name"]))))
|
|
426
|
-
out.info(" link → %s" % (" · ".join(
|
|
437
|
+
out.info(" link → %s" % (" · ".join(link_targets)
|
|
438
|
+
or "(no linking agents)"))
|
|
439
|
+
# Mirrors what the real install reports, so a Gemini-only install
|
|
440
|
+
# does not read as reaching no agent at all.
|
|
441
|
+
if native_targets:
|
|
442
|
+
out.info(" available to %s (reads the store directly)"
|
|
443
|
+
% " · ".join(agents.display_name(a)
|
|
444
|
+
for a in native_targets))
|
|
427
445
|
out.info("dry run — nothing was changed")
|
|
428
446
|
return 1 if failed else 0
|
|
429
447
|
|
|
@@ -76,17 +76,120 @@ _STACK_MARKERS = [
|
|
|
76
76
|
_tilde = paths.tilde
|
|
77
77
|
|
|
78
78
|
|
|
79
|
-
def
|
|
80
|
-
"""
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
def _resolve_as_far_as_it_exists(path: Path) -> Path:
|
|
80
|
+
"""Absolute ``path``, symlinks resolved down to its deepest real ancestor.
|
|
81
|
+
|
|
82
|
+
Plain ``resolve()`` is wrong on both sides of this comparison. The link's
|
|
83
|
+
target does not exist — that is what makes the link broken — and the store
|
|
84
|
+
dir does, so resolving only the one that can be resolved compares a real
|
|
85
|
+
path against a nominal one. On macOS that is not hypothetical: ``/tmp`` is
|
|
86
|
+
itself a symlink to ``/private/tmp``, so a genuine boost link read as
|
|
87
|
+
foreign and `heal` declined to repair anything.
|
|
88
|
+
"""
|
|
89
|
+
path = Path(os.path.abspath(str(path)))
|
|
90
|
+
tail: List[str] = []
|
|
91
|
+
cur = path
|
|
92
|
+
while cur != cur.parent and not cur.exists():
|
|
93
|
+
tail.append(cur.name)
|
|
94
|
+
cur = cur.parent
|
|
95
|
+
with suppress(OSError):
|
|
96
|
+
cur = cur.resolve()
|
|
97
|
+
return cur.joinpath(*reversed(tail))
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _norm(path: Path) -> str:
|
|
101
|
+
"""``path`` as a comparable string, without resolving anything.
|
|
102
|
+
|
|
103
|
+
Strips Windows' extended-length prefix — ``os.readlink`` returns
|
|
104
|
+
``\\\\?\\C:\\...`` for a link the store created while ``store_dir()`` is
|
|
105
|
+
spelled the ordinary way, so the two name one location with two strings —
|
|
106
|
+
and applies `os.path.normcase`, which folds case on Windows (where the
|
|
107
|
+
filesystem is case-insensitive) and is a no-op on POSIX.
|
|
108
|
+
"""
|
|
109
|
+
# Strip BEFORE abspath: on a POSIX host a backslash path is not absolute,
|
|
110
|
+
# so abspath would prepend the cwd and move the prefix out of position —
|
|
111
|
+
# which matters because this must be testable off Windows.
|
|
112
|
+
text = str(path)
|
|
113
|
+
for prefix in ("\\\\?\\UNC\\", "\\\\?\\"):
|
|
114
|
+
if text.startswith(prefix):
|
|
115
|
+
text = text[len(prefix):]
|
|
116
|
+
break
|
|
117
|
+
return os.path.normcase(os.path.abspath(text))
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _within(target: str, parent: str) -> bool:
|
|
121
|
+
"""True if normalised ``target`` is ``parent`` or sits under it."""
|
|
122
|
+
return target == parent or target.startswith(parent.rstrip(os.sep) + os.sep)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _link_key(path: Path) -> str:
|
|
126
|
+
"""``path`` resolved, then normalised into a comparable string.
|
|
127
|
+
|
|
128
|
+
Comparing `Path` objects directly is wrong on Windows, in two ways that
|
|
129
|
+
both read as "boost does not own its own link" and left `heal` refusing to
|
|
130
|
+
repair anything at all there:
|
|
131
|
+
|
|
132
|
+
* ``os.readlink`` returns the extended-length form (``\\\\?\\C:\\...``) for
|
|
133
|
+
a link the store created, while ``store_dir()`` is spelled the ordinary
|
|
134
|
+
way — same location, different string.
|
|
135
|
+
* The filesystem is case-insensitive, so ``C:\\Users`` and ``c:\\users``
|
|
136
|
+
are one directory and two unequal `Path`s.
|
|
137
|
+
|
|
138
|
+
`os.path.normcase` is a no-op on POSIX, so this stays exact where case is.
|
|
139
|
+
"""
|
|
140
|
+
return _norm(_resolve_as_far_as_it_exists(path))
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _owned_link(link: Path) -> bool:
|
|
144
|
+
"""True if ``link`` points into boost's canonical store.
|
|
145
|
+
|
|
146
|
+
Ownership is read off the link itself rather than the lock, so it still
|
|
147
|
+
answers correctly for a skill uninstalled mid-sweep or a lock that has gone
|
|
148
|
+
missing — the two cases where a dangling link is most likely to exist.
|
|
149
|
+
"""
|
|
150
|
+
try:
|
|
151
|
+
raw = Path(os.readlink(str(link)))
|
|
152
|
+
except OSError:
|
|
153
|
+
return False
|
|
154
|
+
target = raw if raw.is_absolute() else link.parent / raw
|
|
155
|
+
store = paths.store_dir()
|
|
156
|
+
# Spelled form first. A link boost made carries the store's own path, so
|
|
157
|
+
# this settles the ordinary case without resolving anything — and every
|
|
158
|
+
# platform quirk lives in resolution. Windows alone supplies three: the
|
|
159
|
+
# extended-length prefix, 8.3 short names, and case-insensitivity.
|
|
160
|
+
if _within(_norm(target), _norm(store)):
|
|
161
|
+
return True
|
|
162
|
+
# Resolved form second, for a store genuinely reached through a symlinked
|
|
163
|
+
# parent — macOS `/tmp` -> `/private/tmp` is the case that made this
|
|
164
|
+
# necessary rather than theoretical.
|
|
165
|
+
return _within(_link_key(target), _link_key(store))
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _broken_links() -> Tuple[List[Path], List[Path]]:
|
|
169
|
+
"""``(ours, theirs)`` — dangling symlinks in the dirs boost links into.
|
|
170
|
+
|
|
171
|
+
Two things this deliberately does NOT do.
|
|
172
|
+
|
|
173
|
+
**It does not look in a native-store agent's dir.** `linking_agents`, not
|
|
174
|
+
`enabled_agents`: boost never links into `~/.gemini/skills`, so anything
|
|
175
|
+
dangling there belongs to someone else and is none of this command's
|
|
176
|
+
business. The rest of `cmd_heal` already had this right.
|
|
177
|
+
|
|
178
|
+
**It does not report a link boost did not create as ours.** `heal` deletes
|
|
179
|
+
what this returns first, and a broken link is not necessarily garbage — a
|
|
180
|
+
skill on an unmounted volume dangles until the volume comes back. Removing
|
|
181
|
+
a link the user made themselves is not a repair, it is data loss with a
|
|
182
|
+
reassuring name, so those are reported and left alone.
|
|
183
|
+
"""
|
|
184
|
+
ours: List[Path] = []
|
|
185
|
+
theirs: List[Path] = []
|
|
186
|
+
for adir in agents.linking_agents().values():
|
|
83
187
|
if not adir.is_dir():
|
|
84
188
|
continue
|
|
85
|
-
|
|
86
|
-
link
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return broken
|
|
189
|
+
for link in sorted(adir.iterdir()):
|
|
190
|
+
if link.is_symlink() and not link.exists():
|
|
191
|
+
(ours if _owned_link(link) else theirs).append(link)
|
|
192
|
+
return ours, theirs
|
|
90
193
|
|
|
91
194
|
|
|
92
195
|
def _read_skill(skill_dir: Path) -> Tuple[dict, str]:
|
|
@@ -365,10 +468,18 @@ def cmd_doctor(argv):
|
|
|
365
468
|
bad("%d orphaned store dir%s (%s) — run `boost sync`"
|
|
366
469
|
% (len(orphans), _s(len(orphans)), ", ".join(orphans[:5])))
|
|
367
470
|
|
|
368
|
-
broken = _broken_links()
|
|
471
|
+
broken, foreign = _broken_links()
|
|
369
472
|
if broken:
|
|
370
473
|
bad("%d broken symlink%s in agent dirs — run `boost heal`"
|
|
371
474
|
% (len(broken), _s(len(broken))))
|
|
475
|
+
if foreign:
|
|
476
|
+
# `out.info`, not `bad`: this does not raise the issue count, because
|
|
477
|
+
# boost will not fix it and `heal` deliberately leaves it — counting it
|
|
478
|
+
# would leave doctor permanently red on something no boost command can
|
|
479
|
+
# clear, which is how a health check stops being read.
|
|
480
|
+
out.info("%d broken symlink%s in agent dirs not created by boost — "
|
|
481
|
+
"left alone; yours to remove or repair"
|
|
482
|
+
% (len(foreign), _s(len(foreign))))
|
|
372
483
|
|
|
373
484
|
for adir in enabled.values():
|
|
374
485
|
if adir.is_dir() and not os.access(str(adir), os.W_OK):
|
|
@@ -691,13 +802,19 @@ def cmd_heal(argv):
|
|
|
691
802
|
% (len(missing), "y" if len(missing) == 1 else "ies"))
|
|
692
803
|
actions.append("mkdir %d" % len(missing))
|
|
693
804
|
|
|
694
|
-
|
|
805
|
+
ours, theirs = _broken_links()
|
|
806
|
+
for link in ours:
|
|
695
807
|
if dry:
|
|
696
808
|
out.info("would remove broken link %s" % _tilde(link))
|
|
697
809
|
else:
|
|
698
810
|
link.unlink()
|
|
699
811
|
out.ok("removed broken link %s" % _tilde(link))
|
|
700
812
|
actions.append("unlink %s" % link.name)
|
|
813
|
+
for link in theirs:
|
|
814
|
+
# Named, never touched: it is in a directory boost writes to, so the
|
|
815
|
+
# user should know it is dangling — but boost did not put it there.
|
|
816
|
+
out.warn("broken link %s does not point into %s — left alone"
|
|
817
|
+
% (_tilde(link), _tilde(paths.store_dir())))
|
|
701
818
|
|
|
702
819
|
plan = store.sync_plan()
|
|
703
820
|
if dry:
|
|
@@ -920,8 +1037,9 @@ def cmd_health(argv):
|
|
|
920
1037
|
decay_n = sum(1 for r in _decay_rows(Path.cwd()) if r["verdict"] == "decay")
|
|
921
1038
|
out.kv("decay", "%d candidate%s" % (decay_n, _s(decay_n)))
|
|
922
1039
|
|
|
923
|
-
broken = _broken_links()
|
|
924
|
-
out.kv("broken links",
|
|
1040
|
+
broken, foreign = _broken_links()
|
|
1041
|
+
out.kv("broken links", "%d%s" % (
|
|
1042
|
+
len(broken), " (+%d not ours)" % len(foreign) if foreign else ""))
|
|
925
1043
|
|
|
926
1044
|
last_sync = "never"
|
|
927
1045
|
if cloned and gitutil.has_git():
|
|
@@ -213,6 +213,7 @@ docs/roadmap/items/dependency-cve-gate-pip-audit.md
|
|
|
213
213
|
docs/roadmap/items/docsite-chrome-and-content-audit.md
|
|
214
214
|
docs/roadmap/items/docstring-coverage-interrogate.md
|
|
215
215
|
docs/roadmap/items/doctor-checks-rules-and-workflows.md
|
|
216
|
+
docs/roadmap/items/dry-run-promised-a-link-nobody-makes.md
|
|
216
217
|
docs/roadmap/items/end-of-options-guard-on-git-commands.md
|
|
217
218
|
docs/roadmap/items/eval-corpus-cannot-see-real-retrieval.md
|
|
218
219
|
docs/roadmap/items/eval-corpus-is-96x-smaller-than-a-real-install.md
|
|
@@ -235,6 +236,7 @@ docs/roadmap/items/github-pages-deploy-is-broken-every-push.md
|
|
|
235
236
|
docs/roadmap/items/golden-set-grades-by-name-not-by-skill.md
|
|
236
237
|
docs/roadmap/items/golden-set-statistical-power.md
|
|
237
238
|
docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md
|
|
239
|
+
docs/roadmap/items/heal-deleted-links-it-never-made.md
|
|
238
240
|
docs/roadmap/items/html-validation-html-validate.md
|
|
239
241
|
docs/roadmap/items/info-rejects-the-qualified-name-it-recommends.md
|
|
240
242
|
docs/roadmap/items/install-docs-never-mentioned-upgrading.md
|
|
@@ -560,6 +562,7 @@ tests/unit/test_injectscan.py
|
|
|
560
562
|
tests/unit/test_installscan.py
|
|
561
563
|
tests/unit/test_integrity.py
|
|
562
564
|
tests/unit/test_journal.py
|
|
565
|
+
tests/unit/test_link_ownership.py
|
|
563
566
|
tests/unit/test_localembed.py
|
|
564
567
|
tests/unit/test_localembed_e2e.py
|
|
565
568
|
tests/unit/test_lockfile.py
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: dry-run-promised-a-link-nobody-makes
|
|
3
|
+
board: code
|
|
4
|
+
section: internals
|
|
5
|
+
status: shipped
|
|
6
|
+
category: Correctness
|
|
7
|
+
complexity: S
|
|
8
|
+
impact: Medium
|
|
9
|
+
wow: 3
|
|
10
|
+
note: the bug was written down in a test comment and pinned as "behaves today"
|
|
11
|
+
order: 100
|
|
12
|
+
owner: fix/dry-run-matches-the-real-install
|
|
13
|
+
pr: 460
|
|
14
|
+
title: install --dry-run predicted an install that never happens
|
|
15
|
+
---
|
|
16
|
+
<b>A preview has exactly one job, and this one got it wrong by an agent and a verb.</b>
|
|
17
|
+
<code>boost install brainstorming --dry-run</code> reported
|
|
18
|
+
<code>link → claude-code · windsurf · cursor · gemini</code>.
|
|
19
|
+
The real install reports three agents, plus a separate line saying Gemini reads the store directly
|
|
20
|
+
— and <code>~/.gemini/skills</code> does not exist afterwards, because boost has never created
|
|
21
|
+
it.
|
|
22
|
+
|
|
23
|
+
<b>One list was doing two jobs.</b> The dry-run block computed a single set of targets from
|
|
24
|
+
<code>agents.enabled_agents()</code> and printed it for both the skill <code>link</code> line and the
|
|
25
|
+
rule/workflow <code>materialize</code> line. For rules and workflows that is right: they really are
|
|
26
|
+
materialised into every enabled agent's dotdir, Gemini included. For a <i>skill</i> it is wrong,
|
|
27
|
+
because Gemini implements the Agent Skills standard and discovers the canonical store itself, so it
|
|
28
|
+
is configured <code>links_skills: false</code> and is deliberately never symlinked. CLAUDE.md is
|
|
29
|
+
explicit — iterate <code>linking_agents()</code> for anything symlink-shaped.
|
|
30
|
+
|
|
31
|
+
<b>The bug was already written down.</b> The functional test carried a comment saying so:
|
|
32
|
+
"<i>the preview lists every enabled agent, so it still promises a gemini link the real install does
|
|
33
|
+
not make … Pinned as it behaves today.</i>" Someone found it, understood it, described it
|
|
34
|
+
accurately, and pinned the wrong behaviour rather than fixing it — which is how a known defect
|
|
35
|
+
acquires a test that defends it.
|
|
36
|
+
|
|
37
|
+
<b>Fixed as a distinction, not a deletion.</b> A skill's preview names the agents that take links and
|
|
38
|
+
adds the same "available to Gemini CLI (reads the store directly)" line the real install prints; a
|
|
39
|
+
rule's preview still names all four, because a rule genuinely reaches all four. A test now compares
|
|
40
|
+
the two runs field by field — the preview's link list against the real install's —
|
|
41
|
+
because <code>"a · b · c"</code> contains
|
|
42
|
+
<code>"a · b"</code>, so a substring assertion passes on exactly this bug. It was
|
|
43
|
+
written as a substring first and caught nothing until it was tightened.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: heal-deleted-links-it-never-made
|
|
3
|
+
board: code
|
|
4
|
+
section: internals
|
|
5
|
+
status: shipped
|
|
6
|
+
category: Safety · Correctness
|
|
7
|
+
complexity: S
|
|
8
|
+
impact: Medium
|
|
9
|
+
wow: 4
|
|
10
|
+
note: a dangling link is not garbage — an unmounted volume comes back, and heal deleted it anyway
|
|
11
|
+
order: 99
|
|
12
|
+
owner: fix/heal-only-removes-links-it-owns
|
|
13
|
+
pr: 459
|
|
14
|
+
title: heal removed symlinks boost never created
|
|
15
|
+
---
|
|
16
|
+
<b><code>boost heal</code> deleted a symlink boost did not make, does not track, and has no claim
|
|
17
|
+
to.</b> Reproduced against a sandbox: plant
|
|
18
|
+
<code>~/.claude/skills/my-own-skill → ~/elsewhere/my-own-skill</code>, run
|
|
19
|
+
<code>boost heal</code>, and it reports <i>"removed broken link ~/.claude/skills/my-own-skill"</i>.
|
|
20
|
+
Same scenario on the fixed build leaves it exactly where it was.
|
|
21
|
+
|
|
22
|
+
<b>A broken link is not the same as garbage.</b> <code>~/.claude/skills/</code> is the user's own
|
|
23
|
+
directory that boost happens to link into. A dangling entry there can be a skill on an unmounted
|
|
24
|
+
volume, a repo checked out somewhere else for the afternoon, or a link into a detached drive
|
|
25
|
+
— all of which come back. Removing one is not a repair; it is data loss under a reassuring
|
|
26
|
+
name, from a command whose entire promise is that it is safe to run.
|
|
27
|
+
|
|
28
|
+
<b>Ownership is legible from the link itself.</b> Every link boost creates points into the canonical
|
|
29
|
+
store, <code>~/.agents/skills/<name></code>. Reading the target beats consulting the lock,
|
|
30
|
+
because the two moments a dangling link is most likely to exist — a skill uninstalled
|
|
31
|
+
mid-sweep, a lock file that has gone missing — are exactly the moments the lock cannot answer.
|
|
32
|
+
Links into the store are swept; everything else is <i>named</i> and left alone, because the user
|
|
33
|
+
should still know it is dangling.
|
|
34
|
+
|
|
35
|
+
<b>The scan was also looking somewhere it has no business.</b> <code>_broken_links</code> iterated
|
|
36
|
+
<code>agents.enabled_agents()</code>, which includes Gemini — and boost never links into
|
|
37
|
+
<code>~/.gemini/skills</code> at all, because Gemini CLI reads the canonical store directly.
|
|
38
|
+
CLAUDE.md states the rule outright: iterate <code>linking_agents()</code> "for anything
|
|
39
|
+
symlink-shaped (link, unlink, stale-link sweeps, coverage counts)". The <i>same function</i> already
|
|
40
|
+
had it right eleven lines further down, where <code>cmd_heal</code> builds its list of missing
|
|
41
|
+
directories and comments on precisely this distinction.
|
|
42
|
+
|
|
43
|
+
<b>A macOS-only trap sat inside the fix.</b> The first attempt compared
|
|
44
|
+
<code>store_dir().resolve()</code> against a normalised link target — resolving the side that
|
|
45
|
+
exists and not the side that does not. On macOS <code>/tmp</code> is itself a symlink to
|
|
46
|
+
<code>/private/tmp</code>, so a genuine boost link read as foreign and <code>heal</code> declined to
|
|
47
|
+
repair anything at all. Both sides are now resolved down to their deepest real ancestor, which is
|
|
48
|
+
the only comparison that is correct when one path is dangling by definition.
|
|
49
|
+
|
|
50
|
+
<b><code>doctor</code> reports it without going red.</b> A foreign broken link is printed as
|
|
51
|
+
information, not counted as an issue: <code>heal</code> deliberately will not fix it, so counting it
|
|
52
|
+
would leave <code>doctor</code> permanently red on something no boost command can clear —
|
|
53
|
+
which is how a health check stops being read. Two tests pin the behaviour and both fail with the
|
|
54
|
+
ownership check reverted.
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
<div class="stat"><b>16</b><span>Shipped</span></div>
|
|
126
126
|
<div class="stat"><b>1</b><span>Next up</span></div>
|
|
127
127
|
<div class="stat"><b>8</b><span>Planned</span></div>
|
|
128
|
-
<div class="stat"><b>
|
|
128
|
+
<div class="stat"><b>217</b><span>Loop finds</span></div>
|
|
129
129
|
<!-- /ROADMAP:stats -->
|
|
130
130
|
</div>
|
|
131
131
|
</section>
|
|
@@ -3470,6 +3470,97 @@ brake anyone can see, not a policy anyone can set.</p></details>
|
|
|
3470
3470
|
<span class="m">install scanned rule content; update did not — and the scanner could not see concealment anyway</span>
|
|
3471
3471
|
</div>
|
|
3472
3472
|
</article>
|
|
3473
|
+
|
|
3474
|
+
<article class="cap rcard" id="heal-deleted-links-it-never-made">
|
|
3475
|
+
<div class="head"><span class="pill shipped">Shipped</span><span class="cat">Safety · Correctness</span></div>
|
|
3476
|
+
<h3>heal removed symlinks boost never created</h3>
|
|
3477
|
+
<details class="cardbody"><summary>Write-up</summary>
|
|
3478
|
+
<p><b><code>boost heal</code> deleted a symlink boost did not make, does not track, and has no claim
|
|
3479
|
+
to.</b> Reproduced against a sandbox: plant
|
|
3480
|
+
<code>~/.claude/skills/my-own-skill → ~/elsewhere/my-own-skill</code>, run
|
|
3481
|
+
<code>boost heal</code>, and it reports <i>"removed broken link ~/.claude/skills/my-own-skill"</i>.
|
|
3482
|
+
Same scenario on the fixed build leaves it exactly where it was.
|
|
3483
|
+
|
|
3484
|
+
<b>A broken link is not the same as garbage.</b> <code>~/.claude/skills/</code> is the user's own
|
|
3485
|
+
directory that boost happens to link into. A dangling entry there can be a skill on an unmounted
|
|
3486
|
+
volume, a repo checked out somewhere else for the afternoon, or a link into a detached drive
|
|
3487
|
+
— all of which come back. Removing one is not a repair; it is data loss under a reassuring
|
|
3488
|
+
name, from a command whose entire promise is that it is safe to run.
|
|
3489
|
+
|
|
3490
|
+
<b>Ownership is legible from the link itself.</b> Every link boost creates points into the canonical
|
|
3491
|
+
store, <code>~/.agents/skills/<name></code>. Reading the target beats consulting the lock,
|
|
3492
|
+
because the two moments a dangling link is most likely to exist — a skill uninstalled
|
|
3493
|
+
mid-sweep, a lock file that has gone missing — are exactly the moments the lock cannot answer.
|
|
3494
|
+
Links into the store are swept; everything else is <i>named</i> and left alone, because the user
|
|
3495
|
+
should still know it is dangling.
|
|
3496
|
+
|
|
3497
|
+
<b>The scan was also looking somewhere it has no business.</b> <code>_broken_links</code> iterated
|
|
3498
|
+
<code>agents.enabled_agents()</code>, which includes Gemini — and boost never links into
|
|
3499
|
+
<code>~/.gemini/skills</code> at all, because Gemini CLI reads the canonical store directly.
|
|
3500
|
+
CLAUDE.md states the rule outright: iterate <code>linking_agents()</code> "for anything
|
|
3501
|
+
symlink-shaped (link, unlink, stale-link sweeps, coverage counts)". The <i>same function</i> already
|
|
3502
|
+
had it right eleven lines further down, where <code>cmd_heal</code> builds its list of missing
|
|
3503
|
+
directories and comments on precisely this distinction.
|
|
3504
|
+
|
|
3505
|
+
<b>A macOS-only trap sat inside the fix.</b> The first attempt compared
|
|
3506
|
+
<code>store_dir().resolve()</code> against a normalised link target — resolving the side that
|
|
3507
|
+
exists and not the side that does not. On macOS <code>/tmp</code> is itself a symlink to
|
|
3508
|
+
<code>/private/tmp</code>, so a genuine boost link read as foreign and <code>heal</code> declined to
|
|
3509
|
+
repair anything at all. Both sides are now resolved down to their deepest real ancestor, which is
|
|
3510
|
+
the only comparison that is correct when one path is dangling by definition.
|
|
3511
|
+
|
|
3512
|
+
<b><code>doctor</code> reports it without going red.</b> A foreign broken link is printed as
|
|
3513
|
+
information, not counted as an issue: <code>heal</code> deliberately will not fix it, so counting it
|
|
3514
|
+
would leave <code>doctor</code> permanently red on something no boost command can clear —
|
|
3515
|
+
which is how a health check stops being read. Two tests pin the behaviour and both fail with the
|
|
3516
|
+
ownership check reverted.</p></details>
|
|
3517
|
+
<div class="meta">
|
|
3518
|
+
<span class="m">Complexity <b>S</b></span>
|
|
3519
|
+
<span class="m">Impact <b>Medium</b></span>
|
|
3520
|
+
<span class="m">Wow <b class="wow">★★★★</b></span>
|
|
3521
|
+
<span class="m">a dangling link is not garbage — an unmounted volume comes back, and heal deleted it anyway</span>
|
|
3522
|
+
</div>
|
|
3523
|
+
</article>
|
|
3524
|
+
|
|
3525
|
+
<article class="cap rcard" id="dry-run-promised-a-link-nobody-makes">
|
|
3526
|
+
<div class="head"><span class="pill shipped">Shipped</span><span class="cat">Correctness</span></div>
|
|
3527
|
+
<h3>install --dry-run predicted an install that never happens</h3>
|
|
3528
|
+
<details class="cardbody"><summary>Write-up</summary>
|
|
3529
|
+
<p><b>A preview has exactly one job, and this one got it wrong by an agent and a verb.</b>
|
|
3530
|
+
<code>boost install brainstorming --dry-run</code> reported
|
|
3531
|
+
<code>link → claude-code · windsurf · cursor · gemini</code>.
|
|
3532
|
+
The real install reports three agents, plus a separate line saying Gemini reads the store directly
|
|
3533
|
+
— and <code>~/.gemini/skills</code> does not exist afterwards, because boost has never created
|
|
3534
|
+
it.
|
|
3535
|
+
|
|
3536
|
+
<b>One list was doing two jobs.</b> The dry-run block computed a single set of targets from
|
|
3537
|
+
<code>agents.enabled_agents()</code> and printed it for both the skill <code>link</code> line and the
|
|
3538
|
+
rule/workflow <code>materialize</code> line. For rules and workflows that is right: they really are
|
|
3539
|
+
materialised into every enabled agent's dotdir, Gemini included. For a <i>skill</i> it is wrong,
|
|
3540
|
+
because Gemini implements the Agent Skills standard and discovers the canonical store itself, so it
|
|
3541
|
+
is configured <code>links_skills: false</code> and is deliberately never symlinked. CLAUDE.md is
|
|
3542
|
+
explicit — iterate <code>linking_agents()</code> for anything symlink-shaped.
|
|
3543
|
+
|
|
3544
|
+
<b>The bug was already written down.</b> The functional test carried a comment saying so:
|
|
3545
|
+
"<i>the preview lists every enabled agent, so it still promises a gemini link the real install does
|
|
3546
|
+
not make … Pinned as it behaves today.</i>" Someone found it, understood it, described it
|
|
3547
|
+
accurately, and pinned the wrong behaviour rather than fixing it — which is how a known defect
|
|
3548
|
+
acquires a test that defends it.
|
|
3549
|
+
|
|
3550
|
+
<b>Fixed as a distinction, not a deletion.</b> A skill's preview names the agents that take links and
|
|
3551
|
+
adds the same "available to Gemini CLI (reads the store directly)" line the real install prints; a
|
|
3552
|
+
rule's preview still names all four, because a rule genuinely reaches all four. A test now compares
|
|
3553
|
+
the two runs field by field — the preview's link list against the real install's —
|
|
3554
|
+
because <code>"a · b · c"</code> contains
|
|
3555
|
+
<code>"a · b"</code>, so a substring assertion passes on exactly this bug. It was
|
|
3556
|
+
written as a substring first and caught nothing until it was tightened.</p></details>
|
|
3557
|
+
<div class="meta">
|
|
3558
|
+
<span class="m">Complexity <b>S</b></span>
|
|
3559
|
+
<span class="m">Impact <b>Medium</b></span>
|
|
3560
|
+
<span class="m">Wow <b class="wow">★★★</b></span>
|
|
3561
|
+
<span class="m">the bug was written down in a test comment and pinned as "behaves today"</span>
|
|
3562
|
+
</div>
|
|
3563
|
+
</article>
|
|
3473
3564
|
<!-- /ROADMAP:cards -->
|
|
3474
3565
|
|
|
3475
3566
|
</div>
|
|
@@ -123,14 +123,47 @@ class TestInstall:
|
|
|
123
123
|
r = boost("install", "--dry-run", "brainstorming")
|
|
124
124
|
assert "would install brainstorming v1.4.0 from fixture-tap" in r.out
|
|
125
125
|
assert "~/.boost/repos/fixture-tap/skills/brainstorming" in r.out
|
|
126
|
-
#
|
|
127
|
-
#
|
|
128
|
-
#
|
|
129
|
-
assert "link → claude-code · windsurf · cursor
|
|
126
|
+
# The preview names the agents that actually take a link. Gemini reads
|
|
127
|
+
# the canonical store directly and is never symlinked, so promising one
|
|
128
|
+
# here made the dry run wrong about the one thing it exists to predict.
|
|
129
|
+
assert "link → claude-code · windsurf · cursor" in r.out
|
|
130
|
+
assert "· gemini" not in r.out
|
|
131
|
+
assert "available to Gemini CLI (reads the store directly)" in r.out
|
|
130
132
|
assert "dry run — nothing was changed" in r.out
|
|
131
133
|
assert not (paths.store_dir() / "brainstorming").exists()
|
|
132
134
|
assert not paths.lockfile_path().exists()
|
|
133
135
|
|
|
136
|
+
def test_dry_run_predicts_the_real_install(self, boost, tapped):
|
|
137
|
+
"""The whole job of a preview: say what the real run will do.
|
|
138
|
+
|
|
139
|
+
These two disagreed by one agent and one verb — `--dry-run` promised a
|
|
140
|
+
`~/.gemini/skills` symlink that no install has ever created.
|
|
141
|
+
"""
|
|
142
|
+
def agents_on(text, marker):
|
|
143
|
+
line = next(x for x in text.splitlines() if marker in x)
|
|
144
|
+
return line.split("→", 1)[1].strip()
|
|
145
|
+
|
|
146
|
+
preview = boost("install", "--dry-run", "brainstorming").out
|
|
147
|
+
real = boost("install", "brainstorming").out
|
|
148
|
+
# Compared as whole fields, not substrings: "a · b · c" contains
|
|
149
|
+
# "a · b", so a substring check would have passed on the bug.
|
|
150
|
+
assert agents_on(preview, "link →") == agents_on(real, "linked →")
|
|
151
|
+
for text in (preview, real):
|
|
152
|
+
assert "available to Gemini CLI (reads the store directly)" in text
|
|
153
|
+
assert not (paths.home() / ".gemini" / "skills").exists()
|
|
154
|
+
|
|
155
|
+
def test_dry_run_still_names_gemini_for_a_rule(self, boost, fixture_tap_src,
|
|
156
|
+
tmp_path):
|
|
157
|
+
# The distinction is the point, not a blanket removal: a RULE really is
|
|
158
|
+
# materialized into ~/.gemini/, so the preview must keep saying so.
|
|
159
|
+
tap_dir = _copy_tap(fixture_tap_src, tmp_path / "rule-dry-tap")
|
|
160
|
+
_add_and_commit(tap_dir, "rules/house.mdc",
|
|
161
|
+
"---\nname: house-style\nversion: 1.0.0\n---\n\nUse tabs.\n",
|
|
162
|
+
"add rule")
|
|
163
|
+
boost("tap", tap_dir)
|
|
164
|
+
r = boost("install", "house-style", "--dry-run")
|
|
165
|
+
assert "materialize → claude-code · windsurf · cursor · gemini" in r.out
|
|
166
|
+
|
|
134
167
|
def test_installs_declared_requires_closure(self, boost, tapped):
|
|
135
168
|
# jira-integration declares `requires: [commit-messages]` in the fixture;
|
|
136
169
|
# installing it must pull in the dependency, dependency-first.
|
|
@@ -79,6 +79,17 @@ class TestDoctor:
|
|
|
79
79
|
assert "1 skill installed · 1 tap synced · 1 broken link" in r.out
|
|
80
80
|
assert "need attention" in r.out # verdict flips on issues
|
|
81
81
|
|
|
82
|
+
def test_a_foreign_broken_link_is_reported_but_not_an_issue(
|
|
83
|
+
self, boost, installed):
|
|
84
|
+
# `heal` deliberately will not fix this, so counting it would leave
|
|
85
|
+
# doctor permanently red on something no boost command can clear.
|
|
86
|
+
mine = paths.home() / ".claude" / "skills" / "my-own-skill"
|
|
87
|
+
mine.symlink_to(paths.home() / "elsewhere" / "my-own-skill")
|
|
88
|
+
r = boost("doctor") # rc 0, not 1
|
|
89
|
+
assert "not created by boost" in r.out
|
|
90
|
+
assert "0 broken links" in r.out # none of boost's are broken
|
|
91
|
+
assert "need attention" not in r.out
|
|
92
|
+
|
|
82
93
|
def test_missing_store_rc1(self, boost, installed):
|
|
83
94
|
shutil.rmtree(paths.store_dir() / "brainstorming")
|
|
84
95
|
r = boost("doctor", expect=1)
|
|
@@ -545,6 +556,34 @@ class TestHeal:
|
|
|
545
556
|
r = boost("heal")
|
|
546
557
|
assert "nothing to heal" in r.out
|
|
547
558
|
|
|
559
|
+
def test_a_link_boost_did_not_create_is_left_alone(self, boost, installed):
|
|
560
|
+
"""`heal` deleted these. A broken link is not necessarily garbage.
|
|
561
|
+
|
|
562
|
+
`~/.claude/skills/` is a directory the user owns and boost merely links
|
|
563
|
+
into, so a dangling entry there can be a skill on an unmounted volume or
|
|
564
|
+
a repo temporarily moved — both of which come back. Removing it is not a
|
|
565
|
+
repair, it is data loss with a reassuring name.
|
|
566
|
+
"""
|
|
567
|
+
mine = paths.home() / ".claude" / "skills" / "my-own-skill"
|
|
568
|
+
mine.symlink_to(paths.home() / "elsewhere" / "my-own-skill")
|
|
569
|
+
|
|
570
|
+
r = boost("heal")
|
|
571
|
+
assert "does not point into" in r.out
|
|
572
|
+
assert "left alone" in r.out
|
|
573
|
+
assert mine.is_symlink() # still there, still dangling
|
|
574
|
+
assert "removed broken link ~/.claude/skills/my-own-skill" not in r.out
|
|
575
|
+
|
|
576
|
+
def test_a_relative_link_into_the_store_is_still_ours(self, boost, installed):
|
|
577
|
+
# Ownership is decided by where the link points, not by how it is
|
|
578
|
+
# spelled — a relative target resolves against the link's own dir.
|
|
579
|
+
rel = paths.home() / ".claude" / "skills" / "relghost"
|
|
580
|
+
import os as _os
|
|
581
|
+
rel.symlink_to(_os.path.relpath(str(paths.store_dir() / "nowhere"),
|
|
582
|
+
str(rel.parent)))
|
|
583
|
+
r = boost("heal")
|
|
584
|
+
assert "removed broken link ~/.claude/skills/relghost" in r.out
|
|
585
|
+
assert not rel.is_symlink()
|
|
586
|
+
|
|
548
587
|
def test_restores_missing_store_from_tap(self, boost, installed):
|
|
549
588
|
shutil.rmtree(paths.store_dir() / "brainstorming")
|
|
550
589
|
r = boost("heal")
|