boost-skill-cli 1.0.199__tar.gz → 1.0.201__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.199/boost_skill_cli.egg-info → boost_skill_cli-1.0.201}/PKG-INFO +1 -1
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/_version.py +2 -2
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/commands/pkg.py +39 -7
- boost_skill_cli-1.0.201/boost_cli/core/adapters.py +564 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201/boost_skill_cli.egg-info}/PKG-INFO +1 -1
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_skill_cli.egg-info/SOURCES.txt +1 -0
- boost_skill_cli-1.0.201/docs/roadmap/items/finish-mutation-hardening-across-core.md +31 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/framework-adapter-multi-agent.md +3 -3
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap.html +19 -7
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_cli_adapt.py +55 -0
- boost_skill_cli-1.0.201/tests/unit/test_adapters_multi.py +380 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_agents.py +7 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_ai.py +4 -1
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_catalog.py +40 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_config.py +18 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_lockfile.py +30 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_output.py +6 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_paths.py +13 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_policy.py +35 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_registry.py +13 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_util.py +72 -0
- boost_skill_cli-1.0.199/boost_cli/core/adapters.py +0 -294
- boost_skill_cli-1.0.199/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -19
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/.gitattributes +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/.gitignore +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/.gitleaks.toml +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/.htmlvalidate.json +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/.lighthouserc.json +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/.lycheeignore +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/.markdownlint-cli2.jsonc +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/.pre-commit-config.yaml +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/.stylelintrc.json +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/.vale/styles/boost/Terminology.yml +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/.vale/styles/config/vocabularies/boost/accept.txt +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/.vale.ini +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/CLAUDE.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/CONTRIBUTING.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/LICENSE +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/MANIFEST.in +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/Makefile +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/README.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/SECURITY.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/__init__.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/__main__.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/cli.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/cliparse.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/commands/__init__.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/commands/_common.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/commands/bmad.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/commands/configuration.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/commands/discovery.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/commands/hooks.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/commands/info.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/commands/intelligence.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/commands/quality.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/commands/run.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/commands/safety.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/commands/taps.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/commands/team.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/__init__.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/agents.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/ai.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/capabilities.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/catalog.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/claude_settings.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/config.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/dense.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/ed25519.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/embed.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/faithfulness.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/frontmatter.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/gitutil.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/imperative.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/injectscan.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/integrity.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/journal.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/lockfile.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/logs.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/mcp.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/minisign.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/nethttp.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/output.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/paths.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/policy.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/projectlock.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/provenance.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/rag.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/registry.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/rules.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/scopes.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/secretscan.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/serve.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/stackprobe.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/staleness.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/store.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/typosquat.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/updatediff.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/util.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/core/workflows.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/data/registries.json +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/errors.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_cli/spin.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_skill_cli.egg-info/entry_points.txt +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_skill_cli.egg-info/requires.txt +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/boost_skill_cli.egg-info/top_level.txt +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/.claude/settings.local.json +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/DEBUGGING.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/adapters.html +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/commands.html +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/demo.gif +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/demo.tape +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/design-roadmap.html +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/eval.html +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/index.html +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/mcp-hub.html +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/rag-architecture.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D01.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D02.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D03.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D04.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D05.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D06.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D07.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D08.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D09.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D10.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D11.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D12.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D13.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D14.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D15.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D16.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D17.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D18.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D19.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D20.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D21.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D22.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D23.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D24.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D25.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/BOOST-D26.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/boost-run-live-agents.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/command-reference-docs-site.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/html-validation-html-validate.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/install-scope-user-or-project.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/mcp-search-before-reinventing.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/pin-the-lint-toolchain.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/project-scope-across-every-command.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/project-scope-symlink-escape-on-write.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/typo-detection-codespell.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/update-diff-before-apply.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/docs/roadmap/items/workspace-scope-install.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/eslint.config.mjs +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/examples/README.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/examples/adapt-demo.sh +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/examples/boost-run-prototype.sh +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/index.html +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/noxfile.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/pyproject.toml +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/requirements/lint-tools.txt +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/scripts/bench_cli.sh +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/scripts/build_command_reference.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/scripts/build_registries.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/scripts/build_roadmap.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/scripts/check_anchors.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/scripts/ensure_eval_corpus.sh +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/scripts/eval_explain.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/scripts/eval_recommend.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/scripts/eval_retrieval.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/scripts/eval_stats_summary.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/scripts/import_budget.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/scripts/mutation_gate.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/scripts/perf_gate.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/setup.cfg +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/style/README.md +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/style/boost.css +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/style/boost.js +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/style/demo.html +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/bdd/features/adapt.feature +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/bdd/features/browse.feature +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/bdd/features/count.feature +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/bdd/features/discover.feature +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/bdd/features/doctor.feature +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/bdd/features/environment.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/bdd/features/explain.feature +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/bdd/features/index.feature +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/bdd/features/install.feature +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/bdd/features/list.feature +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/bdd/features/mcp.feature +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/bdd/features/search.feature +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/bdd/features/steps/cli_steps.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/bdd/features/steps/discovery_steps.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/bdd/features/steps/mcp_steps.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/bdd/features/steps/quality_steps.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/conftest.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/eval/baseline.json +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/eval/explain.jsonl +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/eval/golden.jsonl +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/eval/recommend.jsonl +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/eval/taps.txt +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_capabilities_policy.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_cli_bmad.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_cli_configuration.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_cli_discovery.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_cli_hooks.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_cli_info.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_cli_intelligence.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_cli_pkg.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_cli_quality.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_cli_taps.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_cli_team.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_everyday_loop.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_integrity_enforce.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_property_parsers.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_run.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_tap_signing.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/functional/test_workspace_scope.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/make_fixture.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/perf/test_benchmarks.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/smoke.sh +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_adapters.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_adapters_runner.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_capabilities.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_check_anchors.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_claude_settings.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_cliparse.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_command_reference_fresh.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_dense.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_dense_fallback.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_docs_pages_linked.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_ed25519.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_embed.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_errors_and_cli_table.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_eval_stats_summary.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_faithfulness.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_frontmatter.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_gitleaks_config.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_gitutil.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_imperative.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_import_budget.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_injectscan.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_integrity.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_journal.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_logs.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_mcp.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_minisign.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_mutation_hardening.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_nethttp.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_perf_gate.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_pkg_confusions.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_pkg_injection.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_pkg_secrets.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_projectlock.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_provenance.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_rag.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_registries_fresh.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_roadmap_fresh.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_rules.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_scopes.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_secretscan.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_serve.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_spin.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_stackprobe.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_staleness.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_store.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_token_parity.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_typosquat.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_updatediff.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_version.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/unit/test_workflows.py +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/visual/package.json +0 -0
- {boost_skill_cli-1.0.199 → boost_skill_cli-1.0.201}/tests/visual/visual_check.mjs +0 -0
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '1.0.
|
|
22
|
-
__version_tuple__ = version_tuple = (1, 0,
|
|
21
|
+
__version__ = version = '1.0.201'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 0, 201)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -1093,9 +1093,15 @@ def cmd_export(argv: List[str]) -> int:
|
|
|
1093
1093
|
return 0
|
|
1094
1094
|
|
|
1095
1095
|
|
|
1096
|
-
def
|
|
1097
|
-
"""(
|
|
1098
|
-
|
|
1096
|
+
def _resolve_skill(name: str):
|
|
1097
|
+
"""(display, description, body, skill_md_path, meta) for a skill.
|
|
1098
|
+
|
|
1099
|
+
Resolves the installed store first, then any tap clone, and returns the
|
|
1100
|
+
SKILL.md path + parsed frontmatter alongside the display fields so callers
|
|
1101
|
+
that need the skill's directory (e.g. subagent discovery for multi-agent
|
|
1102
|
+
adaptation) don't re-resolve. Raises BoostError if the name resolves
|
|
1103
|
+
nowhere.
|
|
1104
|
+
"""
|
|
1099
1105
|
p = store.skill_store_dir(name) / "SKILL.md"
|
|
1100
1106
|
if not p.exists():
|
|
1101
1107
|
entry = catalog.resolve_one(name) # raises BoostError if unknown
|
|
@@ -1105,7 +1111,14 @@ def _resolve_skill_source(name: str):
|
|
|
1105
1111
|
hint="refresh the tap with `boost update`")
|
|
1106
1112
|
meta, body = frontmatter.parse(p.read_text(encoding="utf-8", errors="replace"))
|
|
1107
1113
|
display = str(meta.get("name") or name).strip() or name
|
|
1108
|
-
return display, str(meta.get("description") or "").strip(), body
|
|
1114
|
+
return display, str(meta.get("description") or "").strip(), body, p, meta
|
|
1115
|
+
|
|
1116
|
+
|
|
1117
|
+
def _resolve_skill_source(name: str):
|
|
1118
|
+
"""(display_name, description, body) for a skill — the text-only view of
|
|
1119
|
+
:func:`_resolve_skill`, used where the skill's directory isn't needed."""
|
|
1120
|
+
display, description, body, _p, _meta = _resolve_skill(name)
|
|
1121
|
+
return display, description, body
|
|
1109
1122
|
|
|
1110
1123
|
|
|
1111
1124
|
def cmd_adapt(argv: List[str]) -> int:
|
|
@@ -1129,8 +1142,26 @@ def cmd_adapt(argv: List[str]) -> int:
|
|
|
1129
1142
|
model = args.model if args.model is not None else str(config.get("ai.model") or "")
|
|
1130
1143
|
if model.strip().lower() in ("none", "off", ""):
|
|
1131
1144
|
model = None
|
|
1132
|
-
display, description, body =
|
|
1133
|
-
|
|
1145
|
+
display, description, body, skill_md, meta = _resolve_skill(args.name)
|
|
1146
|
+
# A skill that declares subagents projects to a runnable multi-agent
|
|
1147
|
+
# workflow (a CrewAI Crew / LangGraph StateGraph) when the target supports
|
|
1148
|
+
# one; flat skills — and multi-agent targets without a crew path — keep the
|
|
1149
|
+
# single-Agent render.
|
|
1150
|
+
subagents = adapters.discover_subagents(skill_md.parent)
|
|
1151
|
+
crew_size = 0
|
|
1152
|
+
if subagents and adapters.supports_multi(args.to):
|
|
1153
|
+
primary = adapters.AgentSpec(display, description, body,
|
|
1154
|
+
adapters.parse_tools(meta))
|
|
1155
|
+
source = adapters.render_multi(args.to, display, description,
|
|
1156
|
+
[primary, *subagents], model)
|
|
1157
|
+
crew_size = len(subagents) + 1
|
|
1158
|
+
else:
|
|
1159
|
+
if subagents:
|
|
1160
|
+
sys.stderr.write(
|
|
1161
|
+
"note: %s declares %d subagent(s); %s has no crew/graph path, "
|
|
1162
|
+
"so only its primary agent was rendered.\n"
|
|
1163
|
+
% (display, len(subagents), args.to))
|
|
1164
|
+
source = adapters.render(args.to, display, description, body, model)
|
|
1134
1165
|
if args.out:
|
|
1135
1166
|
dest = paths.expand(args.out)
|
|
1136
1167
|
try:
|
|
@@ -1138,8 +1169,9 @@ def cmd_adapt(argv: List[str]) -> int:
|
|
|
1138
1169
|
except OSError as e:
|
|
1139
1170
|
raise BoostError("cannot write %s: %s" % (_tilde(dest), e.strerror or e),
|
|
1140
1171
|
hint="check the output path exists and is writable") from e
|
|
1172
|
+
shape = "crew of %d" % crew_size if crew_size else args.to
|
|
1141
1173
|
out.ok("adapted %s → %s (%s · %s)" % (display, _tilde(dest.resolve()),
|
|
1142
|
-
|
|
1174
|
+
shape, model or "framework default"))
|
|
1143
1175
|
else:
|
|
1144
1176
|
sys.stdout.write(source)
|
|
1145
1177
|
return 0
|
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
"""Render a boost skill into another agent framework's native source.
|
|
2
|
+
|
|
3
|
+
boost installs skills as files for editor-style agents (Claude Code, Cursor,
|
|
4
|
+
Windsurf). Frameworks like CrewAI or the OpenAI Agents SDK are *application
|
|
5
|
+
code* — they have no skills directory to install into; an agent is a value
|
|
6
|
+
constructed in a Python source file. `boost adapt <name> --to <framework>`
|
|
7
|
+
bridges that gap by emitting the framework's own idiom.
|
|
8
|
+
|
|
9
|
+
Each renderer is a pure, deterministic string transform: (name, description,
|
|
10
|
+
body) -> valid Python source. No framework is imported here — the emitted text
|
|
11
|
+
is a template, so the stdlib-only, zero-dependency runtime contract holds. The
|
|
12
|
+
generated code's *validity* is what the tests pin (it must `compile()`); whether
|
|
13
|
+
a given framework version accepts the kwargs is verified out-of-gate, with that
|
|
14
|
+
framework installed.
|
|
15
|
+
"""
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import collections
|
|
19
|
+
import json
|
|
20
|
+
import keyword
|
|
21
|
+
import re
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import Callable, Dict, List, Optional
|
|
24
|
+
|
|
25
|
+
from . import frontmatter
|
|
26
|
+
|
|
27
|
+
# Public: the format id shown in `--to`/errors -> its renderer.
|
|
28
|
+
# Populated at the bottom once the render_* functions are defined.
|
|
29
|
+
FORMATS: Dict[str, "Callable[..., str]"] = {}
|
|
30
|
+
|
|
31
|
+
# Subagent (crew member) directories: a Markdown file under one of these, at any
|
|
32
|
+
# depth beneath a skill, is one of the skill's subagents — so both a flat
|
|
33
|
+
# `agents/reviewer.md` and a plugin-style `plugins/x/agents/reviewer.md` match.
|
|
34
|
+
SUBAGENT_DIRS = {"agents", "subagents"}
|
|
35
|
+
# Frontmatter keys a skill/subagent uses to declare the tools it can call.
|
|
36
|
+
_TOOL_KEYS = ("tools", "allowed-tools", "allowed_tools")
|
|
37
|
+
|
|
38
|
+
# One agent in a (possibly multi-agent) skill: its display name, one-line
|
|
39
|
+
# description/role, full instruction body, and declared tool identifiers. Built
|
|
40
|
+
# via collections.namedtuple (an assignment, so interrogate needs no docstring)
|
|
41
|
+
# rather than a NamedTuple subclass.
|
|
42
|
+
AgentSpec = collections.namedtuple("AgentSpec",
|
|
43
|
+
"name description instructions tools")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def formats() -> List[str]:
|
|
47
|
+
"""Sorted list of supported target framework ids (for help/errors)."""
|
|
48
|
+
return sorted(FORMATS)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def render(fmt: str, name: str, description: str, body: str,
|
|
52
|
+
model: Optional[str] = None) -> str:
|
|
53
|
+
"""Dispatch to the renderer for `fmt`. Raises KeyError on unknown fmt.
|
|
54
|
+
|
|
55
|
+
`model` (a boost/LiteLLM model id) wires the emitted agent to a specific
|
|
56
|
+
LLM; when falsy the agent inherits its framework's default provider. The
|
|
57
|
+
command layer turns a KeyError into a BoostError listing formats().
|
|
58
|
+
"""
|
|
59
|
+
return FORMATS[fmt](name, description, body, model)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# --- shared helpers -------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
def _py_str(s: str) -> str:
|
|
65
|
+
"""A safely-escaped Python string literal for ANY input.
|
|
66
|
+
|
|
67
|
+
JSON string syntax is a subset of Python's, so json.dumps yields a literal
|
|
68
|
+
that is valid Python too — quotes, backslashes and newlines all escaped —
|
|
69
|
+
with ensure_ascii=False keeping non-ASCII readable (and still valid). This
|
|
70
|
+
is the whole defense against a skill body that contains quotes or `\"\"\"`.
|
|
71
|
+
"""
|
|
72
|
+
return json.dumps(s, ensure_ascii=False)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _ident(name: str) -> str:
|
|
76
|
+
"""A safe Python identifier derived from a skill name.
|
|
77
|
+
|
|
78
|
+
`code-reviewer` -> `code_reviewer`; leading digits or a Python keyword get
|
|
79
|
+
an `s_` prefix so the emitted assignment target always parses.
|
|
80
|
+
"""
|
|
81
|
+
ident = re.sub(r"\W+", "_", name.strip().lower()).strip("_")
|
|
82
|
+
if not ident or ident[0].isdigit() or keyword.iskeyword(ident):
|
|
83
|
+
ident = "s_" + ident
|
|
84
|
+
return ident
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _clean(text: str) -> str:
|
|
88
|
+
"""Collapse trailing whitespace so emitted literals stay tidy."""
|
|
89
|
+
return text.strip()
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _litellm_model(model: str) -> str:
|
|
93
|
+
"""Normalize a boost model id to a LiteLLM `provider/model` string.
|
|
94
|
+
|
|
95
|
+
boost's AI bridge is Anthropic (the `claude` CLI / Anthropic API), so a bare
|
|
96
|
+
Claude id like `claude-haiku-4-5-20251001` gets an `anthropic/` prefix.
|
|
97
|
+
A value that already names a provider (`anthropic/…`, `openai/gpt-4o`) is
|
|
98
|
+
passed through unchanged. Both CrewAI and the Agents SDK route through
|
|
99
|
+
LiteLLM, so this one form serves both.
|
|
100
|
+
"""
|
|
101
|
+
m = model.strip()
|
|
102
|
+
return m if "/" in m else "anthropic/" + m
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _langchain_model(model: str) -> str:
|
|
106
|
+
"""Normalize a boost model id to a LangChain ``init_chat_model`` string.
|
|
107
|
+
|
|
108
|
+
LangGraph's ``create_react_agent`` builds its model via LangChain's
|
|
109
|
+
``init_chat_model``, which wants ``provider:model`` (colon) — not LiteLLM's
|
|
110
|
+
``provider/model`` (slash). A bare Claude id gets ``anthropic:``; a
|
|
111
|
+
litellm-style ``anthropic/x`` becomes ``anthropic:x``; a value that already
|
|
112
|
+
uses the colon form passes through.
|
|
113
|
+
"""
|
|
114
|
+
m = model.strip()
|
|
115
|
+
if ":" in m:
|
|
116
|
+
return m
|
|
117
|
+
if "/" in m:
|
|
118
|
+
return m.replace("/", ":", 1)
|
|
119
|
+
return "anthropic:" + m
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# --- multi-agent detection ------------------------------------------------
|
|
123
|
+
|
|
124
|
+
def parse_tools(meta: dict) -> List[str]:
|
|
125
|
+
"""Tool identifiers a skill/subagent declares in its frontmatter.
|
|
126
|
+
|
|
127
|
+
Reads the first present of the ``tools`` / ``allowed-tools`` keys — either a
|
|
128
|
+
YAML list or a comma/space-separated string — normalizes each entry to a
|
|
129
|
+
safe Python identifier via :func:`_ident`, and dedupes preserving first-seen
|
|
130
|
+
order. Returns ``[]`` for a skill that declares no tools (the flat case).
|
|
131
|
+
"""
|
|
132
|
+
raw = None
|
|
133
|
+
for key in _TOOL_KEYS:
|
|
134
|
+
if meta.get(key):
|
|
135
|
+
raw = meta[key]
|
|
136
|
+
break
|
|
137
|
+
if raw is None:
|
|
138
|
+
return []
|
|
139
|
+
parts = re.split(r"[,\s]+", raw.strip()) if isinstance(raw, str) else [str(x) for x in raw]
|
|
140
|
+
seen: List[str] = []
|
|
141
|
+
for part in parts:
|
|
142
|
+
part = part.strip()
|
|
143
|
+
if not part:
|
|
144
|
+
continue
|
|
145
|
+
ident = _ident(part)
|
|
146
|
+
# `s_` is _ident's sentinel for a token with no usable characters (e.g.
|
|
147
|
+
# all punctuation) — not a real tool, so drop it.
|
|
148
|
+
if not ident or ident == "s_":
|
|
149
|
+
continue
|
|
150
|
+
if ident not in seen:
|
|
151
|
+
seen.append(ident)
|
|
152
|
+
return seen
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def discover_subagents(skill_dir: Path) -> List[AgentSpec]:
|
|
156
|
+
"""Discover a skill's subagents for multi-agent adaptation.
|
|
157
|
+
|
|
158
|
+
A subagent is a Markdown file (other than ``SKILL.md``) that lives under an
|
|
159
|
+
``agents/`` or ``subagents/`` directory anywhere beneath ``skill_dir`` and
|
|
160
|
+
carries both a frontmatter ``name`` and ``description``. Files are visited in
|
|
161
|
+
sorted path order so the emitted crew/graph is deterministic. Returns the
|
|
162
|
+
subagents as :class:`AgentSpec`s — an empty list for a flat single-agent
|
|
163
|
+
skill or a missing directory.
|
|
164
|
+
"""
|
|
165
|
+
specs: List[AgentSpec] = []
|
|
166
|
+
if not skill_dir or not skill_dir.is_dir():
|
|
167
|
+
return specs
|
|
168
|
+
for path in sorted(skill_dir.rglob("*.md")):
|
|
169
|
+
if path.name == "SKILL.md":
|
|
170
|
+
continue
|
|
171
|
+
if not (SUBAGENT_DIRS & {part.lower() for part in path.parent.parts}):
|
|
172
|
+
continue
|
|
173
|
+
try:
|
|
174
|
+
meta, body = frontmatter.parse(
|
|
175
|
+
path.read_text(encoding="utf-8", errors="replace"))
|
|
176
|
+
except OSError:
|
|
177
|
+
continue
|
|
178
|
+
name = str(meta.get("name") or "").strip()
|
|
179
|
+
description = str(meta.get("description") or "").strip()
|
|
180
|
+
if not name or not description:
|
|
181
|
+
continue
|
|
182
|
+
specs.append(AgentSpec(name, description, _clean(body), parse_tools(meta)))
|
|
183
|
+
return specs
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _unique_idents(specs: List[AgentSpec]) -> List[str]:
|
|
187
|
+
"""A unique Python identifier per spec, in order — two agents whose names
|
|
188
|
+
normalize to the same ident get numeric suffixes so emitted assignments and
|
|
189
|
+
node names never collide."""
|
|
190
|
+
counts: Dict[str, int] = {}
|
|
191
|
+
idents: List[str] = []
|
|
192
|
+
for spec in specs:
|
|
193
|
+
base = _ident(spec.name)
|
|
194
|
+
if base in counts:
|
|
195
|
+
counts[base] += 1
|
|
196
|
+
idents.append("%s_%d" % (base, counts[base]))
|
|
197
|
+
else:
|
|
198
|
+
counts[base] = 0
|
|
199
|
+
idents.append(base)
|
|
200
|
+
return idents
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _unique_tools(specs: List[AgentSpec]) -> List[str]:
|
|
204
|
+
"""Union of every spec's declared tools, first-seen order preserved."""
|
|
205
|
+
seen: List[str] = []
|
|
206
|
+
for spec in specs:
|
|
207
|
+
for tool in spec.tools:
|
|
208
|
+
if tool not in seen:
|
|
209
|
+
seen.append(tool)
|
|
210
|
+
return seen
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
# --- renderers ------------------------------------------------------------
|
|
214
|
+
|
|
215
|
+
def render_crewai(name: str, description: str, body: str,
|
|
216
|
+
model: Optional[str] = None) -> str:
|
|
217
|
+
"""A CrewAI Agent: role=name, goal=description, backstory=instructions.
|
|
218
|
+
|
|
219
|
+
With `model`, pins the agent's LLM via `crewai.LLM` (LiteLLM under the
|
|
220
|
+
hood); without it, the agent uses CrewAI's default provider.
|
|
221
|
+
"""
|
|
222
|
+
var = _ident(name)
|
|
223
|
+
imports = "from crewai import Agent\n"
|
|
224
|
+
llm = ""
|
|
225
|
+
if model:
|
|
226
|
+
imports = "from crewai import Agent, LLM\n"
|
|
227
|
+
llm = " llm=LLM(model=%s),\n" % _py_str(_litellm_model(model))
|
|
228
|
+
return (
|
|
229
|
+
"# Generated by `boost adapt %s --to crewai`. Do not edit by hand.\n"
|
|
230
|
+
"%s"
|
|
231
|
+
"\n"
|
|
232
|
+
"%s = Agent(\n"
|
|
233
|
+
" role=%s,\n"
|
|
234
|
+
" goal=%s,\n"
|
|
235
|
+
" backstory=%s,\n"
|
|
236
|
+
"%s"
|
|
237
|
+
")\n"
|
|
238
|
+
) % (
|
|
239
|
+
name,
|
|
240
|
+
imports,
|
|
241
|
+
var,
|
|
242
|
+
_py_str(name),
|
|
243
|
+
_py_str(_clean(description)),
|
|
244
|
+
_py_str(_clean(body)),
|
|
245
|
+
llm,
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def render_agents_sdk(name: str, description: str, body: str,
|
|
250
|
+
model: Optional[str] = None) -> str:
|
|
251
|
+
"""An OpenAI Agents SDK Agent: instructions carry the skill body.
|
|
252
|
+
|
|
253
|
+
With `model`, pins the agent's LLM via the SDK's LiteLLM extension
|
|
254
|
+
(`pip install "openai-agents[litellm]"`); without it, the agent uses the
|
|
255
|
+
SDK's default OpenAI model.
|
|
256
|
+
"""
|
|
257
|
+
var = _ident(name)
|
|
258
|
+
imports = "from agents import Agent\n"
|
|
259
|
+
llm = ""
|
|
260
|
+
if model:
|
|
261
|
+
imports = ("from agents import Agent\n"
|
|
262
|
+
"from agents.extensions.models.litellm_model import LitellmModel\n")
|
|
263
|
+
llm = " model=LitellmModel(model=%s),\n" % _py_str(_litellm_model(model))
|
|
264
|
+
return (
|
|
265
|
+
"# Generated by `boost adapt %s --to agents-sdk`. Do not edit by hand.\n"
|
|
266
|
+
"%s"
|
|
267
|
+
"\n"
|
|
268
|
+
"%s = Agent(\n"
|
|
269
|
+
" name=%s,\n"
|
|
270
|
+
" handoff_description=%s,\n"
|
|
271
|
+
" instructions=%s,\n"
|
|
272
|
+
"%s"
|
|
273
|
+
")\n"
|
|
274
|
+
) % (
|
|
275
|
+
name,
|
|
276
|
+
imports,
|
|
277
|
+
var,
|
|
278
|
+
_py_str(name),
|
|
279
|
+
_py_str(_clean(description)),
|
|
280
|
+
_py_str(_clean(body)),
|
|
281
|
+
llm,
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def render_langgraph(name: str, description: str, body: str,
|
|
286
|
+
model: Optional[str] = None) -> str:
|
|
287
|
+
"""A LangGraph node factory: prebuilt ``create_react_agent`` bound to the
|
|
288
|
+
skill body as its system prompt.
|
|
289
|
+
|
|
290
|
+
Unlike CrewAI / the Agents SDK, a LangGraph agent isn't one constructor —
|
|
291
|
+
it's a node compiled with a model and dropped into a ``StateGraph``. So we
|
|
292
|
+
emit a *factory* (``make_<name>``) the caller invokes with a model and any
|
|
293
|
+
tools, rather than a module-level value. With `model`, the factory's
|
|
294
|
+
``model`` argument defaults to the normalized LiteLLM id; without it, the
|
|
295
|
+
caller must supply one (LangGraph has no default provider to inherit).
|
|
296
|
+
"""
|
|
297
|
+
var = _ident(name)
|
|
298
|
+
if model:
|
|
299
|
+
sig = "model=%s, tools=None" % _py_str(_langchain_model(model))
|
|
300
|
+
else:
|
|
301
|
+
sig = "model, tools=None"
|
|
302
|
+
return (
|
|
303
|
+
"# Generated by `boost adapt %s --to langgraph`. Do not edit by hand.\n"
|
|
304
|
+
"from langgraph.prebuilt import create_react_agent\n"
|
|
305
|
+
"\n"
|
|
306
|
+
"SYSTEM_PROMPT = %s\n"
|
|
307
|
+
"\n"
|
|
308
|
+
"\n"
|
|
309
|
+
"def make_%s(%s):\n"
|
|
310
|
+
" %s\n"
|
|
311
|
+
" return create_react_agent(model, tools=tools or [], prompt=SYSTEM_PROMPT)\n"
|
|
312
|
+
) % (
|
|
313
|
+
name,
|
|
314
|
+
_py_str(_clean(body)),
|
|
315
|
+
var,
|
|
316
|
+
sig,
|
|
317
|
+
_py_str(_clean(description)),
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
FORMATS.update({
|
|
322
|
+
"crewai": render_crewai,
|
|
323
|
+
"agents-sdk": render_agents_sdk,
|
|
324
|
+
"langgraph": render_langgraph,
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
# --- multi-agent renderers (crew / graph) ---------------------------------
|
|
329
|
+
# A flat skill projects to one Agent (above); a skill that declares subagents
|
|
330
|
+
# projects to a runnable *workflow* — a CrewAI Crew or a LangGraph StateGraph —
|
|
331
|
+
# with one agent per subagent and declared tools surfaced as stubs. Same
|
|
332
|
+
# contract as the single-agent renderers: pure text that must ``compile()``.
|
|
333
|
+
|
|
334
|
+
def _tool_stub(tool: str, decorator: str) -> str:
|
|
335
|
+
"""One tool stub — a decorated function that raises until implemented.
|
|
336
|
+
|
|
337
|
+
``decorator`` is the full decorator line (``@tool`` for LangChain,
|
|
338
|
+
``@tool("name")`` for CrewAI); the body is a docstring plus a
|
|
339
|
+
``NotImplementedError`` so the generated module ``compile()``s and fails
|
|
340
|
+
loudly rather than silently no-op'ing if run before the tool is filled in.
|
|
341
|
+
"""
|
|
342
|
+
return (
|
|
343
|
+
"%s\n"
|
|
344
|
+
"def %s(argument: str) -> str:\n"
|
|
345
|
+
" %s\n"
|
|
346
|
+
" raise NotImplementedError(%s)\n"
|
|
347
|
+
) % (decorator, tool,
|
|
348
|
+
_py_str("TODO: implement the %s tool (declared by the skill)." % tool),
|
|
349
|
+
_py_str("boost adapt: implement the '%s' tool" % tool))
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def _crew_header(kind: str, workflow: str, description: str) -> str:
|
|
353
|
+
"""The two-line generated-file banner (provenance + crew description)."""
|
|
354
|
+
summary = _clean(description).replace("\n", " ") or workflow
|
|
355
|
+
return ("# Generated by `boost adapt %s --to %s`. Do not edit by hand.\n"
|
|
356
|
+
"# %s\n") % (workflow, kind, summary)
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def render_crew(workflow: str, description: str, specs: List[AgentSpec],
|
|
360
|
+
model: Optional[str] = None) -> str:
|
|
361
|
+
"""Render a multi-agent skill as a CrewAI ``Crew``.
|
|
362
|
+
|
|
363
|
+
Each :class:`AgentSpec` becomes an ``Agent`` (role / goal / backstory) paired
|
|
364
|
+
with a ``Task``, assembled into a sequential ``Crew``. Tools any agent
|
|
365
|
+
declares are surfaced as ``NotImplementedError`` stubs to fill in. `model`
|
|
366
|
+
pins every agent's LLM via ``crewai.LLM``; without it CrewAI's default
|
|
367
|
+
provider is used. ``description`` documents the crew as a whole.
|
|
368
|
+
"""
|
|
369
|
+
idents = _unique_idents(specs)
|
|
370
|
+
tools = _unique_tools(specs)
|
|
371
|
+
imports = ["from crewai import Agent, Crew, Process, Task" + (", LLM" if model else "")]
|
|
372
|
+
if tools:
|
|
373
|
+
imports.append("from crewai.tools import tool")
|
|
374
|
+
llm_line = " llm=LLM(model=%s),\n" % _py_str(_litellm_model(model)) if model else ""
|
|
375
|
+
|
|
376
|
+
blocks: List[str] = []
|
|
377
|
+
for ident, spec in zip(idents, specs):
|
|
378
|
+
tline = " tools=[%s],\n" % ", ".join(spec.tools) if spec.tools else ""
|
|
379
|
+
blocks.append(
|
|
380
|
+
"%s = Agent(\n"
|
|
381
|
+
" role=%s,\n"
|
|
382
|
+
" goal=%s,\n"
|
|
383
|
+
" backstory=%s,\n"
|
|
384
|
+
"%s%s"
|
|
385
|
+
")\n" % (ident, _py_str(_clean(spec.name)),
|
|
386
|
+
_py_str(_clean(spec.description)),
|
|
387
|
+
_py_str(_clean(spec.instructions)), tline, llm_line))
|
|
388
|
+
for ident, spec in zip(idents, specs):
|
|
389
|
+
blocks.append(
|
|
390
|
+
"%s_task = Task(\n"
|
|
391
|
+
" description=%s,\n"
|
|
392
|
+
" expected_output=%s,\n"
|
|
393
|
+
" agent=%s,\n"
|
|
394
|
+
")\n" % (ident, _py_str(_clean(spec.description)),
|
|
395
|
+
_py_str("The result of the %s step." % _clean(spec.name)), ident))
|
|
396
|
+
crew = ("crew = Crew(\n"
|
|
397
|
+
" agents=[%s],\n"
|
|
398
|
+
" tasks=[%s],\n"
|
|
399
|
+
" process=Process.sequential,\n"
|
|
400
|
+
")\n") % (", ".join(idents), ", ".join(i + "_task" for i in idents))
|
|
401
|
+
|
|
402
|
+
parts = [_crew_header("crewai", workflow, description), "\n".join(imports) + "\n", "\n"]
|
|
403
|
+
if tools:
|
|
404
|
+
parts.append("\n".join(_tool_stub(t, "@tool(%s)" % _py_str(t)) for t in tools))
|
|
405
|
+
parts.append("\n")
|
|
406
|
+
parts.append("\n".join(blocks))
|
|
407
|
+
parts.append("\n" + crew)
|
|
408
|
+
return "".join(parts)
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def render_graph(workflow: str, description: str, specs: List[AgentSpec],
|
|
412
|
+
model: Optional[str] = None) -> str:
|
|
413
|
+
"""Render a multi-agent skill as a LangGraph ``StateGraph``.
|
|
414
|
+
|
|
415
|
+
Emits a ``build_<workflow>(model)`` factory that constructs one
|
|
416
|
+
``create_react_agent`` node per :class:`AgentSpec`, wires them into a
|
|
417
|
+
sequential graph (``START`` → … → ``END``) over ``MessagesState``, and
|
|
418
|
+
returns the compiled graph. Declared tools become ``@tool`` stubs. With
|
|
419
|
+
`model` the factory's ``model`` argument defaults to the normalized LangChain
|
|
420
|
+
id; without it the caller must supply one (LangGraph has no default
|
|
421
|
+
provider). ``description`` documents the graph.
|
|
422
|
+
"""
|
|
423
|
+
idents = _unique_idents(specs)
|
|
424
|
+
tools = _unique_tools(specs)
|
|
425
|
+
imports = ["from langgraph.graph import END, START, MessagesState, StateGraph",
|
|
426
|
+
"from langgraph.prebuilt import create_react_agent"]
|
|
427
|
+
if tools:
|
|
428
|
+
imports.append("from langchain_core.tools import tool")
|
|
429
|
+
sig = "model=%s" % _py_str(_langchain_model(model)) if model else "model"
|
|
430
|
+
|
|
431
|
+
prompts = "SYSTEM_PROMPTS = {\n%s}\n" % "".join(
|
|
432
|
+
" %s: %s,\n" % (_py_str(ident), _py_str(_clean(spec.instructions)))
|
|
433
|
+
for ident, spec in zip(idents, specs))
|
|
434
|
+
|
|
435
|
+
lines: List[str] = [' """Build and compile the %s crew as a graph."""' % workflow]
|
|
436
|
+
lines.extend(
|
|
437
|
+
" %s = create_react_agent(model, tools=[%s], prompt=SYSTEM_PROMPTS[%s])"
|
|
438
|
+
% (ident, ", ".join(spec.tools), _py_str(ident))
|
|
439
|
+
for ident, spec in zip(idents, specs))
|
|
440
|
+
lines.append("")
|
|
441
|
+
for ident in idents:
|
|
442
|
+
lines.append(" def %s_node(state):" % ident)
|
|
443
|
+
lines.append(" return {\"messages\": %s.invoke(state)[\"messages\"]}" % ident)
|
|
444
|
+
lines.append("")
|
|
445
|
+
lines.append(" builder = StateGraph(MessagesState)")
|
|
446
|
+
lines.extend(" builder.add_node(%s, %s_node)" % (_py_str(ident), ident)
|
|
447
|
+
for ident in idents)
|
|
448
|
+
prev = "START"
|
|
449
|
+
for ident in idents:
|
|
450
|
+
lines.append(" builder.add_edge(%s, %s)" % (prev, _py_str(ident)))
|
|
451
|
+
prev = _py_str(ident)
|
|
452
|
+
lines.append(" builder.add_edge(%s, END)" % prev)
|
|
453
|
+
lines.append(" return builder.compile()")
|
|
454
|
+
factory = "def build_%s(%s):\n%s\n" % (_ident(workflow), sig, "\n".join(lines))
|
|
455
|
+
|
|
456
|
+
parts = [_crew_header("langgraph", workflow, description),
|
|
457
|
+
"\n".join(imports) + "\n", "\n", prompts, "\n"]
|
|
458
|
+
if tools:
|
|
459
|
+
parts.append("\n".join(_tool_stub(t, "@tool") for t in tools))
|
|
460
|
+
parts.append("\n\n")
|
|
461
|
+
parts.append(factory)
|
|
462
|
+
return "".join(parts)
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
# Multi-agent (crew/graph) renderers, keyed by the same format id as FORMATS.
|
|
466
|
+
# A format absent here has no multi-agent path; the command layer falls back to
|
|
467
|
+
# the single-agent renderer (flattening the skill to its primary agent).
|
|
468
|
+
MULTI_FORMATS: Dict[str, "Callable[..., str]"] = {
|
|
469
|
+
"crewai": render_crew,
|
|
470
|
+
"langgraph": render_graph,
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
def supports_multi(fmt: str) -> bool:
|
|
475
|
+
"""True if `fmt` has a multi-agent (crew/graph) renderer."""
|
|
476
|
+
return fmt in MULTI_FORMATS
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def render_multi(fmt: str, workflow: str, description: str,
|
|
480
|
+
specs: List[AgentSpec], model: Optional[str] = None) -> str:
|
|
481
|
+
"""Dispatch to the crew/graph renderer for `fmt`.
|
|
482
|
+
|
|
483
|
+
Raises ``KeyError`` for a format with no multi-agent path — callers guard
|
|
484
|
+
with :func:`supports_multi` and fall back to :func:`render` (single agent).
|
|
485
|
+
"""
|
|
486
|
+
return MULTI_FORMATS[fmt](workflow, description, specs, model)
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
# A default read-only toolset appended to the adapted agent so it can *act*,
|
|
490
|
+
# not roleplay. Emitted as text (never imported here) — the framework only loads
|
|
491
|
+
# when the generated runner is executed. `chr(10)` avoids escaping newlines in
|
|
492
|
+
# this template; the inner `%s`/`%d` are runtime formatting in the emitted code
|
|
493
|
+
# and must NOT be touched by render_runner's `%` on _RUNNER_MAIN alone.
|
|
494
|
+
_RUNNER_TOOLS = '''
|
|
495
|
+
# --- boost run: default read-only tools (the agent's hands) ---
|
|
496
|
+
import pathlib as _boost_pl
|
|
497
|
+
from agents import Runner as _boost_Runner, function_tool as _boost_tool
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
@_boost_tool
|
|
501
|
+
def read_file(path: str) -> str:
|
|
502
|
+
"""Read a UTF-8 text file and return its first ~16000 characters."""
|
|
503
|
+
return _boost_pl.Path(path).read_text(encoding="utf-8", errors="replace")[:16000]
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
@_boost_tool
|
|
507
|
+
def list_dir(path: str = ".") -> str:
|
|
508
|
+
"""List a directory's entries, one per line (directories end with /)."""
|
|
509
|
+
entries = sorted(p.name + ("/" if p.is_dir() else "")
|
|
510
|
+
for p in _boost_pl.Path(path).iterdir())
|
|
511
|
+
return chr(10).join(entries)
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
@_boost_tool
|
|
515
|
+
def grep(pattern: str, path: str = ".") -> str:
|
|
516
|
+
"""Case-insensitive substring search across text files under path."""
|
|
517
|
+
root = _boost_pl.Path(path)
|
|
518
|
+
files = [root] if root.is_file() else [p for p in root.rglob("*") if p.is_file()]
|
|
519
|
+
hits = []
|
|
520
|
+
for _f in files[:500]:
|
|
521
|
+
try:
|
|
522
|
+
_text = _f.read_text(encoding="utf-8", errors="replace")
|
|
523
|
+
except OSError:
|
|
524
|
+
continue
|
|
525
|
+
for _i, _line in enumerate(_text.splitlines(), 1):
|
|
526
|
+
if pattern.lower() in _line.lower():
|
|
527
|
+
hits.append("%s:%d: %s" % (_f, _i, _line.strip()[:200]))
|
|
528
|
+
if len(hits) >= 200:
|
|
529
|
+
return chr(10).join(hits)
|
|
530
|
+
return chr(10).join(hits) or "no matches"
|
|
531
|
+
'''
|
|
532
|
+
|
|
533
|
+
_RUNNER_MAIN = '''
|
|
534
|
+
# --- boost run: wire the tools onto the adapted agent and execute ---
|
|
535
|
+
_boost_agent = Agent(name=_boost_brain.name, instructions=_boost_brain.instructions,
|
|
536
|
+
model=getattr(_boost_brain, "model", None),
|
|
537
|
+
tools=[read_file, list_dir, grep])
|
|
538
|
+
print(_boost_Runner.run_sync(_boost_agent, %s).final_output)
|
|
539
|
+
'''
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
def render_runner(name: str, description: str, body: str,
|
|
543
|
+
model: Optional[str] = None, target: Optional[str] = None) -> str:
|
|
544
|
+
"""A self-contained OpenAI Agents SDK *runner* for ``boost run``.
|
|
545
|
+
|
|
546
|
+
The adapted agent (its brain — instructions + model, via
|
|
547
|
+
:func:`render_agents_sdk`) plus a default read-only toolset (its hands) and a
|
|
548
|
+
``Runner.run_sync`` call on a prompt built from ``target``. Like the rest of
|
|
549
|
+
this module it imports no framework — the text only needs to ``compile()``;
|
|
550
|
+
``boost run`` either prints it (``--print``) or executes it where the SDK is
|
|
551
|
+
installed.
|
|
552
|
+
"""
|
|
553
|
+
brain = render_agents_sdk(name, description, body, model)
|
|
554
|
+
# Capture the adapted agent under a reserved name *before* the tool defs — a
|
|
555
|
+
# skill literally named `grep`/`read-file`/`list-dir` normalizes (_ident) to
|
|
556
|
+
# a tool identifier, and the emitted `def grep(...)` would otherwise rebind
|
|
557
|
+
# (clobber) the brain. `_boost_*` names never collide: _ident strips the
|
|
558
|
+
# leading underscore, so no skill name maps onto them.
|
|
559
|
+
capture = "\n_boost_brain = %s\n" % _ident(name)
|
|
560
|
+
tgt = _clean(target or "")
|
|
561
|
+
where = "`" + tgt + "`" if tgt else "the current directory (`.`)"
|
|
562
|
+
prompt = ("Apply your instructions to %s. Use the read_file, list_dir, and "
|
|
563
|
+
"grep tools to inspect it, then produce your output." % where)
|
|
564
|
+
return brain + capture + _RUNNER_TOOLS + (_RUNNER_MAIN % _py_str(prompt))
|
|
@@ -307,6 +307,7 @@ tests/functional/test_tap_signing.py
|
|
|
307
307
|
tests/functional/test_workspace_scope.py
|
|
308
308
|
tests/perf/test_benchmarks.py
|
|
309
309
|
tests/unit/test_adapters.py
|
|
310
|
+
tests/unit/test_adapters_multi.py
|
|
310
311
|
tests/unit/test_adapters_runner.py
|
|
311
312
|
tests/unit/test_agents.py
|
|
312
313
|
tests/unit/test_ai.py
|