boost-skill-cli 1.0.82__tar.gz → 1.0.83__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.82 → boost_skill_cli-1.0.83}/PKG-INFO +1 -1
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/_version.py +2 -2
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/commands/pkg.py +6 -6
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/commands/quality.py +15 -13
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/commands/taps.py +15 -10
- boost_skill_cli-1.0.83/boost_cli/core/staleness.py +78 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_skill_cli.egg-info/PKG-INFO +1 -1
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_skill_cli.egg-info/SOURCES.txt +2 -0
- boost_skill_cli-1.0.83/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +16 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap.html +13 -12
- boost_skill_cli-1.0.83/tests/unit/test_staleness.py +102 -0
- boost_skill_cli-1.0.82/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -16
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/.gitattributes +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/.gitignore +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/CLAUDE.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/CONTRIBUTING.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/LICENSE +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/MANIFEST.in +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/Makefile +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/README.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/SECURITY.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/__init__.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/__main__.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/cli.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/cliparse.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/commands/__init__.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/commands/bmad.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/commands/configuration.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/commands/discovery.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/commands/hooks.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/commands/info.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/commands/intelligence.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/commands/team.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/__init__.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/agents.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/ai.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/catalog.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/claude_settings.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/config.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/dense.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/embed.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/frontmatter.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/gitutil.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/journal.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/lockfile.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/logs.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/mcp.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/output.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/paths.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/policy.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/rag.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/registry.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/store.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/core/util.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/data/registries.json +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/errors.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_cli/spin.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_skill_cli.egg-info/entry_points.txt +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_skill_cli.egg-info/requires.txt +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_skill_cli.egg-info/top_level.txt +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/.claude/settings.local.json +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/DEBUGGING.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/demo.gif +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/demo.tape +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/design-roadmap.html +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/index.html +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/mcp-hub.html +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/rag-architecture.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D01.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D02.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D03.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D04.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D05.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D06.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D07.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D08.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D09.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D10.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D11.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D12.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D13.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D14.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D15.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D16.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D17.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D18.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D19.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D20.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D21.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D22.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D23.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D24.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D25.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/BOOST-D26.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/command-reference-docs-site.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/html-validation-html-validate.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/typo-detection-codespell.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/update-diff-before-apply.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/index.html +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/pyproject.toml +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/scripts/build_registries.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/scripts/build_roadmap.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/scripts/mutation_gate.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/setup.cfg +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/style/README.md +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/style/boost.css +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/style/boost.js +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/style/demo.html +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/conftest.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/functional/test_cli_bmad.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/functional/test_cli_configuration.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/functional/test_cli_discovery.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/functional/test_cli_hooks.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/functional/test_cli_info.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/functional/test_cli_intelligence.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/functional/test_cli_pkg.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/functional/test_cli_quality.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/functional/test_cli_taps.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/functional/test_cli_team.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/functional/test_everyday_loop.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/make_fixture.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/smoke.sh +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_agents.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_ai.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_catalog.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_claude_settings.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_cliparse.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_config.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_dense.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_dense_fallback.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_embed.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_errors_and_cli_table.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_frontmatter.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_gitutil.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_journal.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_lockfile.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_logs.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_mcp.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_mutation_hardening.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_output.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_paths.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_policy.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_rag.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_registries_fresh.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_registry.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_roadmap_fresh.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_spin.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_store.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_token_parity.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_util.py +0 -0
- {boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/tests/unit/test_version.py +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.83'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 0, 83)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -16,7 +16,7 @@ from typing import Dict, List, Optional
|
|
|
16
16
|
|
|
17
17
|
from .. import cliparse
|
|
18
18
|
from ..core import (agents, catalog, gitutil, journal, lockfile, paths,
|
|
19
|
-
registry, store, util)
|
|
19
|
+
registry, staleness, store, util)
|
|
20
20
|
from ..core import output as out
|
|
21
21
|
from ..errors import BoostError
|
|
22
22
|
|
|
@@ -287,16 +287,16 @@ def cmd_update(argv: List[str]) -> int:
|
|
|
287
287
|
entry = matches[0]
|
|
288
288
|
old_v = str(lk.get("version", "0.0.0"))
|
|
289
289
|
new_v = str(entry.get("version", "0.0.0"))
|
|
290
|
-
|
|
291
|
-
if
|
|
290
|
+
head, src_sha = "", None
|
|
291
|
+
if not util.semver_gt(new_v, old_v):
|
|
292
292
|
head = gitutil.head_commit(registry.get(tapname).path)
|
|
293
293
|
if head and head != lk.get("commit"):
|
|
294
294
|
try:
|
|
295
|
-
|
|
295
|
+
src_sha = util.sha256_dir(store.source_dir_for(entry))
|
|
296
296
|
except BoostError:
|
|
297
297
|
continue
|
|
298
|
-
|
|
299
|
-
|
|
298
|
+
reason = staleness.upstream_reason(old_v, new_v, lk.get("commit", ""),
|
|
299
|
+
head, lk.get("sha256", ""), src_sha)
|
|
300
300
|
if reason is None:
|
|
301
301
|
continue
|
|
302
302
|
try:
|
|
@@ -18,7 +18,7 @@ from typing import List, Optional, Tuple
|
|
|
18
18
|
from .. import cliparse
|
|
19
19
|
from ..core import (agents, ai, catalog, frontmatter, gitutil, journal,
|
|
20
20
|
lockfile, logs, output as out, paths, policy, registry,
|
|
21
|
-
store, util)
|
|
21
|
+
staleness, store, util)
|
|
22
22
|
from ..errors import BoostError
|
|
23
23
|
|
|
24
24
|
# --- audit: dangerous-content patterns ------------------------------------
|
|
@@ -119,18 +119,20 @@ def _drift_status(name: str, entry: dict) -> str:
|
|
|
119
119
|
"""'in-sync' | 'local-edits' | 'upstream-moved' | 'source-missing'
|
|
120
120
|
| 'store-missing' | 'n/a' (local imports with no tap source)."""
|
|
121
121
|
sdir = store.skill_store_dir(name)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
122
|
+
store_sha = util.sha256_dir(sdir) if sdir.is_dir() else None
|
|
123
|
+
is_local = entry.get("tap") == "local"
|
|
124
|
+
lock_sha = entry.get("sha256", "")
|
|
125
|
+
source_sha = None
|
|
126
|
+
if store_sha is not None and store_sha == lock_sha and not is_local:
|
|
127
|
+
try:
|
|
128
|
+
src = store.source_dir_for(
|
|
129
|
+
{"name": name, "tap": entry.get("tap", ""),
|
|
130
|
+
"rel_dir": entry.get("source_dir", ".")})
|
|
131
|
+
except BoostError:
|
|
132
|
+
source_sha = None
|
|
133
|
+
else:
|
|
134
|
+
source_sha = util.sha256_dir(src)
|
|
135
|
+
return staleness.drift_state(store_sha, lock_sha, is_local, source_sha)
|
|
134
136
|
|
|
135
137
|
|
|
136
138
|
_DRIFT_STYLE = {"in-sync": out.GREEN, "local-edits": out.YELLOW,
|
|
@@ -5,7 +5,7 @@ import argparse
|
|
|
5
5
|
import json
|
|
6
6
|
|
|
7
7
|
from .. import cliparse, spin
|
|
8
|
-
from ..core import catalog, config, gitutil, journal, lockfile, paths, registry, store, util
|
|
8
|
+
from ..core import catalog, config, gitutil, journal, lockfile, paths, registry, staleness, store, util
|
|
9
9
|
from ..core import output as out
|
|
10
10
|
from ..errors import BoostError
|
|
11
11
|
|
|
@@ -218,9 +218,8 @@ def cmd_outdated(argv) -> int:
|
|
|
218
218
|
latest = str(entry.get("version") or "0.0.0")
|
|
219
219
|
installed_v = str(lk.get("version") or "0.0.0")
|
|
220
220
|
stale, latest_disp = False, latest
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
else:
|
|
221
|
+
head, src_sha, src_missing = "", None, False
|
|
222
|
+
if not util.semver_gt(latest, installed_v):
|
|
224
223
|
if tap_name not in heads:
|
|
225
224
|
try:
|
|
226
225
|
tap = registry.get(tap_name)
|
|
@@ -231,13 +230,19 @@ def cmd_outdated(argv) -> int:
|
|
|
231
230
|
head = heads[tap_name]
|
|
232
231
|
if head and head != lk.get("commit"):
|
|
233
232
|
try:
|
|
234
|
-
|
|
233
|
+
src_sha = util.sha256_dir(store.source_dir_for(entry))
|
|
235
234
|
except BoostError:
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
235
|
+
src_missing = True
|
|
236
|
+
if src_missing:
|
|
237
|
+
stale, latest_disp = True, "source missing"
|
|
238
|
+
else:
|
|
239
|
+
reason = staleness.upstream_reason(
|
|
240
|
+
installed_v, latest, lk.get("commit", ""), head,
|
|
241
|
+
lk.get("sha256", ""), src_sha)
|
|
242
|
+
if reason == staleness.VERSION:
|
|
243
|
+
stale = True
|
|
244
|
+
elif reason == staleness.CONTENT:
|
|
245
|
+
stale, latest_disp = True, "%s (%s)" % (latest, head[:7])
|
|
241
246
|
if stale:
|
|
242
247
|
results.append({"name": name, "installed": installed_v,
|
|
243
248
|
"latest": latest_disp, "tap": tap_name,
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Single source of truth for "is an installed skill stale vs its tap?".
|
|
2
|
+
|
|
3
|
+
``cmd_update`` (pkg.py), ``cmd_outdated`` (taps.py) and ``_drift_status``
|
|
4
|
+
(quality.py) each re-derived this from the same three signals — the catalog
|
|
5
|
+
version, the tap's HEAD commit and the source tree's ``sha256`` — so the logic
|
|
6
|
+
lived in three places that would inevitably drift apart. These two pure
|
|
7
|
+
(I/O-free) functions are now the one decision the commands render.
|
|
8
|
+
|
|
9
|
+
Keeping them free of any filesystem/subprocess access is deliberate: the
|
|
10
|
+
commands gather the raw signals (``head_commit``, ``source_dir_for``,
|
|
11
|
+
``sha256_dir``) and pass them in, so the *decision* stays trivially testable.
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import Optional
|
|
16
|
+
|
|
17
|
+
from . import util
|
|
18
|
+
|
|
19
|
+
# ── upstream_reason: why a tap's copy is newer than the installed one ──────
|
|
20
|
+
VERSION = "version" # the catalog advertises a higher semver
|
|
21
|
+
CONTENT = "content" # the tap HEAD moved AND the source tree's bytes changed
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def upstream_reason(installed_version: str, latest_version: str,
|
|
25
|
+
installed_commit: str, tap_head: str,
|
|
26
|
+
installed_sha: str, source_sha: Optional[str]
|
|
27
|
+
) -> Optional[str]:
|
|
28
|
+
"""Why the tap's copy is newer than the installed one, else ``None``.
|
|
29
|
+
|
|
30
|
+
Mirrors the historical order exactly: a higher advertised semver wins
|
|
31
|
+
immediately; otherwise a *moved* tap HEAD **plus** a changed source tree
|
|
32
|
+
counts as content drift. ``source_sha`` is ``None`` when the source tree
|
|
33
|
+
could not be hashed (missing checkout) — treated as "no content signal",
|
|
34
|
+
i.e. not stale on that axis.
|
|
35
|
+
"""
|
|
36
|
+
if util.semver_gt(latest_version, installed_version):
|
|
37
|
+
return VERSION
|
|
38
|
+
if tap_head and tap_head != installed_commit:
|
|
39
|
+
if source_sha is not None and source_sha != installed_sha:
|
|
40
|
+
return CONTENT
|
|
41
|
+
return None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# ── drift_state: how an installed skill's store copy relates to lock+tap ───
|
|
45
|
+
IN_SYNC = "in-sync"
|
|
46
|
+
LOCAL_EDITS = "local-edits"
|
|
47
|
+
UPSTREAM_MOVED = "upstream-moved"
|
|
48
|
+
SOURCE_MISSING = "source-missing"
|
|
49
|
+
STORE_MISSING = "store-missing"
|
|
50
|
+
NA = "n/a"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def drift_state(store_sha: Optional[str], lock_sha: str,
|
|
54
|
+
is_local: bool, source_sha: Optional[str]) -> str:
|
|
55
|
+
"""Drift of an installed skill's store copy vs its lock entry and tap.
|
|
56
|
+
|
|
57
|
+
Signals (all pre-computed by the caller):
|
|
58
|
+
|
|
59
|
+
* ``store_sha`` — ``sha256`` of the on-disk store dir, or ``None`` if the
|
|
60
|
+
store dir is missing.
|
|
61
|
+
* ``lock_sha`` — the ``sha256`` recorded in the lock entry.
|
|
62
|
+
* ``is_local`` — ``True`` for local imports (no tap source to compare).
|
|
63
|
+
* ``source_sha`` — ``sha256`` of the tap source dir, or ``None`` if it is
|
|
64
|
+
unavailable (only consulted once the store copy matches the lock and the
|
|
65
|
+
skill has a tap).
|
|
66
|
+
|
|
67
|
+
The ordering is significant and matches the historical ``_drift_status``:
|
|
68
|
+
a missing store beats local edits, which beat the local/upstream split.
|
|
69
|
+
"""
|
|
70
|
+
if store_sha is None:
|
|
71
|
+
return STORE_MISSING
|
|
72
|
+
if store_sha != lock_sha:
|
|
73
|
+
return LOCAL_EDITS
|
|
74
|
+
if is_local:
|
|
75
|
+
return NA
|
|
76
|
+
if source_sha is None:
|
|
77
|
+
return SOURCE_MISSING
|
|
78
|
+
return IN_SYNC if source_sha == lock_sha else UPSTREAM_MOVED
|
|
@@ -48,6 +48,7 @@ boost_cli/core/paths.py
|
|
|
48
48
|
boost_cli/core/policy.py
|
|
49
49
|
boost_cli/core/rag.py
|
|
50
50
|
boost_cli/core/registry.py
|
|
51
|
+
boost_cli/core/staleness.py
|
|
51
52
|
boost_cli/core/store.py
|
|
52
53
|
boost_cli/core/util.py
|
|
53
54
|
boost_cli/data/registries.json
|
|
@@ -223,6 +224,7 @@ tests/unit/test_registries_fresh.py
|
|
|
223
224
|
tests/unit/test_registry.py
|
|
224
225
|
tests/unit/test_roadmap_fresh.py
|
|
225
226
|
tests/unit/test_spin.py
|
|
227
|
+
tests/unit/test_staleness.py
|
|
226
228
|
tests/unit/test_store.py
|
|
227
229
|
tests/unit/test_token_parity.py
|
|
228
230
|
tests/unit/test_util.py
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: consolidate-skill-staleness-drift-logic-into-cor
|
|
3
|
+
board: code
|
|
4
|
+
section: shipped
|
|
5
|
+
status: shipped
|
|
6
|
+
category: Correctness
|
|
7
|
+
complexity: M
|
|
8
|
+
impact: High
|
|
9
|
+
wow: 3
|
|
10
|
+
note: three copies → one core module
|
|
11
|
+
order: 3
|
|
12
|
+
owner: loop/consolidate-staleness
|
|
13
|
+
pr: 91
|
|
14
|
+
title: Consolidate skill-staleness / drift logic into core
|
|
15
|
+
---
|
|
16
|
+
The "is this skill outdated" decision — <code>semver_gt</code> → commit compare → <code>sha256_dir</code> vs lock — was reimplemented nearly verbatim in <code>cmd_update</code>, <code>cmd_outdated</code> and <code>_drift_status</code> — three copies of core business logic that would drift apart. It now lives in one place: <code>core/staleness.py</code> exposes two <b>pure</b> (I/O-free) decisions — <code>upstream_reason()</code> (the version→commit→content ladder rendered by <code>cmd_update</code>/<code>cmd_outdated</code>) and <code>drift_state()</code> (the store/local-edits/upstream ladder rendered by <code>_drift_status</code>). The commands became thin renderers; behavior is byte-for-byte preserved and the new module is fully unit-tested (every branch pinned, all mutants killed).
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
<section class="block reveal">
|
|
116
116
|
<div class="stats">
|
|
117
117
|
<!-- ROADMAP:stats -->
|
|
118
|
-
<div class="stat"><b>
|
|
118
|
+
<div class="stat"><b>10</b><span>Shipped</span></div>
|
|
119
119
|
<div class="stat"><b>3</b><span>Next up</span></div>
|
|
120
120
|
<div class="stat"><b>4</b><span>Planned</span></div>
|
|
121
121
|
<div class="stat"><b>85</b><span>Loop finds</span></div>
|
|
@@ -162,6 +162,18 @@
|
|
|
162
162
|
</div>
|
|
163
163
|
</article>
|
|
164
164
|
|
|
165
|
+
<article class="cap rcard">
|
|
166
|
+
<div class="head"><span class="pill shipped">Shipped</span><span class="cat">Correctness</span></div>
|
|
167
|
+
<h3>Consolidate skill-staleness / drift logic into core</h3>
|
|
168
|
+
<p>The "is this skill outdated" decision — <code>semver_gt</code> → commit compare → <code>sha256_dir</code> vs lock — was reimplemented nearly verbatim in <code>cmd_update</code>, <code>cmd_outdated</code> and <code>_drift_status</code> — three copies of core business logic that would drift apart. It now lives in one place: <code>core/staleness.py</code> exposes two <b>pure</b> (I/O-free) decisions — <code>upstream_reason()</code> (the version→commit→content ladder rendered by <code>cmd_update</code>/<code>cmd_outdated</code>) and <code>drift_state()</code> (the store/local-edits/upstream ladder rendered by <code>_drift_status</code>). The commands became thin renderers; behavior is byte-for-byte preserved and the new module is fully unit-tested (every branch pinned, all mutants killed).</p>
|
|
169
|
+
<div class="meta">
|
|
170
|
+
<span class="m">Complexity <b>M</b></span>
|
|
171
|
+
<span class="m hi">Impact <b>High</b></span>
|
|
172
|
+
<span class="m">Wow <b class="wow">★★★</b></span>
|
|
173
|
+
<span class="m">three copies → one core module</span>
|
|
174
|
+
</div>
|
|
175
|
+
</article>
|
|
176
|
+
|
|
165
177
|
<article class="cap rcard">
|
|
166
178
|
<div class="head"><span class="pill shipped">Shipped</span><span class="cat">Testing</span></div>
|
|
167
179
|
<h3>Mutation hardening — <code>core/frontmatter.py</code></h3>
|
|
@@ -439,17 +451,6 @@
|
|
|
439
451
|
</div>
|
|
440
452
|
</article>
|
|
441
453
|
|
|
442
|
-
<article class="cap rcard">
|
|
443
|
-
<div class="head"><span class="pill next">Next</span><span class="cat">Correctness</span></div>
|
|
444
|
-
<h3>Consolidate skill-staleness / drift logic into core</h3>
|
|
445
|
-
<p>The "is this skill outdated" decision — <code>semver_gt</code> → commit compare → <code>sha256_dir</code> vs lock — is reimplemented nearly verbatim in <code>cmd_update</code>, <code>cmd_outdated</code> and <code>_drift_status</code> (<code>pkg.py:277 · taps.py:225 · quality.py:120</code>). Three copies of core business logic that <b>will drift apart</b>. Make it one <code>core</code> function the commands render.</p>
|
|
446
|
-
<div class="meta">
|
|
447
|
-
<span class="m">Complexity <b>M</b></span>
|
|
448
|
-
<span class="m hi">Impact <b>High</b></span>
|
|
449
|
-
<span class="m">Wow <b class="wow">★★★</b></span>
|
|
450
|
-
</div>
|
|
451
|
-
</article>
|
|
452
|
-
|
|
453
454
|
<article class="cap rcard">
|
|
454
455
|
<div class="head"><span class="pill shipped">Shipped</span><span class="cat">Performance</span></div>
|
|
455
456
|
<h3>Memoize <code>config.load()</code> in-process</h3>
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""Unit tests: boost_cli/core/staleness.py — the single-source staleness/drift
|
|
2
|
+
decision that cmd_update, cmd_outdated and _drift_status now render.
|
|
3
|
+
|
|
4
|
+
Both functions are pure, so every branch (and the ordering between branches) is
|
|
5
|
+
pinned here with assertions specific enough to kill mutants.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from boost_cli.core import staleness
|
|
10
|
+
|
|
11
|
+
SHA_A = "a" * 64
|
|
12
|
+
SHA_B = "b" * 64
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TestUpstreamReason:
|
|
16
|
+
def test_higher_semver_is_version(self):
|
|
17
|
+
assert staleness.upstream_reason(
|
|
18
|
+
"1.0.0", "1.1.0", "c1", "c2", SHA_A, SHA_B) == staleness.VERSION
|
|
19
|
+
|
|
20
|
+
def test_version_constant_value(self):
|
|
21
|
+
# pins the literal so a mutated constant is caught
|
|
22
|
+
assert staleness.VERSION == "version"
|
|
23
|
+
|
|
24
|
+
def test_content_constant_value(self):
|
|
25
|
+
assert staleness.CONTENT == "content"
|
|
26
|
+
|
|
27
|
+
def test_version_wins_even_when_commit_and_content_also_differ(self):
|
|
28
|
+
# semver must be checked FIRST — a higher version reports "version"
|
|
29
|
+
# regardless of the (also-changed) commit/content signals.
|
|
30
|
+
assert staleness.upstream_reason(
|
|
31
|
+
"1.0.0", "2.0.0", "old", "new", SHA_A, SHA_B) == staleness.VERSION
|
|
32
|
+
|
|
33
|
+
def test_same_version_no_commit_move_is_none(self):
|
|
34
|
+
assert staleness.upstream_reason(
|
|
35
|
+
"1.0.0", "1.0.0", "c1", "c1", SHA_A, SHA_B) is None
|
|
36
|
+
|
|
37
|
+
def test_empty_tap_head_is_none(self):
|
|
38
|
+
# no HEAD signal (e.g. tap not cloned) → not stale on the content axis
|
|
39
|
+
assert staleness.upstream_reason(
|
|
40
|
+
"1.0.0", "1.0.0", "c1", "", SHA_A, SHA_B) is None
|
|
41
|
+
|
|
42
|
+
def test_moved_commit_but_source_unhashable_is_none(self):
|
|
43
|
+
# source_sha None means "no content signal" — must NOT report content
|
|
44
|
+
assert staleness.upstream_reason(
|
|
45
|
+
"1.0.0", "1.0.0", "old", "new", SHA_A, None) is None
|
|
46
|
+
|
|
47
|
+
def test_moved_commit_same_content_is_none(self):
|
|
48
|
+
assert staleness.upstream_reason(
|
|
49
|
+
"1.0.0", "1.0.0", "old", "new", SHA_A, SHA_A) is None
|
|
50
|
+
|
|
51
|
+
def test_moved_commit_changed_content_is_content(self):
|
|
52
|
+
assert staleness.upstream_reason(
|
|
53
|
+
"1.0.0", "1.0.0", "old", "new", SHA_A, SHA_B) == staleness.CONTENT
|
|
54
|
+
|
|
55
|
+
def test_lower_advertised_version_not_stale_by_version(self):
|
|
56
|
+
# a downgrade in the catalog is not an upgrade — no commit move → None
|
|
57
|
+
assert staleness.upstream_reason(
|
|
58
|
+
"2.0.0", "1.0.0", "c1", "c1", SHA_A, SHA_B) is None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class TestDriftState:
|
|
62
|
+
def test_store_missing(self):
|
|
63
|
+
assert staleness.drift_state(
|
|
64
|
+
None, SHA_A, False, SHA_A) == staleness.STORE_MISSING
|
|
65
|
+
|
|
66
|
+
def test_store_missing_takes_precedence_over_local(self):
|
|
67
|
+
# a missing store is reported even for a local import
|
|
68
|
+
assert staleness.drift_state(
|
|
69
|
+
None, SHA_A, True, None) == staleness.STORE_MISSING
|
|
70
|
+
|
|
71
|
+
def test_local_edits(self):
|
|
72
|
+
assert staleness.drift_state(
|
|
73
|
+
SHA_B, SHA_A, False, SHA_A) == staleness.LOCAL_EDITS
|
|
74
|
+
|
|
75
|
+
def test_local_edits_take_precedence_over_na(self):
|
|
76
|
+
# edited store beats the local/upstream split even for local imports
|
|
77
|
+
assert staleness.drift_state(
|
|
78
|
+
SHA_B, SHA_A, True, None) == staleness.LOCAL_EDITS
|
|
79
|
+
|
|
80
|
+
def test_local_import_in_sync_is_na(self):
|
|
81
|
+
assert staleness.drift_state(
|
|
82
|
+
SHA_A, SHA_A, True, None) == staleness.NA
|
|
83
|
+
|
|
84
|
+
def test_source_missing(self):
|
|
85
|
+
assert staleness.drift_state(
|
|
86
|
+
SHA_A, SHA_A, False, None) == staleness.SOURCE_MISSING
|
|
87
|
+
|
|
88
|
+
def test_in_sync(self):
|
|
89
|
+
assert staleness.drift_state(
|
|
90
|
+
SHA_A, SHA_A, False, SHA_A) == staleness.IN_SYNC
|
|
91
|
+
|
|
92
|
+
def test_upstream_moved(self):
|
|
93
|
+
assert staleness.drift_state(
|
|
94
|
+
SHA_A, SHA_A, False, SHA_B) == staleness.UPSTREAM_MOVED
|
|
95
|
+
|
|
96
|
+
def test_status_constant_values(self):
|
|
97
|
+
assert staleness.IN_SYNC == "in-sync"
|
|
98
|
+
assert staleness.LOCAL_EDITS == "local-edits"
|
|
99
|
+
assert staleness.UPSTREAM_MOVED == "upstream-moved"
|
|
100
|
+
assert staleness.SOURCE_MISSING == "source-missing"
|
|
101
|
+
assert staleness.STORE_MISSING == "store-missing"
|
|
102
|
+
assert staleness.NA == "n/a"
|
boost_skill_cli-1.0.82/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: consolidate-skill-staleness-drift-logic-into-cor
|
|
3
|
-
board: code
|
|
4
|
-
section: internals
|
|
5
|
-
status: next
|
|
6
|
-
category: Correctness
|
|
7
|
-
complexity: M
|
|
8
|
-
impact: High
|
|
9
|
-
wow: 3
|
|
10
|
-
note:
|
|
11
|
-
order: 3
|
|
12
|
-
owner:
|
|
13
|
-
pr:
|
|
14
|
-
title: Consolidate skill-staleness / drift logic into core
|
|
15
|
-
---
|
|
16
|
-
The "is this skill outdated" decision — <code>semver_gt</code> → commit compare → <code>sha256_dir</code> vs lock — is reimplemented nearly verbatim in <code>cmd_update</code>, <code>cmd_outdated</code> and <code>_drift_status</code> (<code>pkg.py:277 · taps.py:225 · quality.py:120</code>). Three copies of core business logic that <b>will drift apart</b>. Make it one <code>core</code> function the commands render.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{boost_skill_cli-1.0.82 → boost_skill_cli-1.0.83}/boost_skill_cli.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|