boost-skill-cli 1.0.152__tar.gz → 1.0.154__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.152 → boost_skill_cli-1.0.154}/PKG-INFO +1 -1
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost +6 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/_version.py +2 -2
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/cli.py +6 -6
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/cliparse.py +1 -1
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/commands/bmad.py +6 -6
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/commands/configuration.py +25 -19
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/commands/discovery.py +11 -14
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/commands/info.py +9 -7
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/commands/intelligence.py +9 -11
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/commands/pkg.py +15 -22
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/commands/quality.py +14 -14
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/commands/taps.py +1 -1
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/commands/team.py +8 -8
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/catalog.py +4 -4
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/claude_settings.py +5 -6
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/config.py +2 -2
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/dense.py +12 -4
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/frontmatter.py +1 -2
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/gitutil.py +2 -2
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/injectscan.py +6 -4
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/journal.py +2 -2
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/lockfile.py +3 -3
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/logs.py +4 -9
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/mcp.py +1 -1
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/output.py +17 -1
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/paths.py +6 -2
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/policy.py +4 -5
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/rag.py +4 -4
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/registry.py +7 -5
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/serve.py +11 -7
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/staleness.py +2 -3
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/store.py +2 -2
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/updatediff.py +2 -5
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/util.py +26 -4
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_skill_cli.egg-info/PKG-INFO +1 -1
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +3 -3
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/windows-in-the-ci-matrix.md +3 -3
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap.html +2 -2
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/pyproject.toml +17 -4
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/scripts/build_registries.py +2 -2
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/scripts/build_roadmap.py +5 -5
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/scripts/eval_retrieval.py +2 -2
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/scripts/mutation_gate.py +1 -1
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/bdd/features/steps/discovery_steps.py +2 -2
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/functional/test_cli_adapt.py +1 -1
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/functional/test_cli_bmad.py +2 -2
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/functional/test_cli_configuration.py +17 -18
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/functional/test_cli_discovery.py +51 -26
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/functional/test_cli_info.py +18 -10
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/functional/test_cli_intelligence.py +24 -25
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/functional/test_cli_pkg.py +23 -23
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/functional/test_cli_quality.py +10 -10
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/functional/test_cli_taps.py +10 -10
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/functional/test_cli_team.py +12 -9
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/functional/test_everyday_loop.py +2 -2
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/functional/test_property_parsers.py +3 -3
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/make_fixture.py +4 -2
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_adapters.py +2 -1
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_catalog.py +39 -34
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_claude_settings.py +3 -3
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_config.py +10 -10
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_dense.py +38 -3
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_dense_fallback.py +3 -2
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_docs_pages_linked.py +1 -1
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_gitutil.py +3 -3
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_journal.py +9 -9
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_lockfile.py +14 -14
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_logs.py +11 -11
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_mcp.py +4 -4
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_mutation_hardening.py +3 -3
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_output.py +2 -2
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_paths.py +6 -4
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_policy.py +4 -4
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_rag.py +18 -18
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_registries_fresh.py +1 -1
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_registry.py +6 -7
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_roadmap_fresh.py +2 -2
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_serve.py +55 -4
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_store.py +29 -28
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_token_parity.py +1 -1
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_typosquat.py +3 -1
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_util.py +10 -10
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/.gitattributes +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/.gitignore +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/CLAUDE.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/CONTRIBUTING.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/LICENSE +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/MANIFEST.in +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/Makefile +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/README.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/SECURITY.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/__init__.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/__main__.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/commands/__init__.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/commands/hooks.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/__init__.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/adapters.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/agents.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/ai.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/embed.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/imperative.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/nethttp.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/rules.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/secretscan.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/stackprobe.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/typosquat.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/core/workflows.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/data/registries.json +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/errors.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_cli/spin.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_skill_cli.egg-info/SOURCES.txt +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_skill_cli.egg-info/entry_points.txt +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_skill_cli.egg-info/requires.txt +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/boost_skill_cli.egg-info/top_level.txt +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/.claude/settings.local.json +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/DEBUGGING.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/adapters.html +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/demo.gif +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/demo.tape +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/design-roadmap.html +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/eval.html +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/index.html +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/mcp-hub.html +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/rag-architecture.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D01.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D02.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D03.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D04.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D05.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D06.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D07.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D08.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D09.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D10.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D11.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D12.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D13.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D14.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D15.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D16.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D17.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D18.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D19.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D20.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D21.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D22.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D23.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D24.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D25.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/BOOST-D26.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/boost-run-live-agents.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/command-reference-docs-site.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/framework-adapter-multi-agent.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/html-validation-html-validate.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/install-scope-user-or-project.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/typo-detection-codespell.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/update-diff-before-apply.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/docs/roadmap/items/workspace-scope-install.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/examples/README.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/examples/adapt-demo.sh +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/examples/boost-run-prototype.sh +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/index.html +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/scripts/bench_cli.sh +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/scripts/ensure_eval_corpus.sh +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/scripts/eval_explain.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/scripts/eval_recommend.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/setup.cfg +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/style/README.md +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/style/boost.css +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/style/boost.js +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/style/demo.html +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/bdd/features/adapt.feature +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/bdd/features/browse.feature +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/bdd/features/count.feature +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/bdd/features/discover.feature +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/bdd/features/doctor.feature +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/bdd/features/environment.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/bdd/features/explain.feature +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/bdd/features/index.feature +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/bdd/features/install.feature +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/bdd/features/list.feature +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/bdd/features/mcp.feature +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/bdd/features/search.feature +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/bdd/features/steps/cli_steps.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/bdd/features/steps/mcp_steps.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/bdd/features/steps/quality_steps.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/conftest.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/eval/baseline.json +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/eval/explain.jsonl +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/eval/golden.jsonl +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/eval/recommend.jsonl +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/eval/taps.txt +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/functional/test_cli_hooks.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/perf/test_benchmarks.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/smoke.sh +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_agents.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_ai.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_cliparse.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_embed.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_errors_and_cli_table.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_frontmatter.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_imperative.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_injectscan.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_nethttp.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_pkg_confusions.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_pkg_injection.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_pkg_secrets.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_rules.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_secretscan.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_spin.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_stackprobe.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_staleness.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_updatediff.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_version.py +0 -0
- {boost_skill_cli-1.0.152 → boost_skill_cli-1.0.154}/tests/unit/test_workflows.py +0 -0
|
@@ -12,6 +12,12 @@ while [ -h "$SOURCE" ]; do
|
|
|
12
12
|
[[ "$SOURCE" != /* ]] && SOURCE="$DIR/$SOURCE"
|
|
13
13
|
done
|
|
14
14
|
ROOT="$(cd -P "$(dirname "$SOURCE")" >/dev/null 2>&1 && pwd)"
|
|
15
|
+
# Under Git Bash on Windows, $ROOT is an MSYS path (/d/a/boost/boost); native
|
|
16
|
+
# Windows Python can't resolve that, so convert to a mixed path (D:/a/...)
|
|
17
|
+
# before it's embedded in the -c script below. No-op on Linux/macOS.
|
|
18
|
+
if command -v cygpath >/dev/null 2>&1; then
|
|
19
|
+
ROOT="$(cygpath -m "$ROOT")"
|
|
20
|
+
fi
|
|
15
21
|
|
|
16
22
|
find_python() {
|
|
17
23
|
for py in python3 python; do
|
|
@@ -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.154'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 0, 154)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -17,6 +17,7 @@ from .core import logs
|
|
|
17
17
|
from .core import nethttp
|
|
18
18
|
from .core import output as out
|
|
19
19
|
from .errors import BoostError
|
|
20
|
+
import contextlib
|
|
20
21
|
|
|
21
22
|
# Global flags handled before dispatch, stripped from the command's own argv.
|
|
22
23
|
_GLOBAL_FLAGS = {
|
|
@@ -174,7 +175,7 @@ def print_command_help(name: str) -> int:
|
|
|
174
175
|
meta = resolve(name)
|
|
175
176
|
if not meta:
|
|
176
177
|
return _unknown(name)
|
|
177
|
-
_group,
|
|
178
|
+
_group, _module, summary = meta
|
|
178
179
|
print(out.c("boost %s" % name, out.BOLD) + " — " + summary)
|
|
179
180
|
# delegate to the command's own --help for flags
|
|
180
181
|
return _dispatch(name, ["--help"], soft=True)
|
|
@@ -196,7 +197,7 @@ def _unknown(name: str) -> int:
|
|
|
196
197
|
|
|
197
198
|
|
|
198
199
|
def _dispatch(name: str, argv: List[str], soft: bool = False) -> int:
|
|
199
|
-
|
|
200
|
+
_group, module, _summary = _BY_NAME[name]
|
|
200
201
|
mod = importlib.import_module("boost_cli.commands.%s" % module)
|
|
201
202
|
func = getattr(mod, "cmd_%s" % name.replace("-", "_"), None)
|
|
202
203
|
if func is None:
|
|
@@ -224,6 +225,7 @@ def _extract_globals(argv: List[str]) -> tuple[dict, List[str]]:
|
|
|
224
225
|
|
|
225
226
|
def main(argv: List[str] | None = None) -> int:
|
|
226
227
|
argv = list(sys.argv[1:] if argv is None else argv)
|
|
228
|
+
out.harden_console_encoding()
|
|
227
229
|
# Belt-and-suspenders fork safety: a host may fork() into `boost mcp
|
|
228
230
|
# --stdio` without the no_proxy env boost injects at registration, leaving
|
|
229
231
|
# the process one default getproxies() away from a macOS _scproxy SIGABRT.
|
|
@@ -263,13 +265,11 @@ def main(argv: List[str] | None = None) -> int:
|
|
|
263
265
|
print()
|
|
264
266
|
return rc
|
|
265
267
|
except BrokenPipeError:
|
|
266
|
-
|
|
268
|
+
with contextlib.suppress(Exception):
|
|
267
269
|
sys.stdout.close()
|
|
268
|
-
except Exception:
|
|
269
|
-
pass
|
|
270
270
|
rc = 0
|
|
271
271
|
return rc
|
|
272
|
-
except Exception as e:
|
|
272
|
+
except Exception as e:
|
|
273
273
|
report = logs.write_crash_report(e, [name, *rest])
|
|
274
274
|
if logs.is_debug():
|
|
275
275
|
raise
|
|
@@ -19,7 +19,7 @@ from .core import output as out
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class BoostArgumentParser(argparse.ArgumentParser):
|
|
22
|
-
def error(self, message: str):
|
|
22
|
+
def error(self, message: str):
|
|
23
23
|
"""Print a branded error + dimmed usage, then exit 2 (argparse's code)."""
|
|
24
24
|
out.err(message)
|
|
25
25
|
sys.stderr.write(out.c(self.format_usage(), out.DIM))
|
|
@@ -119,7 +119,7 @@ def _run_installer(directory: Path, modules: str) -> "subprocess.CompletedProces
|
|
|
119
119
|
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=900)
|
|
120
120
|
except (OSError, subprocess.TimeoutExpired) as e:
|
|
121
121
|
raise BoostError("bmad install failed: %s" % e,
|
|
122
|
-
hint="run it yourself: " + " ".join(cmd))
|
|
122
|
+
hint="run it yourself: " + " ".join(cmd)) from e
|
|
123
123
|
if proc.returncode != 0:
|
|
124
124
|
tail = (proc.stderr or proc.stdout or "").strip().splitlines()
|
|
125
125
|
raise BoostError(
|
|
@@ -192,7 +192,7 @@ def _copy_global_skills(modules) -> int:
|
|
|
192
192
|
continue
|
|
193
193
|
t = dest / d.name
|
|
194
194
|
if t.exists():
|
|
195
|
-
|
|
195
|
+
util.rmtree(t)
|
|
196
196
|
shutil.copytree(d, t)
|
|
197
197
|
n += 1
|
|
198
198
|
return n
|
|
@@ -278,7 +278,7 @@ def _disable(scope) -> int:
|
|
|
278
278
|
for d in sorted(_skills_dir(scope).glob("bmad-*")):
|
|
279
279
|
target = qdir / d.name
|
|
280
280
|
if target.exists():
|
|
281
|
-
|
|
281
|
+
util.rmtree(target)
|
|
282
282
|
shutil.move(str(d), str(target))
|
|
283
283
|
moved += 1
|
|
284
284
|
_set_scope_state(scope, startup=False, disabled=True)
|
|
@@ -298,7 +298,7 @@ def _enable(scope) -> int:
|
|
|
298
298
|
for d in sorted(qdir.glob("bmad-*")):
|
|
299
299
|
target = dest / d.name
|
|
300
300
|
if target.exists():
|
|
301
|
-
|
|
301
|
+
util.rmtree(target)
|
|
302
302
|
shutil.move(str(d), str(target))
|
|
303
303
|
restored += 1
|
|
304
304
|
_set_scope_state(scope, disabled=False)
|
|
@@ -366,7 +366,7 @@ def _state_read() -> dict:
|
|
|
366
366
|
if not p.exists():
|
|
367
367
|
return {"global": {}, "projects": {}}
|
|
368
368
|
try:
|
|
369
|
-
d = json.loads(p.read_text())
|
|
369
|
+
d = json.loads(p.read_text(encoding="utf-8"))
|
|
370
370
|
except (json.JSONDecodeError, OSError):
|
|
371
371
|
return {"global": {}, "projects": {}}
|
|
372
372
|
d.setdefault("global", {})
|
|
@@ -376,7 +376,7 @@ def _state_read() -> dict:
|
|
|
376
376
|
|
|
377
377
|
def _state_write(d: dict) -> None:
|
|
378
378
|
paths.ensure_dirs()
|
|
379
|
-
_state_path().write_text(json.dumps(d, indent=2) + "\n")
|
|
379
|
+
_state_path().write_text(json.dumps(d, indent=2) + "\n", encoding="utf-8")
|
|
380
380
|
|
|
381
381
|
|
|
382
382
|
def _proj_key() -> str:
|
|
@@ -72,7 +72,7 @@ def cmd_config(argv) -> int:
|
|
|
72
72
|
except TypeError as e:
|
|
73
73
|
raise BoostError(str(e),
|
|
74
74
|
hint="the parent key holds a plain value — "
|
|
75
|
-
"`boost config unset` it first")
|
|
75
|
+
"`boost config unset` it first") from e
|
|
76
76
|
val = config.get(args.key)
|
|
77
77
|
journal.log("config", args.key, op="set")
|
|
78
78
|
out.ok("set %s = %s"
|
|
@@ -101,25 +101,31 @@ def cmd_clean(argv) -> int:
|
|
|
101
101
|
help="also remove snapshots older than 90 days")
|
|
102
102
|
args = p.parse_args(argv)
|
|
103
103
|
|
|
104
|
-
items = [] # (path, kind, bytes)
|
|
105
|
-
for
|
|
104
|
+
items: list[tuple[Path, str, int]] = [] # (path, kind, bytes)
|
|
105
|
+
for spec in agents.known_agents().values():
|
|
106
106
|
adir = spec["dir"]
|
|
107
107
|
if not adir.is_dir():
|
|
108
108
|
continue
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
items.extend(
|
|
110
|
+
(link, "broken symlink", 0)
|
|
111
|
+
for link in sorted(adir.iterdir())
|
|
112
|
+
if link.is_symlink() and not link.exists()
|
|
113
|
+
)
|
|
112
114
|
|
|
113
115
|
configured = {t.safe_name for t in registry.list_taps()}
|
|
114
116
|
if paths.cache_dir().is_dir():
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
items.extend(
|
|
118
|
+
(f, "stale tap cache", f.stat().st_size)
|
|
119
|
+
for f in sorted(paths.cache_dir().glob("*.json"))
|
|
120
|
+
if f.stem not in configured
|
|
121
|
+
)
|
|
118
122
|
|
|
119
123
|
if paths.lock_history_dir().is_dir():
|
|
120
124
|
snaps = sorted(paths.lock_history_dir().glob("lock-*.json"))
|
|
121
|
-
|
|
122
|
-
|
|
125
|
+
items.extend(
|
|
126
|
+
(old, "old lock history", old.stat().st_size)
|
|
127
|
+
for old in snaps[:-50]
|
|
128
|
+
)
|
|
123
129
|
|
|
124
130
|
if paths.store_dir().is_dir():
|
|
125
131
|
for pth in sorted(paths.store_dir().rglob("*")):
|
|
@@ -152,7 +158,7 @@ def cmd_clean(argv) -> int:
|
|
|
152
158
|
if pth.is_symlink() or pth.is_file():
|
|
153
159
|
pth.unlink()
|
|
154
160
|
elif pth.is_dir():
|
|
155
|
-
|
|
161
|
+
util.rmtree(pth)
|
|
156
162
|
except OSError as e:
|
|
157
163
|
out.warn("could not remove %s: %s" % (_tilde(pth), e))
|
|
158
164
|
continue
|
|
@@ -224,7 +230,7 @@ def cmd_create(argv) -> int:
|
|
|
224
230
|
title = name.replace("-", " ").title()
|
|
225
231
|
target.mkdir(parents=True, exist_ok=True)
|
|
226
232
|
skill_md.write_text(frontmatter.dump(meta) + "\n\n"
|
|
227
|
-
+ _CREATE_BODY % {"title": title})
|
|
233
|
+
+ _CREATE_BODY % {"title": title}, encoding="utf-8")
|
|
228
234
|
journal.log("create", name, path=str(target))
|
|
229
235
|
out.ok("created %s" % _tilde(skill_md))
|
|
230
236
|
if args.install:
|
|
@@ -426,7 +432,7 @@ def cmd_onboard(argv) -> int:
|
|
|
426
432
|
for rel, content in files:
|
|
427
433
|
fp = repo / rel
|
|
428
434
|
fp.parent.mkdir(parents=True, exist_ok=True)
|
|
429
|
-
fp.write_text(content)
|
|
435
|
+
fp.write_text(content, encoding="utf-8")
|
|
430
436
|
out.ok("created %s" % _tilde(fp))
|
|
431
437
|
journal.log("onboard", _tilde(repo), pr=args.pr or None)
|
|
432
438
|
|
|
@@ -442,7 +448,7 @@ def cmd_onboard(argv) -> int:
|
|
|
442
448
|
text=True, timeout=120)
|
|
443
449
|
except (subprocess.TimeoutExpired, OSError) as e:
|
|
444
450
|
raise BoostError("gh pr create failed: %s" % e,
|
|
445
|
-
hint="branch %s is committed — push it and open the PR manually" % branch)
|
|
451
|
+
hint="branch %s is committed — push it and open the PR manually" % branch) from e
|
|
446
452
|
if proc.returncode != 0:
|
|
447
453
|
tail = (proc.stderr or proc.stdout or "").strip().splitlines()
|
|
448
454
|
raise BoostError("gh pr create failed: %s" % (tail[-1] if tail else "unknown error"),
|
|
@@ -599,7 +605,7 @@ def cmd_schedule(argv) -> int:
|
|
|
599
605
|
if plist.exists():
|
|
600
606
|
present = True
|
|
601
607
|
m = re.search(r"<key>StartInterval</key>\s*<integer>(\d+)</integer>",
|
|
602
|
-
plist.read_text())
|
|
608
|
+
plist.read_text(encoding="utf-8"))
|
|
603
609
|
if m:
|
|
604
610
|
secs = int(m.group(1))
|
|
605
611
|
interval = _interval_label(secs)
|
|
@@ -641,7 +647,7 @@ def cmd_schedule(argv) -> int:
|
|
|
641
647
|
if darwin:
|
|
642
648
|
plist = _plist_path()
|
|
643
649
|
plist.parent.mkdir(parents=True, exist_ok=True)
|
|
644
|
-
plist.write_text(_plist_body(shim, seconds))
|
|
650
|
+
plist.write_text(_plist_body(shim, seconds), encoding="utf-8")
|
|
645
651
|
out.ok("wrote %s" % _tilde(plist))
|
|
646
652
|
try:
|
|
647
653
|
subprocess.run(["launchctl", "unload", str(plist)],
|
|
@@ -669,7 +675,7 @@ def cmd_schedule(argv) -> int:
|
|
|
669
675
|
kept = [ln for ln in lines if not ln.rstrip().endswith(_CRON_MARK)]
|
|
670
676
|
try:
|
|
671
677
|
proc = subprocess.run(["crontab", "-"],
|
|
672
|
-
input="\n".join(kept
|
|
678
|
+
input="\n".join([*kept, entry]) + "\n",
|
|
673
679
|
capture_output=True, text=True, timeout=30)
|
|
674
680
|
except (OSError, subprocess.TimeoutExpired):
|
|
675
681
|
proc = None
|
|
@@ -943,7 +949,7 @@ def cmd_mcp(argv) -> int:
|
|
|
943
949
|
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
|
|
944
950
|
except (OSError, subprocess.TimeoutExpired) as e:
|
|
945
951
|
raise BoostError("claude mcp %s failed: %s" % (args.action, e),
|
|
946
|
-
hint="run it yourself: " + " ".join(cmd))
|
|
952
|
+
hint="run it yourself: " + " ".join(cmd)) from e
|
|
947
953
|
for ln in (proc.stdout or "").strip().splitlines():
|
|
948
954
|
out.info(ln)
|
|
949
955
|
if proc.returncode != 0:
|
|
@@ -22,6 +22,7 @@ from ..core import (agents, ai, catalog, config, dense, embed, gitutil,
|
|
|
22
22
|
from ..core import output as out
|
|
23
23
|
from ..core.stackprobe import detect_stack # re-exported: shared with Quality
|
|
24
24
|
from ..errors import BoostError
|
|
25
|
+
import contextlib
|
|
25
26
|
|
|
26
27
|
__all__ = ["detect_stack"]
|
|
27
28
|
|
|
@@ -31,7 +32,7 @@ def _positive_int(s: str) -> int:
|
|
|
31
32
|
try:
|
|
32
33
|
v = int(s)
|
|
33
34
|
except ValueError:
|
|
34
|
-
raise argparse.ArgumentTypeError("invalid int value: %r" % s)
|
|
35
|
+
raise argparse.ArgumentTypeError("invalid int value: %r" % s) from None
|
|
35
36
|
if v < 1:
|
|
36
37
|
raise argparse.ArgumentTypeError("must be >= 1")
|
|
37
38
|
return v
|
|
@@ -219,7 +220,7 @@ def cmd_index(argv):
|
|
|
219
220
|
"search/code?q=filename:SKILL.md&per_page=100&page=%d" % page],
|
|
220
221
|
capture_output=True, text=True, timeout=120)
|
|
221
222
|
except (subprocess.TimeoutExpired, OSError) as e:
|
|
222
|
-
raise BoostError("gh api timed out on page %d" % page, hint=str(e))
|
|
223
|
+
raise BoostError("gh api timed out on page %d" % page, hint=str(e)) from e
|
|
223
224
|
if proc.returncode != 0:
|
|
224
225
|
tail = "\n".join((proc.stderr or proc.stdout or "").strip()
|
|
225
226
|
.splitlines()[-3:])
|
|
@@ -233,7 +234,7 @@ def cmd_index(argv):
|
|
|
233
234
|
data = json.loads(proc.stdout)
|
|
234
235
|
except json.JSONDecodeError:
|
|
235
236
|
raise BoostError("gh api returned unparseable JSON",
|
|
236
|
-
hint="try `boost index` again, or `gh auth status`")
|
|
237
|
+
hint="try `boost index` again, or `gh auth status`") from None
|
|
237
238
|
if page == 1:
|
|
238
239
|
total = int(data.get("total_count") or 0)
|
|
239
240
|
batch = data.get("items") or []
|
|
@@ -252,7 +253,7 @@ def cmd_index(argv):
|
|
|
252
253
|
paths.ensure_dirs()
|
|
253
254
|
_discovery_path().write_text(json.dumps(
|
|
254
255
|
{"generated": util.now_iso(), "github_total": total, "items": items},
|
|
255
|
-
indent=1))
|
|
256
|
+
indent=1), encoding="utf-8")
|
|
256
257
|
repos = len({it["repo"] for it in items})
|
|
257
258
|
out.ok("indexed %d skill files across %d repos (GitHub reports %d total)"
|
|
258
259
|
% (len(items), repos, total))
|
|
@@ -325,10 +326,10 @@ def cmd_discover(argv):
|
|
|
325
326
|
"gh auth login`), then run `boost index`")
|
|
326
327
|
return 0
|
|
327
328
|
try:
|
|
328
|
-
data = json.loads(dpath.read_text())
|
|
329
|
+
data = json.loads(dpath.read_text(encoding="utf-8"))
|
|
329
330
|
except (json.JSONDecodeError, OSError):
|
|
330
331
|
raise BoostError("the discovery index is corrupt",
|
|
331
|
-
hint="rebuild it with `boost index`")
|
|
332
|
+
hint="rebuild it with `boost index`") from None
|
|
332
333
|
all_items = data.get("items") or []
|
|
333
334
|
tokens = [t.lower() for t in args.query if t.strip()]
|
|
334
335
|
items = [it for it in all_items
|
|
@@ -598,7 +599,7 @@ def _aurora_pairs(curses):
|
|
|
598
599
|
"""Allocate Aurora curses colour pairs; token-name -> attr int (0 if none)."""
|
|
599
600
|
names = ("cyan", "violet", "pink", "green", "yellow")
|
|
600
601
|
try:
|
|
601
|
-
custom = curses.can_change_color() and
|
|
602
|
+
custom = curses.can_change_color() and 16 + len(names) <= curses.COLORS
|
|
602
603
|
except curses.error:
|
|
603
604
|
custom = False
|
|
604
605
|
fg = dict(_nearest_base(curses))
|
|
@@ -695,19 +696,15 @@ def _browse_tui(curses, entries):
|
|
|
695
696
|
return "loading description…"
|
|
696
697
|
|
|
697
698
|
def ui(scr):
|
|
698
|
-
|
|
699
|
+
with contextlib.suppress(curses.error):
|
|
699
700
|
curses.curs_set(0)
|
|
700
|
-
except curses.error:
|
|
701
|
-
pass
|
|
702
701
|
scr.timeout(80) # short poll so a finished lazy-load redraws promptly
|
|
703
702
|
th = _aurora_theme(curses)
|
|
704
703
|
|
|
705
704
|
def put(y, x, s, attr=0): # clip-safe cell writer
|
|
706
705
|
if 0 <= y < _h and 0 <= x < _w - 1 and s:
|
|
707
|
-
|
|
706
|
+
with contextlib.suppress(curses.error):
|
|
708
707
|
scr.addnstr(y, x, s, _w - 1 - x, attr)
|
|
709
|
-
except curses.error:
|
|
710
|
-
pass
|
|
711
708
|
|
|
712
709
|
filt, sel, detail = "", 0, False
|
|
713
710
|
selected: set = set()
|
|
@@ -979,7 +976,7 @@ def cmd_count(argv):
|
|
|
979
976
|
dpath = _discovery_path()
|
|
980
977
|
if dpath.exists():
|
|
981
978
|
try:
|
|
982
|
-
discovery = len(json.loads(dpath.read_text()).get("items") or [])
|
|
979
|
+
discovery = len(json.loads(dpath.read_text(encoding="utf-8")).get("items") or [])
|
|
983
980
|
except (json.JSONDecodeError, OSError):
|
|
984
981
|
discovery = None
|
|
985
982
|
if args.as_json:
|
|
@@ -31,7 +31,7 @@ def _read(p: Path) -> str:
|
|
|
31
31
|
try:
|
|
32
32
|
return Path(p).read_text(encoding="utf-8", errors="replace")
|
|
33
33
|
except OSError as e:
|
|
34
|
-
raise BoostError("cannot read %s: %s" % (_tilde(p), e))
|
|
34
|
+
raise BoostError("cannot read %s: %s" % (_tilde(p), e)) from e
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
def _resolve_skill_md(name: str):
|
|
@@ -115,7 +115,7 @@ def _kind_table(heading, items, extra=None):
|
|
|
115
115
|
row.append(str(e.get(extra[1], "") or ""))
|
|
116
116
|
rows.append(tuple(row))
|
|
117
117
|
if extra:
|
|
118
|
-
headers = headers
|
|
118
|
+
headers = (*headers, extra[0])
|
|
119
119
|
out.table(rows, headers=headers)
|
|
120
120
|
noun = heading.split()[-1][:-1] # "installed rules" -> "rule"
|
|
121
121
|
print(" " + out.aurora("%d %s%s installed"
|
|
@@ -319,10 +319,10 @@ def cmd_edit(argv):
|
|
|
319
319
|
editor = os.environ.get("VISUAL") or os.environ.get("EDITOR") or "vi"
|
|
320
320
|
cmd = shlex.split(editor) or ["vi"] # support EDITOR="code -w" etc.
|
|
321
321
|
try:
|
|
322
|
-
rc = subprocess.call(cmd
|
|
322
|
+
rc = subprocess.call([*cmd, str(path)])
|
|
323
323
|
except OSError as e:
|
|
324
324
|
raise BoostError("cannot launch editor %r: %s" % (editor, e),
|
|
325
|
-
hint="set $VISUAL or $EDITOR to a valid command")
|
|
325
|
+
hint="set $VISUAL or $EDITOR to a valid command") from e
|
|
326
326
|
if rc != 0:
|
|
327
327
|
out.warn("editor exited with status %d" % rc)
|
|
328
328
|
sha = util.sha256_dir(sdir)
|
|
@@ -595,9 +595,11 @@ def cmd_deps(argv):
|
|
|
595
595
|
unmet, pairs, seen = [], [], set()
|
|
596
596
|
for name in sorted(inst):
|
|
597
597
|
meta = _skill_meta(name) or {}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
598
|
+
unmet.extend(
|
|
599
|
+
{"skill": name, "requires": r}
|
|
600
|
+
for r in _as_list(meta.get("requires"))
|
|
601
|
+
if r not in inst
|
|
602
|
+
)
|
|
601
603
|
for c_name in _as_list(meta.get("conflicts")):
|
|
602
604
|
if c_name in inst:
|
|
603
605
|
key = tuple(sorted((name, c_name)))
|
|
@@ -22,6 +22,7 @@ from ..core import (ai, catalog, frontmatter, gitutil, imperative, journal,
|
|
|
22
22
|
lockfile, paths, store, util)
|
|
23
23
|
from ..core import output as out
|
|
24
24
|
from ..errors import BoostError
|
|
25
|
+
import contextlib
|
|
25
26
|
|
|
26
27
|
# ---------------------------------------------------------------- helpers
|
|
27
28
|
|
|
@@ -60,14 +61,14 @@ def _load_state(fname: str, default: dict) -> dict:
|
|
|
60
61
|
if not p.exists():
|
|
61
62
|
return json.loads(json.dumps(default))
|
|
62
63
|
try:
|
|
63
|
-
return json.loads(p.read_text())
|
|
64
|
+
return json.loads(p.read_text(encoding="utf-8"))
|
|
64
65
|
except (json.JSONDecodeError, OSError):
|
|
65
66
|
return json.loads(json.dumps(default))
|
|
66
67
|
|
|
67
68
|
|
|
68
69
|
def _save_state(fname: str, data: dict) -> None:
|
|
69
70
|
paths.ensure_dirs()
|
|
70
|
-
(paths.state_dir() / fname).write_text(json.dumps(data, indent=2) + "\n")
|
|
71
|
+
(paths.state_dir() / fname).write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
|
|
71
72
|
|
|
72
73
|
|
|
73
74
|
def _install_generated(name: str, text: str) -> None:
|
|
@@ -75,7 +76,7 @@ def _install_generated(name: str, text: str) -> None:
|
|
|
75
76
|
with tempfile.TemporaryDirectory(prefix="boost-gen-") as td:
|
|
76
77
|
src = Path(td) / name
|
|
77
78
|
src.mkdir()
|
|
78
|
-
(src / "SKILL.md").write_text(text)
|
|
79
|
+
(src / "SKILL.md").write_text(text, encoding="utf-8")
|
|
79
80
|
res = store.install_from_path(src, name=name, tap_label="local")
|
|
80
81
|
out.ok("installed %s → %s" % (name, _tilde(res.dest)))
|
|
81
82
|
if res.linked:
|
|
@@ -88,7 +89,7 @@ def _write_generated(dest: Path, text: str) -> bool:
|
|
|
88
89
|
out.info("aborted — %s left untouched" % _tilde(dest))
|
|
89
90
|
return False
|
|
90
91
|
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
91
|
-
dest.write_text(text)
|
|
92
|
+
dest.write_text(text, encoding="utf-8")
|
|
92
93
|
out.ok("wrote %s" % _tilde(dest))
|
|
93
94
|
return True
|
|
94
95
|
|
|
@@ -649,7 +650,7 @@ def cmd_evolve(argv: List[str]) -> int:
|
|
|
649
650
|
if not args.apply:
|
|
650
651
|
out.info(out.role("re-run with --apply to write these changes", "muted"))
|
|
651
652
|
return 0
|
|
652
|
-
skill_md.write_text(new)
|
|
653
|
+
skill_md.write_text(new, encoding="utf-8")
|
|
653
654
|
entry["sha256"] = util.sha256_dir(store.skill_store_dir(args.name))
|
|
654
655
|
entry["updated_at"] = util.now_iso()
|
|
655
656
|
entry["version"] = new_ver
|
|
@@ -777,9 +778,8 @@ def cmd_context(argv: List[str]) -> int:
|
|
|
777
778
|
inst = lockfile.installed()
|
|
778
779
|
for name in sorted(_mentioned_skills(state)):
|
|
779
780
|
entry = inst.get(name)
|
|
780
|
-
if entry and not entry.get("quarantined"):
|
|
781
|
-
|
|
782
|
-
restored += 1
|
|
781
|
+
if entry and not entry.get("quarantined") and store.link_agents(name).linked:
|
|
782
|
+
restored += 1
|
|
783
783
|
state["enabled"] = False
|
|
784
784
|
_save_state(_CONTEXT_STATE, state)
|
|
785
785
|
journal.log("context", "disable", restored=restored)
|
|
@@ -1005,10 +1005,8 @@ def _repo_activity(since: str) -> Tuple[Optional[int], Optional[int]]:
|
|
|
1005
1005
|
proc = gitutil.run(["rev-list", "--count", "--since=" + since, "HEAD"],
|
|
1006
1006
|
cwd=Path.cwd(), check=False)
|
|
1007
1007
|
if proc.returncode == 0:
|
|
1008
|
-
|
|
1008
|
+
with contextlib.suppress(ValueError):
|
|
1009
1009
|
commits = int(proc.stdout.strip() or 0)
|
|
1010
|
-
except ValueError:
|
|
1011
|
-
pass
|
|
1012
1010
|
proc = gitutil.run(["log", "--name-only", "--since=" + since,
|
|
1013
1011
|
"--pretty=format:"], cwd=Path.cwd(), check=False)
|
|
1014
1012
|
if proc.returncode == 0:
|
|
@@ -22,14 +22,7 @@ from ..core import output as out
|
|
|
22
22
|
from ..errors import BoostError
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
"""Contract $HOME to ~ for display (also matches the resolved home,
|
|
27
|
-
so /private/var vs /var symlinks on macOS still contract)."""
|
|
28
|
-
s = str(p)
|
|
29
|
-
for h in (str(paths.home()), str(paths.home().resolve())):
|
|
30
|
-
if s == h or s.startswith(h + os.sep):
|
|
31
|
-
return "~" + s[len(h):]
|
|
32
|
-
return s
|
|
25
|
+
_tilde = paths.tilde
|
|
33
26
|
|
|
34
27
|
|
|
35
28
|
def _plural(n: int, word: str) -> str:
|
|
@@ -338,7 +331,7 @@ def cmd_sync(argv: List[str]) -> int:
|
|
|
338
331
|
for name in orphans:
|
|
339
332
|
target = store.skill_store_dir(name)
|
|
340
333
|
if target.is_dir():
|
|
341
|
-
|
|
334
|
+
util.rmtree(target)
|
|
342
335
|
journal.log("prune", name)
|
|
343
336
|
pruned.append(name)
|
|
344
337
|
left = [n for n in orphans if n not in pruned]
|
|
@@ -572,10 +565,10 @@ def _bundle_dump(file: Optional[str]) -> int:
|
|
|
572
565
|
return 0
|
|
573
566
|
dest = paths.expand(file)
|
|
574
567
|
try:
|
|
575
|
-
dest.write_text(text)
|
|
568
|
+
dest.write_text(text, encoding="utf-8")
|
|
576
569
|
except OSError as e:
|
|
577
570
|
raise BoostError("cannot write %s: %s" % (_tilde(dest), e.strerror or e),
|
|
578
|
-
hint="check the path exists and is writable")
|
|
571
|
+
hint="check the path exists and is writable") from e
|
|
579
572
|
n_taps = sum(1 for ln in text.splitlines() if ln.startswith("tap "))
|
|
580
573
|
n_skills = sum(1 for ln in text.splitlines() if ln.startswith("skill "))
|
|
581
574
|
out.ok("wrote %s (%s, %s)" % (_tilde(dest), _plural(n_taps, "tap"),
|
|
@@ -596,9 +589,9 @@ def _bundle_install(file: Optional[str]) -> int:
|
|
|
596
589
|
hint="point at the Boostfile itself, "
|
|
597
590
|
"or use `boost import` for skill directories")
|
|
598
591
|
try:
|
|
599
|
-
text, label = path.read_text(), str(path)
|
|
592
|
+
text, label = path.read_text(encoding="utf-8"), str(path)
|
|
600
593
|
except OSError as e:
|
|
601
|
-
raise BoostError("cannot read %s: %s" % (_tilde(path), e.strerror or e))
|
|
594
|
+
raise BoostError("cannot read %s: %s" % (_tilde(path), e.strerror or e)) from e
|
|
602
595
|
taps_added = installed_n = present = failed = 0
|
|
603
596
|
have_taps = {t.name for t in registry.list_taps()}
|
|
604
597
|
have_skills = set(lockfile.installed())
|
|
@@ -880,7 +873,7 @@ def _snapshot_save(label: Optional[str]) -> int:
|
|
|
880
873
|
manifest = {"id": snap_id, "label": label or "", "created": util.now_iso(),
|
|
881
874
|
"skills": skill_count}
|
|
882
875
|
(paths.snapshots_dir() / (snap_id + ".json")).write_text(
|
|
883
|
-
json.dumps(manifest, indent=2) + "\n")
|
|
876
|
+
json.dumps(manifest, indent=2) + "\n", encoding="utf-8")
|
|
884
877
|
journal.log("snapshot", snap_id, label=label)
|
|
885
878
|
out.ok("saved %s (%s, %s)" % (snap_id, _plural(skill_count, "skill"),
|
|
886
879
|
util.human_size(tar_path.stat().st_size)))
|
|
@@ -900,7 +893,7 @@ def _snapshot_list(as_json: bool) -> int:
|
|
|
900
893
|
meta = {}
|
|
901
894
|
if side.exists():
|
|
902
895
|
try:
|
|
903
|
-
meta = json.loads(side.read_text())
|
|
896
|
+
meta = json.loads(side.read_text(encoding="utf-8"))
|
|
904
897
|
except (json.JSONDecodeError, OSError):
|
|
905
898
|
meta = {}
|
|
906
899
|
snaps.append({"id": snap_id, "created": meta.get("created", ""),
|
|
@@ -936,21 +929,21 @@ def _snapshot_restore(snap_id: str) -> int:
|
|
|
936
929
|
# Read the whole archive BEFORE touching the store, so a corrupt
|
|
937
930
|
# snapshot can never leave us with an emptied environment.
|
|
938
931
|
try:
|
|
939
|
-
tf = tarfile.open(str(tar_path), "r:gz")
|
|
932
|
+
tf = tarfile.open(str(tar_path), "r:gz") # noqa: SIM115 (opened in a try to translate the error; used via `with tf:` below)
|
|
940
933
|
except (tarfile.TarError, OSError, EOFError) as e:
|
|
941
934
|
raise BoostError("snapshot %s is unreadable: %s" % (snap_id, e),
|
|
942
935
|
hint="the store was left untouched — "
|
|
943
|
-
"see `boost snapshot list` for other snapshots")
|
|
936
|
+
"see `boost snapshot list` for other snapshots") from e
|
|
944
937
|
with tf:
|
|
945
938
|
try:
|
|
946
939
|
members = tf.getmembers()
|
|
947
940
|
except (tarfile.TarError, OSError, EOFError) as e:
|
|
948
941
|
raise BoostError("snapshot %s is corrupt: %s" % (snap_id, e),
|
|
949
942
|
hint="the store was left untouched — "
|
|
950
|
-
"see `boost snapshot list` for other snapshots")
|
|
943
|
+
"see `boost snapshot list` for other snapshots") from e
|
|
951
944
|
for child in root.iterdir():
|
|
952
945
|
if child.is_dir() and not child.is_symlink():
|
|
953
|
-
|
|
946
|
+
util.rmtree(child)
|
|
954
947
|
else:
|
|
955
948
|
child.unlink()
|
|
956
949
|
try:
|
|
@@ -1006,7 +999,7 @@ def cmd_export(argv: List[str]) -> int:
|
|
|
1006
999
|
for name in chosen:
|
|
1007
1000
|
sdir = store.skill_store_dir(name)
|
|
1008
1001
|
for f in sorted(p for p in sdir.rglob("*") if p.is_file()):
|
|
1009
|
-
zf.write(str(f), arcname="%s/%s" % (name, f.relative_to(sdir)))
|
|
1002
|
+
zf.write(str(f), arcname="%s/%s" % (name, f.relative_to(sdir).as_posix()))
|
|
1010
1003
|
else:
|
|
1011
1004
|
with tarfile.open(str(dest), "w:gz") as tf:
|
|
1012
1005
|
data = manifest.encode()
|
|
@@ -1019,7 +1012,7 @@ def cmd_export(argv: List[str]) -> int:
|
|
|
1019
1012
|
tf.add(str(store.skill_store_dir(name)), arcname=name)
|
|
1020
1013
|
except OSError as e:
|
|
1021
1014
|
raise BoostError("cannot write %s: %s" % (_tilde(dest), e.strerror or e),
|
|
1022
|
-
hint="check the output path exists and is writable")
|
|
1015
|
+
hint="check the output path exists and is writable") from e
|
|
1023
1016
|
out.ok("exported %s → %s (%s)" % (_plural(len(chosen), "skill"),
|
|
1024
1017
|
_tilde(dest.resolve()),
|
|
1025
1018
|
util.human_size(dest.stat().st_size)))
|
|
@@ -1070,7 +1063,7 @@ def cmd_adapt(argv: List[str]) -> int:
|
|
|
1070
1063
|
util.atomic_write_text(dest, source)
|
|
1071
1064
|
except OSError as e:
|
|
1072
1065
|
raise BoostError("cannot write %s: %s" % (_tilde(dest), e.strerror or e),
|
|
1073
|
-
hint="check the output path exists and is writable")
|
|
1066
|
+
hint="check the output path exists and is writable") from e
|
|
1074
1067
|
out.ok("adapted %s → %s (%s · %s)" % (display, _tilde(dest.resolve()),
|
|
1075
1068
|
args.to, model or "framework default"))
|
|
1076
1069
|
else:
|