boost-skill-cli 1.0.154__tar.gz → 1.0.156__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.156/.gitleaks.toml +17 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/Makefile +1 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/PKG-INFO +1 -1
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/_version.py +2 -2
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/commands/discovery.py +9 -1
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_skill_cli.egg-info/PKG-INFO +1 -1
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_skill_cli.egg-info/SOURCES.txt +4 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +3 -3
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +3 -3
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap.html +2 -2
- boost_skill_cli-1.0.156/scripts/import_budget.py +156 -0
- boost_skill_cli-1.0.156/tests/unit/test_gitleaks_config.py +59 -0
- boost_skill_cli-1.0.156/tests/unit/test_import_budget.py +135 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/.gitattributes +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/.gitignore +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/CLAUDE.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/CONTRIBUTING.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/LICENSE +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/MANIFEST.in +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/README.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/SECURITY.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/__init__.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/__main__.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/cli.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/cliparse.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/commands/__init__.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/commands/bmad.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/commands/configuration.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/commands/hooks.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/commands/info.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/commands/intelligence.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/commands/pkg.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/commands/quality.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/commands/taps.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/commands/team.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/__init__.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/adapters.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/agents.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/ai.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/catalog.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/claude_settings.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/config.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/dense.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/embed.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/frontmatter.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/gitutil.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/imperative.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/injectscan.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/journal.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/lockfile.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/logs.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/mcp.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/nethttp.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/output.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/paths.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/policy.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/rag.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/registry.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/rules.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/secretscan.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/serve.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/stackprobe.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/staleness.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/store.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/typosquat.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/updatediff.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/util.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/core/workflows.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/data/registries.json +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/errors.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_cli/spin.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_skill_cli.egg-info/entry_points.txt +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_skill_cli.egg-info/requires.txt +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/boost_skill_cli.egg-info/top_level.txt +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/.claude/settings.local.json +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/DEBUGGING.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/adapters.html +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/demo.gif +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/demo.tape +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/design-roadmap.html +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/eval.html +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/index.html +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/mcp-hub.html +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/rag-architecture.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D01.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D02.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D03.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D04.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D05.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D06.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D07.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D08.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D09.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D10.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D11.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D12.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D13.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D14.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D15.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D16.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D17.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D18.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D19.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D20.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D21.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D22.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D23.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D24.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D25.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/BOOST-D26.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/boost-run-live-agents.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/command-reference-docs-site.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/framework-adapter-multi-agent.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/html-validation-html-validate.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/install-scope-user-or-project.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/typo-detection-codespell.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/update-diff-before-apply.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/docs/roadmap/items/workspace-scope-install.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/examples/README.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/examples/adapt-demo.sh +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/examples/boost-run-prototype.sh +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/index.html +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/pyproject.toml +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/scripts/bench_cli.sh +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/scripts/build_registries.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/scripts/build_roadmap.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/scripts/ensure_eval_corpus.sh +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/scripts/eval_explain.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/scripts/eval_recommend.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/scripts/eval_retrieval.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/scripts/mutation_gate.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/setup.cfg +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/style/README.md +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/style/boost.css +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/style/boost.js +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/style/demo.html +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/bdd/features/adapt.feature +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/bdd/features/browse.feature +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/bdd/features/count.feature +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/bdd/features/discover.feature +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/bdd/features/doctor.feature +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/bdd/features/environment.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/bdd/features/explain.feature +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/bdd/features/index.feature +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/bdd/features/install.feature +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/bdd/features/list.feature +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/bdd/features/mcp.feature +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/bdd/features/search.feature +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/bdd/features/steps/cli_steps.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/bdd/features/steps/discovery_steps.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/bdd/features/steps/mcp_steps.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/bdd/features/steps/quality_steps.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/conftest.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/eval/baseline.json +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/eval/explain.jsonl +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/eval/golden.jsonl +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/eval/recommend.jsonl +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/eval/taps.txt +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/functional/test_cli_adapt.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/functional/test_cli_bmad.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/functional/test_cli_configuration.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/functional/test_cli_discovery.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/functional/test_cli_hooks.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/functional/test_cli_info.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/functional/test_cli_intelligence.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/functional/test_cli_pkg.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/functional/test_cli_quality.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/functional/test_cli_taps.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/functional/test_cli_team.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/functional/test_everyday_loop.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/functional/test_property_parsers.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/make_fixture.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/perf/test_benchmarks.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/smoke.sh +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_adapters.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_agents.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_ai.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_catalog.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_claude_settings.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_cliparse.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_config.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_dense.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_dense_fallback.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_docs_pages_linked.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_embed.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_errors_and_cli_table.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_frontmatter.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_gitutil.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_imperative.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_injectscan.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_journal.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_lockfile.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_logs.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_mcp.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_mutation_hardening.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_nethttp.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_output.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_paths.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_pkg_confusions.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_pkg_injection.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_pkg_secrets.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_policy.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_rag.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_registries_fresh.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_registry.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_roadmap_fresh.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_rules.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_secretscan.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_serve.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_spin.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_stackprobe.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_staleness.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_store.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_token_parity.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_typosquat.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_updatediff.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_util.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_version.py +0 -0
- {boost_skill_cli-1.0.154 → boost_skill_cli-1.0.156}/tests/unit/test_workflows.py +0 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# gitleaks configuration — secret-scanning gate (see .github/workflows/ci.yml).
|
|
2
|
+
#
|
|
3
|
+
# Extends gitleaks' upstream default ruleset (which covers cloud keys, tokens,
|
|
4
|
+
# private keys, high-entropy strings, …) and allowlists the one place boost
|
|
5
|
+
# ships *synthetic* secrets on purpose: its own secret-scanner test fixtures.
|
|
6
|
+
# Everything else — source, docs, real history — is scanned unmodified.
|
|
7
|
+
|
|
8
|
+
title = "boost gitleaks config"
|
|
9
|
+
|
|
10
|
+
[extend]
|
|
11
|
+
useDefault = true
|
|
12
|
+
|
|
13
|
+
[[allowlists]]
|
|
14
|
+
description = "boost's own secret-scanner tests ship synthetic private keys / tokens by design (they exist to prove core/secretscan.py flags them)"
|
|
15
|
+
paths = [
|
|
16
|
+
'''tests/unit/test_secretscan\.py''',
|
|
17
|
+
]
|
|
@@ -43,6 +43,7 @@ lint:
|
|
|
43
43
|
@command -v actionlint >/dev/null 2>&1 && actionlint || echo "actionlint not on PATH — skipping (CI enforces it)"
|
|
44
44
|
$(PY) scripts/build_registries.py --check
|
|
45
45
|
$(PY) scripts/build_roadmap.py --check
|
|
46
|
+
$(PY) scripts/import_budget.py
|
|
46
47
|
|
|
47
48
|
# Supply-chain CVE gate: fail on a known OSV/PyPI advisory in the project's
|
|
48
49
|
# dependency closure. Mirrors the pip-audit CI workflow; run before releasing.
|
|
@@ -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.156'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 0, 156)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -17,7 +17,7 @@ import urllib.parse
|
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
|
|
19
19
|
from .. import cliparse, spin
|
|
20
|
-
from ..core import (agents, ai, catalog, config,
|
|
20
|
+
from ..core import (agents, ai, catalog, config, gitutil,
|
|
21
21
|
journal, lockfile, paths, rag, registry, store, util)
|
|
22
22
|
from ..core import output as out
|
|
23
23
|
from ..core.stackprobe import detect_stack # re-exported: shared with Quality
|
|
@@ -165,6 +165,11 @@ def cmd_reindex(argv):
|
|
|
165
165
|
stats = rag.build(force=args.force)
|
|
166
166
|
dense_stats = None
|
|
167
167
|
if args.dense:
|
|
168
|
+
# Imported lazily (only on `--dense`) so the optional dense/embedding
|
|
169
|
+
# stack never loads for the common offline commands this module also
|
|
170
|
+
# holds — count, stats, trending, plain search. See the import-budget
|
|
171
|
+
# gate (scripts/import_budget.py).
|
|
172
|
+
from ..core import embed
|
|
168
173
|
with spin.Spinner("embedding chunks into the dense store"):
|
|
169
174
|
dense_stats = _reindex_dense(args.force)
|
|
170
175
|
if args.as_json:
|
|
@@ -192,6 +197,9 @@ def cmd_reindex(argv):
|
|
|
192
197
|
|
|
193
198
|
def _reindex_dense(force):
|
|
194
199
|
"""Build the dense vector store; returns stats or None when unavailable."""
|
|
200
|
+
# Local import: the dense/embedding engines are opt-in (`search --dense`),
|
|
201
|
+
# so they stay out of startup for every other command in this module.
|
|
202
|
+
from ..core import dense, embed
|
|
195
203
|
if not dense.have_backend() or not embed.available():
|
|
196
204
|
return None
|
|
197
205
|
return dense.build(force=force)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
.gitattributes
|
|
2
2
|
.gitignore
|
|
3
|
+
.gitleaks.toml
|
|
3
4
|
CLAUDE.md
|
|
4
5
|
CONTRIBUTING.md
|
|
5
6
|
LICENSE
|
|
@@ -224,6 +225,7 @@ scripts/ensure_eval_corpus.sh
|
|
|
224
225
|
scripts/eval_explain.py
|
|
225
226
|
scripts/eval_recommend.py
|
|
226
227
|
scripts/eval_retrieval.py
|
|
228
|
+
scripts/import_budget.py
|
|
227
229
|
scripts/mutation_gate.py
|
|
228
230
|
style/README.md
|
|
229
231
|
style/boost.css
|
|
@@ -280,8 +282,10 @@ tests/unit/test_docs_pages_linked.py
|
|
|
280
282
|
tests/unit/test_embed.py
|
|
281
283
|
tests/unit/test_errors_and_cli_table.py
|
|
282
284
|
tests/unit/test_frontmatter.py
|
|
285
|
+
tests/unit/test_gitleaks_config.py
|
|
283
286
|
tests/unit/test_gitutil.py
|
|
284
287
|
tests/unit/test_imperative.py
|
|
288
|
+
tests/unit/test_import_budget.py
|
|
285
289
|
tests/unit/test_injectscan.py
|
|
286
290
|
tests/unit/test_journal.py
|
|
287
291
|
tests/unit/test_lockfile.py
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
id: secret-scanning-gitleaks-push-protection
|
|
3
3
|
board: code
|
|
4
4
|
section: health
|
|
5
|
-
status:
|
|
5
|
+
status: shipped
|
|
6
6
|
category: Security · Secrets
|
|
7
7
|
complexity: S
|
|
8
8
|
impact: Med
|
|
9
9
|
wow: 3
|
|
10
10
|
note: pre-commit-able
|
|
11
11
|
order: 4
|
|
12
|
-
owner:
|
|
13
|
-
pr:
|
|
12
|
+
owner: loop/gitleaks
|
|
13
|
+
pr: 180
|
|
14
14
|
title: Secret scanning — <code>gitleaks</code> + push protection
|
|
15
15
|
---
|
|
16
16
|
Scan the full history and every PR diff for leaked tokens, keys and
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
id: startup-and-import-time-budget-x-importtime
|
|
3
3
|
board: code
|
|
4
4
|
section: compat
|
|
5
|
-
status:
|
|
5
|
+
status: shipped
|
|
6
6
|
category: Perf · Startup
|
|
7
7
|
complexity: M
|
|
8
8
|
impact: High
|
|
9
9
|
wow: 4
|
|
10
10
|
note: lazy-import guard
|
|
11
11
|
order: 5
|
|
12
|
-
owner:
|
|
13
|
-
pr:
|
|
12
|
+
owner: loop/import-budget
|
|
13
|
+
pr: 179
|
|
14
14
|
title: Startup & import-time budget — <code>-X importtime</code>
|
|
15
15
|
---
|
|
16
16
|
For a CLI, cold-start latency <em>is</em> the UX — every command pays it.
|
|
@@ -987,7 +987,7 @@ harness.</p>
|
|
|
987
987
|
</article>
|
|
988
988
|
|
|
989
989
|
<article class="cap rcard">
|
|
990
|
-
<div class="head"><span class="pill
|
|
990
|
+
<div class="head"><span class="pill shipped">Shipped</span><span class="cat">Security · Secrets</span></div>
|
|
991
991
|
<h3>Secret scanning — <code>gitleaks</code> + push protection</h3>
|
|
992
992
|
<p>Scan the full history and every PR diff for leaked tokens, keys and
|
|
993
993
|
PyPI credentials with the free <code>gitleaks</code> action, paired
|
|
@@ -1787,7 +1787,7 @@ and the work stays visible.</p>
|
|
|
1787
1787
|
</article>
|
|
1788
1788
|
|
|
1789
1789
|
<article class="cap rcard">
|
|
1790
|
-
<div class="head"><span class="pill
|
|
1790
|
+
<div class="head"><span class="pill shipped">Shipped</span><span class="cat">Perf · Startup</span></div>
|
|
1791
1791
|
<h3>Startup & import-time budget — <code>-X importtime</code></h3>
|
|
1792
1792
|
<p>For a CLI, cold-start latency <em>is</em> the UX — every command pays it.
|
|
1793
1793
|
A gate on <code>python -X importtime boost</code> catches the accidental
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Startup import-time budget — the lazy-import guard.
|
|
3
|
+
|
|
4
|
+
For a CLI, cold-start latency *is* the UX: every command pays it before it does
|
|
5
|
+
anything. This gate runs ``python -X importtime`` for a set of common, fully
|
|
6
|
+
offline commands and asserts that a denylist of heavy or optional-only modules
|
|
7
|
+
never gets imported at startup.
|
|
8
|
+
|
|
9
|
+
The classic regression it catches is the accidental *top-level* import of an
|
|
10
|
+
optional dependency — the ``[rag]`` stack (``sqlite_vec``), an embedding/AI SDK,
|
|
11
|
+
or a scientific-python tree — that a hot path only ever needs lazily. boost is
|
|
12
|
+
architected so those load inside the one function that needs them (e.g.
|
|
13
|
+
``search --dense``); this gate keeps it that way.
|
|
14
|
+
|
|
15
|
+
Deliberately name-based, not timing-based: a denylisted module is either
|
|
16
|
+
imported or it isn't, identically on a fast laptop and a slow, differently
|
|
17
|
+
CPU-throttled CI runner across every Python version — so the gate is
|
|
18
|
+
deterministic and never flakes. A coarse module-count ceiling is reported as an
|
|
19
|
+
advisory only (stdlib import graphs differ across Python versions), never a hard
|
|
20
|
+
failure.
|
|
21
|
+
|
|
22
|
+
Usage:
|
|
23
|
+
python scripts/import_budget.py # exit 1 if anything leaked
|
|
24
|
+
python scripts/import_budget.py --list # also print each command's count
|
|
25
|
+
"""
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import os
|
|
29
|
+
import subprocess
|
|
30
|
+
import sys
|
|
31
|
+
import tempfile
|
|
32
|
+
from pathlib import Path
|
|
33
|
+
from typing import Dict, List, Set
|
|
34
|
+
|
|
35
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
36
|
+
|
|
37
|
+
# Common commands that must stay lean. All are fully offline and touch the core
|
|
38
|
+
# dispatch + store/catalog paths, so a leak anywhere in that surface is caught.
|
|
39
|
+
COMMANDS: List[List[str]] = [["--help"], ["--version"], ["list"], ["count"]]
|
|
40
|
+
|
|
41
|
+
# Modules that must NEVER load for the commands above. Heavy C extensions,
|
|
42
|
+
# scientific-python, and the embedding/AI SDKs — plus boost's own optional-only
|
|
43
|
+
# engines, which stay lazy behind `search --dense`. A leak means a hot path grew
|
|
44
|
+
# a top-level import of an optional dependency.
|
|
45
|
+
DENYLIST: Set[str] = {
|
|
46
|
+
# the [rag] extra's native dependency
|
|
47
|
+
"sqlite_vec",
|
|
48
|
+
# scientific-python / vector libs an embedding backend might drag in
|
|
49
|
+
"numpy", "scipy", "pandas", "torch", "transformers",
|
|
50
|
+
"sentence_transformers", "faiss",
|
|
51
|
+
# embedding / LLM provider SDKs (boost talks to them over stdlib urllib,
|
|
52
|
+
# so none of these should ever import at startup)
|
|
53
|
+
"openai", "voyageai", "anthropic", "cohere",
|
|
54
|
+
"langchain", "langchain_core", "langchain_community",
|
|
55
|
+
"ragas", "ranx",
|
|
56
|
+
# boost's own optional-only engines
|
|
57
|
+
"boost_cli.core.dense", "boost_cli.core.embed",
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# Advisory ceiling on total modules imported by a single command — reported, not
|
|
61
|
+
# enforced (import graphs legitimately differ across Python versions/platforms).
|
|
62
|
+
SOFT_MODULE_CEILING = 260
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def parse_modules(importtime_stderr: str) -> Set[str]:
|
|
66
|
+
"""Module names from ``python -X importtime`` stderr.
|
|
67
|
+
|
|
68
|
+
Each line is ``import time: <self> | <cumulative> | <indent><module>``; the
|
|
69
|
+
module name is the third ``|``-delimited field with its nesting indent
|
|
70
|
+
stripped. The header line (``self [us] | cumulative | imported package``)
|
|
71
|
+
has no numeric first field and is skipped.
|
|
72
|
+
"""
|
|
73
|
+
modules: Set[str] = set()
|
|
74
|
+
for line in importtime_stderr.splitlines():
|
|
75
|
+
if "import time:" not in line:
|
|
76
|
+
continue
|
|
77
|
+
_, _, rest = line.partition("import time:")
|
|
78
|
+
parts = rest.split("|")
|
|
79
|
+
if len(parts) != 3:
|
|
80
|
+
continue
|
|
81
|
+
if not parts[0].strip().isdigit(): # the header row
|
|
82
|
+
continue
|
|
83
|
+
name = parts[2].strip()
|
|
84
|
+
if name:
|
|
85
|
+
modules.add(name)
|
|
86
|
+
return modules
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def imported_modules(command: List[str]) -> Set[str]:
|
|
90
|
+
"""The set of modules imported when running ``boost <command>``.
|
|
91
|
+
|
|
92
|
+
Runs in a subprocess with a throwaway ``$HOME`` so a real ``~/.boost`` can
|
|
93
|
+
never influence which modules load (or leave state behind), and with
|
|
94
|
+
``PYTHONPATH`` pointed at the repo so no editable install is required.
|
|
95
|
+
"""
|
|
96
|
+
env = dict(os.environ)
|
|
97
|
+
with tempfile.TemporaryDirectory(prefix="boost-import-budget-") as home:
|
|
98
|
+
env["HOME"] = home
|
|
99
|
+
env["PYTHONPATH"] = str(ROOT)
|
|
100
|
+
env["BOOST_NO_AI"] = "1"
|
|
101
|
+
env.pop("BOOST_HOME", None)
|
|
102
|
+
proc = subprocess.run(
|
|
103
|
+
[sys.executable, "-X", "importtime", "-c",
|
|
104
|
+
"from boost_cli.cli import main; main(%r)" % (command,)],
|
|
105
|
+
cwd=str(ROOT), env=env, capture_output=True, text=True,
|
|
106
|
+
)
|
|
107
|
+
return parse_modules(proc.stderr)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def leaks_for(modules: Set[str]) -> List[str]:
|
|
111
|
+
"""Sorted denylisted modules present in ``modules`` (empty = clean)."""
|
|
112
|
+
return sorted(DENYLIST & modules)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def check() -> Dict[str, dict]:
|
|
116
|
+
"""Run every command; return ``{label: {"leaks": [...], "count": int}}``."""
|
|
117
|
+
report: Dict[str, dict] = {}
|
|
118
|
+
for command in COMMANDS:
|
|
119
|
+
mods = imported_modules(command)
|
|
120
|
+
report["boost " + " ".join(command)] = {
|
|
121
|
+
"leaks": leaks_for(mods),
|
|
122
|
+
"count": len(mods),
|
|
123
|
+
}
|
|
124
|
+
return report
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def main(argv: List[str] | None = None) -> int:
|
|
128
|
+
argv = list(sys.argv[1:] if argv is None else argv)
|
|
129
|
+
show_counts = "--list" in argv
|
|
130
|
+
report = check()
|
|
131
|
+
|
|
132
|
+
failed = False
|
|
133
|
+
for label, data in report.items():
|
|
134
|
+
if data["leaks"]:
|
|
135
|
+
failed = True
|
|
136
|
+
print("import-budget: FAIL %s imported %s"
|
|
137
|
+
% (label, ", ".join(data["leaks"])))
|
|
138
|
+
if show_counts:
|
|
139
|
+
print(" %-16s %d modules" % (label, data["count"]))
|
|
140
|
+
if data["count"] > SOFT_MODULE_CEILING:
|
|
141
|
+
print("import-budget: note — %s imported %d modules (advisory "
|
|
142
|
+
"ceiling %d); check for a new heavy dependency"
|
|
143
|
+
% (label, data["count"], SOFT_MODULE_CEILING))
|
|
144
|
+
|
|
145
|
+
if failed:
|
|
146
|
+
print("\nimport-budget: heavy/optional modules must stay lazy — move "
|
|
147
|
+
"the import inside the function that needs it (see "
|
|
148
|
+
"scripts/import_budget.py DENYLIST).")
|
|
149
|
+
return 1
|
|
150
|
+
print("import-budget: OK — no heavy/optional module imported by %d common "
|
|
151
|
+
"commands" % len(COMMANDS))
|
|
152
|
+
return 0
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
if __name__ == "__main__":
|
|
156
|
+
sys.exit(main())
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Unit test: .gitleaks.toml — the secret-scanning gate's configuration.
|
|
2
|
+
|
|
3
|
+
Validates the config is well-formed and does what the CI gate relies on:
|
|
4
|
+
extend the upstream default ruleset and allowlist boost's own synthetic
|
|
5
|
+
secret-scanner fixtures (so the gate stays green on deliberate test data while
|
|
6
|
+
still catching a real leak anywhere else).
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
import pytest
|
|
14
|
+
|
|
15
|
+
_CONFIG = Path(__file__).resolve().parents[2] / ".gitleaks.toml"
|
|
16
|
+
|
|
17
|
+
pytestmark = [
|
|
18
|
+
pytest.mark.skipif(not _CONFIG.exists(),
|
|
19
|
+
reason="repo-root .gitleaks.toml not reachable (e.g. mutation sandbox)"),
|
|
20
|
+
pytest.mark.skipif(sys.version_info < (3, 11),
|
|
21
|
+
reason="tomllib is stdlib only on Python 3.11+"),
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _load():
|
|
26
|
+
import tomllib
|
|
27
|
+
with open(_CONFIG, "rb") as f:
|
|
28
|
+
return tomllib.load(f)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_is_valid_toml():
|
|
32
|
+
assert isinstance(_load(), dict)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_extends_the_default_ruleset():
|
|
36
|
+
# Without useDefault the config would replace, not extend, gitleaks' rules —
|
|
37
|
+
# silently disabling every built-in detector.
|
|
38
|
+
cfg = _load()
|
|
39
|
+
assert cfg.get("extend", {}).get("useDefault") is True
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_allowlists_the_secretscan_fixtures():
|
|
43
|
+
cfg = _load()
|
|
44
|
+
allowlists = cfg.get("allowlists") or ([cfg["allowlist"]] if "allowlist" in cfg else [])
|
|
45
|
+
paths = [p for al in allowlists for p in al.get("paths", [])]
|
|
46
|
+
assert any("test_secretscan" in p for p in paths), (
|
|
47
|
+
"the synthetic-secret fixture file must be allowlisted or the gate "
|
|
48
|
+
"reports boost's own test data as a leak")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_allowlist_does_not_blanket_ignore_tests():
|
|
52
|
+
# A too-broad `tests/` allowlist would blind the scanner to a real secret
|
|
53
|
+
# committed in any other test file. Keep it scoped to the fixture file.
|
|
54
|
+
cfg = _load()
|
|
55
|
+
allowlists = cfg.get("allowlists") or ([cfg["allowlist"]] if "allowlist" in cfg else [])
|
|
56
|
+
paths = [p for al in allowlists for p in al.get("paths", [])]
|
|
57
|
+
for p in paths:
|
|
58
|
+
assert p.rstrip("$").rstrip("/") not in ("tests", "tests/", r"tests/.*", "tests"), \
|
|
59
|
+
"allowlist path %r is too broad — scope it to the fixture file" % p
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""Unit tests: scripts/import_budget.py — the startup lazy-import guard.
|
|
2
|
+
|
|
3
|
+
The pure parsing/denylist logic is tested directly; a single integration test
|
|
4
|
+
runs the real gate over the live interpreter so a genuine leak (a heavy module
|
|
5
|
+
newly imported at startup) fails here too, not just in CI.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import importlib.util
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
|
|
14
|
+
_SCRIPT = Path(__file__).resolve().parents[2] / "scripts" / "import_budget.py"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _load():
|
|
18
|
+
spec = importlib.util.spec_from_file_location("import_budget", _SCRIPT)
|
|
19
|
+
mod = importlib.util.module_from_spec(spec)
|
|
20
|
+
spec.loader.exec_module(mod)
|
|
21
|
+
return mod
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
pytestmark = pytest.mark.skipif(
|
|
25
|
+
not _SCRIPT.exists(), reason="repo-root scripts/ not reachable (e.g. mutation sandbox)")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# A realistic slice of `python -X importtime` stderr (the real header + rows).
|
|
29
|
+
_SAMPLE = """\
|
|
30
|
+
import time: self [us] | cumulative | imported package
|
|
31
|
+
import time: 120 | 120 | _io
|
|
32
|
+
import time: 200 | 900 | urllib.request
|
|
33
|
+
import time: 90 | 90 | http.client
|
|
34
|
+
import time: 300 | 1200 | boost_cli.cli
|
|
35
|
+
import time: 150 | 150 | sqlite_vec
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class TestParseModules:
|
|
40
|
+
def test_extracts_names_and_skips_header(self):
|
|
41
|
+
mod = _load()
|
|
42
|
+
names = mod.parse_modules(_SAMPLE)
|
|
43
|
+
assert "urllib.request" in names
|
|
44
|
+
assert "boost_cli.cli" in names
|
|
45
|
+
assert "sqlite_vec" in names
|
|
46
|
+
# the header row ("self [us] | cumulative | imported package") is not a
|
|
47
|
+
# module and must not be captured
|
|
48
|
+
assert "imported package" not in names
|
|
49
|
+
assert "cumulative" not in names
|
|
50
|
+
|
|
51
|
+
def test_strips_nesting_indent(self):
|
|
52
|
+
mod = _load()
|
|
53
|
+
# deeply nested rows keep only the dotted module name, no leading spaces
|
|
54
|
+
names = mod.parse_modules("import time: 90 | 90 | a.b.c\n")
|
|
55
|
+
assert names == {"a.b.c"}
|
|
56
|
+
|
|
57
|
+
def test_ignores_non_importtime_lines(self):
|
|
58
|
+
mod = _load()
|
|
59
|
+
noise = "some other stderr line\nWARNING: whatever\n"
|
|
60
|
+
assert mod.parse_modules(noise) == set()
|
|
61
|
+
|
|
62
|
+
def test_ignores_malformed_rows(self):
|
|
63
|
+
mod = _load()
|
|
64
|
+
# a row missing the third field yields nothing rather than a bad name
|
|
65
|
+
assert mod.parse_modules("import time: 10 | 10\n") == set()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class TestLeaksFor:
|
|
69
|
+
def test_flags_denylisted_modules_only(self):
|
|
70
|
+
mod = _load()
|
|
71
|
+
present = {"json", "os", "sqlite_vec", "boost_cli.core.dense", "urllib.request"}
|
|
72
|
+
assert mod.leaks_for(present) == ["boost_cli.core.dense", "sqlite_vec"]
|
|
73
|
+
|
|
74
|
+
def test_clean_set_has_no_leaks(self):
|
|
75
|
+
mod = _load()
|
|
76
|
+
assert mod.leaks_for({"json", "os", "boost_cli.cli", "urllib.request"}) == []
|
|
77
|
+
|
|
78
|
+
def test_result_is_sorted(self):
|
|
79
|
+
mod = _load()
|
|
80
|
+
present = {"ranx", "anticipation", "numpy", "torch"}
|
|
81
|
+
assert mod.leaks_for(present) == sorted(mod.DENYLIST & present)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class TestMain:
|
|
85
|
+
def test_returns_1_and_reports_on_leak(self, monkeypatch, capsys):
|
|
86
|
+
mod = _load()
|
|
87
|
+
monkeypatch.setattr(mod, "check", lambda: {
|
|
88
|
+
"boost count": {"leaks": ["sqlite_vec"], "count": 210},
|
|
89
|
+
})
|
|
90
|
+
rc = mod.main([])
|
|
91
|
+
out = capsys.readouterr().out
|
|
92
|
+
assert rc == 1
|
|
93
|
+
assert "FAIL" in out and "sqlite_vec" in out and "boost count" in out
|
|
94
|
+
|
|
95
|
+
def test_returns_0_when_clean(self, monkeypatch, capsys):
|
|
96
|
+
mod = _load()
|
|
97
|
+
monkeypatch.setattr(mod, "check", lambda: {
|
|
98
|
+
"boost --help": {"leaks": [], "count": 177},
|
|
99
|
+
})
|
|
100
|
+
rc = mod.main([])
|
|
101
|
+
assert rc == 0
|
|
102
|
+
assert "OK" in capsys.readouterr().out
|
|
103
|
+
|
|
104
|
+
def test_list_flag_prints_counts(self, monkeypatch, capsys):
|
|
105
|
+
mod = _load()
|
|
106
|
+
monkeypatch.setattr(mod, "check", lambda: {
|
|
107
|
+
"boost list": {"leaks": [], "count": 201},
|
|
108
|
+
})
|
|
109
|
+
mod.main(["--list"])
|
|
110
|
+
assert "201 modules" in capsys.readouterr().out
|
|
111
|
+
|
|
112
|
+
def test_soft_ceiling_is_advisory_not_fatal(self, monkeypatch, capsys):
|
|
113
|
+
mod = _load()
|
|
114
|
+
over = mod.SOFT_MODULE_CEILING + 50
|
|
115
|
+
monkeypatch.setattr(mod, "check", lambda: {
|
|
116
|
+
"boost --help": {"leaks": [], "count": over},
|
|
117
|
+
})
|
|
118
|
+
rc = mod.main([])
|
|
119
|
+
# a high module count is a note, not a failure (import graphs differ
|
|
120
|
+
# across Python versions/platforms)
|
|
121
|
+
assert rc == 0
|
|
122
|
+
assert "advisory ceiling" in capsys.readouterr().out
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class TestIntegration:
|
|
126
|
+
def test_live_startup_has_no_heavy_imports(self):
|
|
127
|
+
"""The real gate over this interpreter must be clean — a genuine
|
|
128
|
+
regression (a heavy module imported at startup) fails the suite here."""
|
|
129
|
+
mod = _load()
|
|
130
|
+
report = mod.check()
|
|
131
|
+
offenders = {label: data["leaks"]
|
|
132
|
+
for label, data in report.items() if data["leaks"]}
|
|
133
|
+
assert not offenders, (
|
|
134
|
+
"heavy/optional modules leaked into startup: %s — keep the import "
|
|
135
|
+
"lazy (see scripts/import_budget.py)" % offenders)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|