kanon-cli 3.3.2__tar.gz → 3.3.3__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.
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/CHANGELOG.md +135 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/PKG-INFO +1 -1
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/integration-testing.md +191 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/pyproject.toml +1 -1
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/__init__.py +1 -1
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/marketplace_validator.py +210 -30
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_validate_marketplace.py +50 -5
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_validate_marketplace.py +10 -5
- kanon_cli-3.3.3/tests/scenarios/test_et.py +445 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_ci_workflows.py +34 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_marketplace_validator.py +223 -10
- kanon_cli-3.3.3/tests/unit/test_toolchain_isolation.py +243 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/uv.lock +1 -1
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.claude/settings.json +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/.devcontainer.postcreate.sh +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/VERSION +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/catalog-entry.json +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/devcontainer-functions.sh +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/devcontainer.json +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/fix-line-endings.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/nix-family-os/README.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/nix-family-os/tinyproxy-daemon.sh +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/nix-family-os/tinyproxy.conf.template +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/postcreate-wrapper.sh +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/project-setup.sh +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/wsl-family-os/README.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/wsl-family-os/tinyproxy-daemon.sh +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/wsl-family-os/tinyproxy.conf.template +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.github/CODEOWNERS +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.github/actions/setup-kanon/action.yml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.github/workflows/codeql-analysis.yml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.github/workflows/main-validation.yml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.github/workflows/pr-validation.yml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.github/workflows/publish.yml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.gitignore +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.markdownlint.json +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.pre-commit-config.yaml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.tool-versions +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.yamllint +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/CLAUDE.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/CONTRIBUTING.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/LICENSE +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/Makefile +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/README.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/architecture.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/catalog-author-guide.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/catalog-format-versioning.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/catalogs-explained.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/claude-marketplaces-guide.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/cli/catalog-audit.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/cli/doctor.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/cli/validate.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/cli-reference.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/cli.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/coming-from-pip-npm-cargo.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/configuration.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/contributing.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/creating-manifest-repos.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/creating-packages.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/doctor.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/exit-codes.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/git-auth-setup.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/how-it-works.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/installation.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/lifecycle.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/list-and-add.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/lockfile.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/migrating-existing-kanon-files.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/migration-to-add.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/multi-source-guide.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/outdated-and-why.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/pipeline-integration.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/privacy.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/repo/README.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/repo/internal-fs-layout.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/repo/manifest-format.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/repo/python-support.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/repo/repo-hooks.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/repo/smart-sync.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/repo/windows.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/security-model.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/setup-guide.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/shell-completion.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/test-coverage.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/testing/matrix-traceability.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/troubleshooting.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/url-canonicalization.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/version-resolution.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/git-hooks/pre-commit +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/git-hooks/pre-push +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/link +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/scripts/check_archive_no_duplicates.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/__main__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/cli.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/add.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/catalog.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/clean.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/completion.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/doctor.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/install.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/list.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/marketplace.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/outdated.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/remove.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/repo.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/search.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/validate.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/why.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/cache.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/cached_catalogs.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/catalog_entries.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/catalog_versions.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/lockfile_names.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/midtoken.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/pep440_filter.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/powershell.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/preamble.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/project_versions.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/sanitize.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/source_names.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/constants.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/catalog.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/clean.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/cli_args.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/discover.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/git_runner.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/include_walker.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/install.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/kanon_hash.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/kanonenv.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/kanonenv_writer.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/lockfile.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/manifest.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/manifest_vars.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/marketplace.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/metadata.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/remote_url.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/telemetry.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/update_check.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/url.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/xml_validator.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/color.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/command.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/editor.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/error.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/event_log.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/fetch.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/git_command.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/git_config.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/git_refs.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/git_ssh +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/git_superproject.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/git_trace2_event_log.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/git_trace2_event_log_base.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/hooks/commit-msg +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/hooks/pre-auto-gc +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/hooks.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/main.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/manifest_xml.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/pager.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/platform_utils.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/platform_utils_win32.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/progress.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/project.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/repo +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/repo_logging.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/repo_trace.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/requirements.jsonc +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/ssh.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/abandon.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/branches.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/checkout.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/cherry_pick.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/diff.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/diffmanifests.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/download.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/envsubst.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/forall.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/gc.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/grep.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/help.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/info.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/init.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/list.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/manifest.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/overview.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/prune.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/rebase.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/selfupdate.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/smartsync.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/stage.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/start.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/status.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/sync.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/upload.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/version_constraints.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/wrapper.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/utils/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/utils/concurrency.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/utils/levenshtein.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/utils/lock_file_path.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/utils/spawn.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/version.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/conftest.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-1/repo-specs/duplicate-child-marketplace.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-1/repo-specs/missing-recommended-marketplace.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-1/repo-specs/missing-required-marketplace.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-1/repo-specs/multiple-blocks-marketplace.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-2/repo-specs/dotted-name-marketplace.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-2/repo-specs/hyphenated-name-marketplace.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-2/repo-specs/uppercase-name-marketplace.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-3/repo-specs/group-a-1-marketplace.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-3/repo-specs/group-a-2-marketplace.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-3/repo-specs/group-b-1-marketplace.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-3/repo-specs/group-b-2-marketplace.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-4/repo-specs/file-url-marketplace.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-4/repo-specs/query-string-marketplace.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-4/repo-specs/unresolvable-marketplace.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/legacy-catalog-dir/catalog/sample-entry/.kanon +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/legacy-catalog-dir/repo-specs/sample.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalogs/zero-pep440-tags/README.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalogs/zero-pep440-tags/repo-specs/entry-a/entry-a-marketplace.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/completion/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/completion/expected-bash.sh +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/completion/expected-powershell.ps1 +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/completion/expected-zsh.sh +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/README.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/conflict-detected.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/entry-not-found.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/lockfile-hash-mismatch.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/lockfile-sha-unreachable.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/missing-catalog-source.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/missing-required-metadata-field.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/source-collision.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/zero-pep440-tags-under-prefix.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/README.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-add.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-catalog-audit.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-catalog.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-clean.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-completion.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-doctor.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-install.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-list.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-marketplace.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-outdated.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-remove.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-search.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-toplevel.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-why.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/.gitignore +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/README.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/linter-test-bad.invalid-yaml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/linter-test-bad.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/linter-test-bad.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/sample-manifest.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/sample-project-config.json +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/test.gitconfig +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/version_constraints_data.json +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/conftest.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_add_alias_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_alias_consumer_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_argparse_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_argparse_help.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_ci_runs_operator_path_tests.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_clean_lifecycle.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_cli_entry_point.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_completion_snapshots.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_default_branch_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_env_int_guard_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_error_snapshots.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_exit_code_matrix.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_groups_filter.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_help_snapshots.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_help_text_contract.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_home_flag_unwritable_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_init_default_branch_prerequisite_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_install_hermetic_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_install_lifecycle.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_install_real_kanon.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_install_v3_lock_fail_fast_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_kanon_home_store_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_kanon_repo_cli.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_kanon_repo_e2e.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_kanon_repo_lifecycle_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_lifecycle_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_list.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_list_telemetry.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_make_operator_path_targets.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_marketplace_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_matrix_traceability_complete.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_provider_agnostic.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_abandon_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_abandon_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_abandon_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_branches_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_branches_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_branches_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_checkout_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_checkout_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_checkout_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_cherry_pick_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_cherry_pick_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_cherry_pick_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_diff_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_diff_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_diff_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_diffmanifests_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_diffmanifests_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_diffmanifests_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_dir_override.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_download_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_download_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_download_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_envsubst_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_envsubst_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_envsubst_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_exit_codes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_forall_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_forall_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_forall_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_gc_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_gc_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_gc_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_grep_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_grep_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_grep_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_help_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_help_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_help_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_info_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_info_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_info_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_init_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_init_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_init_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_init_mirror.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_list_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_list_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_list_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_manifest_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_manifest_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_manifest_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_manifest_revision_as_tag.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_overview_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_overview_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_overview_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_passthrough.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_prune_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_prune_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_prune_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_rebase_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_rebase_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_rebase_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_selfupdate_disabled.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_selfupdate_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_selfupdate_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_selfupdate_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_smartsync_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_smartsync_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_smartsync_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_stage_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_stage_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_stage_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_start_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_start_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_start_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_status_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_status_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_status_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_sync_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_sync_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_sync_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_upload_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_upload_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_upload_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_singular_catalog_source_inert.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_stdout_stderr_discipline.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_telemetry_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_update_alert_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_validate_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_validate_lifecycle.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_validate_lockfile.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_validate_xml_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_validate_xml_repo_root.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_zero_source_clean_error.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/conftest.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/fixtures/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/fixtures/synthetic/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/fixtures/synthetic/conftest.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/fixtures/synthetic/drift.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/fixtures/synthetic/test_synthetic_pytest_fixtures.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/fixtures/synthetic/upgrade_versioned.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/provider_allowlist.txt +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/conftest.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_bug_fixes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_consolidated_constraints_e2e.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_envsubst_integration.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_import_functional.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_linkfile_copyfile.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_linkfile_exclude_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_manifest_parsing.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_process_isolation.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_repo_module_smoke.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_repo_pipeline.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_repo_run_lifecycle.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_repo_sync_lifecycle.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_version_constraints_integration.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_annotation_roundtrip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_contactinfo_roundtrip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_copyfile_roundtrip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_default_roundtrip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_extend_project_roundtrip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_include_roundtrip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_linkfile_roundtrip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_manifest_roundtrip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_manifest_server_roundtrip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_notice_roundtrip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_project_roundtrip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_remote_roundtrip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_remove_project_roundtrip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_repo_hooks_roundtrip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_submanifest_roundtrip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_superproject_roundtrip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_add_core.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_add_dry_run.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_add_env_var_detection.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_add_zero_tags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_auto_discovery.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_background_refresh.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_cache_clock_skew.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_cache_layout.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_audit_entry_uniqueness.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_audit_framework.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_audit_legacy_dir.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_audit_metadata.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_audit_remote_url.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_audit_source_name.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_audit_strict.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_audit_tag_format.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_constraints.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_ci_validation.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_clean_env_override_cleanup.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_clean_lifecycle.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_clean_paths.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_cli_entry_points.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_complete_cached_catalogs.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_complete_catalog_entries.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_complete_catalog_versions.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_complete_lockfile_names.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_complete_project_versions.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_complete_source_names.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_completion_bash.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_completion_powershell_subcommand.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_completion_subcommand.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_completion_zsh.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_concurrency.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_concurrency_serialization.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_copyfile_fs_effects.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_cross_platform_contract.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_doc_validation.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_doctor_cache_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_doctor_cache_flags_workspace_independent.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_doctor_consistency.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_doctor_default_subcheck_output.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_doctor_effective_source.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_doctor_prune_cache.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_doctor_remote_check.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_envsubst_command.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_fs_fault_extended.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_fs_fault_injection.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_full_lifecycle_synthetic.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_full_user_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_git_fault_injection.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_git_retry_env.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_gitignore_idempotency.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_home_flag_store_relocation.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_after_add.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_command.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_env_var_resolution.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_include_cycle.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_include_diamond.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_lifecycle.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_lock_file_derivation.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_lockfile_replay.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_marketplace_registration.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_no_kanon_remediation.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_optional_vars.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_path_conflict_integration.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_paths.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_per_alias_gitbase.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_reconcile.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_refresh_lock.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_refresh_lock_source.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_remote_url_policy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_required_vars.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_strict.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_json_output_stream_discipline.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_kanon_add_placeholder_handling.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_kanon_clean_embedded.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_kanon_dir_collision.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_kanon_full_lifecycle.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_kanon_install_embedded.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_kanonenv_parsing.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_lifecycle_recovery.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_linkfile_fs_effects.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_all_versions.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_all_versions_canonical.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_all_versions_malformed_revision_resilience.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_command_json.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_default.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_detail.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_filter.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_format_json.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_synthetic_catalog_variants.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_tree.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_lockfile_roundtrip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_marketplace_install.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_marketplace_lifecycle.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_marketplace_orphan_prune.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_midtoken_bash.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_midtoken_zsh.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_misc_features.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_multi_source_aggregation.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_no_bundled_catalog.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_no_default_catalog.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_no_hardcoded_org_values.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_observability.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_outdated.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_outdated_branch_drift.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_outdated_fail_on_upgrade.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_outdated_format_json.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_outdated_refs_tags_revision_parsing.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_platform_parity.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_preamble_bash.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_preamble_zsh.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_remove_core.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_remove_dry_run.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_remove_force_integration.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_signal_handling.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_synthetic_drift_fixture.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_synthetic_upgrade_versioned_fixture.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_unicode_encoding.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_validate_marketplace_revision_existence.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_validate_metadata.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_validate_xml.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_version_resolution.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_version_widened_bare_pep440.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_wheel_e2e.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_why_ambiguous.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_why_chain_walker.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_why_format_json.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_why_live_resolve.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_why_not_found_suggestion.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_workspace_dir_env.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f1_s2_t5_regression.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f5_s2_t7_regression.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s1_t1_regression.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s1_t2_regression.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s1_t3_regression.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s1_t4_regression.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s2_t1_regression.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s2_t2_regression.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s2_t3_regression.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s2_t4_regression.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s2_t5_regression.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s2_t6_regression.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s3_t1_regression.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s3_t2_regression.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_install_relative_regression.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_linkfile_samefile_regression.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/_rp_helpers.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/conftest.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_ad.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_bs.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_cd.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_content_pins.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_cs.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_doctor_cache.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_doctor_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_ec.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_ep.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_ev.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_hv.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_ic.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_id.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_install_graph_capture.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_ks.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_lf.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_list_journey.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_lockfile_lifecycle.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_marketplace_direct_checkout.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_mk.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_ms.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_ns_marketplace_and_global_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_outdated_two_source.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_pk.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rc.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_refresh_lock_existing_checkout.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rls_exact_vs_range.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_abandon.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_branches.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_checkout.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_cherry_pick.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_diff.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_diffmanifests.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_download.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_envsubst.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_forall.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_gc.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_grep.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_help.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_info.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_init.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_list.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_manifest.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_overview.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_prune.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_rebase.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_smartsync.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_stage.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_start.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_status.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_sync.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_upload.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_wrap.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rx.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_scenario_coverage_meta.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_search_multi_source.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_tc_bootstrap.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_tc_clean.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_tc_install.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_tc_validate.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_uj.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_va.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_va_validate_lockfile.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_why_surface_query.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_why_url_path.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_why_url_path_placeholder.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/security/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/security/test_security_hardening.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/test_wheel_layout.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/commands/test_repo_dir_resolution.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/conftest.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/conftest.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/fixtures/.gitignore +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/fixtures/README.md +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/fixtures/sample-manifest.xml +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/fixtures/sample-project-config.json +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/fixtures/test.gitconfig +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/fixtures/version_constraints_data.json +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/functional/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/functional/test_features.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/subcmds/__init__.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/subcmds/test_init_mirror.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/subcmds/test_manifest_revision_as_tag.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/subcmds/test_manifest_revision_as_tag_pep440.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/subcmds/test_selfupdate_stub.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_abandon_massive.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_branches_coverage.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug10_selfupdate_incompatible.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug11_race_condition.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug12_backup_preserved.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug13_init_reinit_warning.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug14_non_tty_log.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug15_prerelease_docs.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug16_nested_var_warning.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug18_envsubst_double_parse.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug19_glob_src_error.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug1_envsubst_malformed_xml.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug20_glob_dest_file.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug2_linkfile_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug3_execv_replaces_process.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug4_symlink_overwrite.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug5_empty_envsubst_list.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug6_undefined_env_vars.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug7_git_ls_remote_retry.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug8_ls_remote_stderr.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug9_constraint_resolution_cache.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_checklocalpath_rules_1_5.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_checklocalpath_rules_6_11.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_checkout_massive.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_cherrypick_coverage.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_color.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_command.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_conftest_fixtures.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_diffmanifests_deep.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_doc_validate_git_preconditions.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_download_coverage.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_editor.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_embedded_mode.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_envsubst_basic.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_envsubst_edge.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_envsubst_massive.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_error.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_event_log.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_event_log_massive.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_fetch.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_fixture_files.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_forall_deep.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_git_command.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_git_config.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_git_refs.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_git_superproject.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_git_trace2_event_log.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_gitconfig_coverage.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_grep_deep.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_harness_smoke.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_hooks.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_import_verification.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_imports.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_include_path_resolution.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_info_deep.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_init_deep.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_list_massive.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_main.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_main_coverage.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_main_init_download_boost.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_makefile_lint_format.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_makefile_structure.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_makefile_test_targets.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_manifest_coverage_boost.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_manifest_deep.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_manifest_doc_rp_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_manifest_massive.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_manifest_subcmd_massive.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_manifest_xml.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_manifest_xml_pep440.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_medium_files_boost.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_mkdtemp_cleanup.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_overview_massive.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_package_structure.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_pager.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_parselist.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_pep440_edge_1.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_pep440_edge_2.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_pep440_ops_ge.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_pep440_ops_rest.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_platform_utils.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_process_isolation.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_progress.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_coverage_boost.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_coverage_threshold.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_deep.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_deep_boost.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_final_boost.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_integration.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_massive.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_metaproject_boost.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_methods.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_sync.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_prune_massive.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_rebase_coverage.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_remaining_coverage_boost.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_repo_envsubst_api.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_repo_logging.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_repo_run_api.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_repo_sync_api.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_repo_trace.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_revision_inheritance.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_revision_tag_branch_sha.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_ruff_config.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_selfupdate_embedded.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_selfupdate_massive.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_small_files_boost.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_ssh.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_ssh_deep.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_stage_coverage.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_stage_massive.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_start_coverage.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_status_coverage.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_status_gaps.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_status_massive.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmd_imports.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_abandon.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_branches.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_checkout.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_cherry_pick.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_diff.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_diffmanifests.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_download.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_envsubst.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_forall.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_gc.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_grep.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_help.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_info.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_init.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_list.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_manifest.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_overview.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_prune.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_rebase.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_selfupdate.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_smartsync.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_stage.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_start.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_status.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_sync.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_upload.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_superproject_deep.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_sync_coverage_boost.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_sync_deep.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_sync_deep_boost.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_sync_massive.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_upload_deep.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_version_consolidation.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_version_constraints.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_wheel_contents.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_wrapper.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_annotation_attributes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_annotation_crossref.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_annotation_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_contactinfo_attributes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_contactinfo_crossref.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_contactinfo_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_copyfile_attributes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_copyfile_crossref.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_copyfile_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_default_attributes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_default_crossref.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_default_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_extend_project_attributes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_extend_project_crossref.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_extend_project_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_fault_malformed.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_fault_structural.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_include_attributes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_include_crossref.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_include_cycles.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_include_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_linkfile_attributes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_linkfile_crossref.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_linkfile_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_manifest_attributes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_manifest_crossref.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_manifest_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_manifest_server_attributes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_manifest_server_crossref.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_manifest_server_flow.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_manifest_server_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_notice_attributes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_notice_crossref.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_notice_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_project_attributes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_project_crossref.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_project_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_remote_attributes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_remote_crossref.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_remote_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_remove_project_attributes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_remove_project_crossref.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_remove_project_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_repo_hooks_attributes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_repo_hooks_crossref.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_repo_hooks_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_submanifest_attributes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_submanifest_crossref.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_submanifest_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_superproject_attributes.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_superproject_crossref.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_superproject_flow.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_superproject_happy.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xmlbool.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xmlint.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_yamllint_config.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_accessed_at_coalescing.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_add.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_add_collision.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_add_zero_tags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_background_refresh.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_bare_semver_to_tag.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_build_project_entries.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_cache.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_cache_layout.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_cache_ttl.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_cached_catalogs.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_check_parser.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_entry_uniqueness.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_framework.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_legacy_dir.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_metadata.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_project_tag_format.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_remote_url.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_source_name.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_strict.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_tag_format.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_source_parsing.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_check_no_comments.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_clean.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_clean_command.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_cli.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_cli_args.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_cli_help_format.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_cli_json_stream_discipline.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_complete_cached_catalogs.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_complete_catalog_entries.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_complete_catalog_versions.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_complete_lockfile_names.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_complete_project_versions.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_complete_source_names.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_completion.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_completion_sanitization.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_completion_subcommand.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_concurrency.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_conftest_scrubber.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_constants.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_constants_doctor_subcheck.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_constants_env_int.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_constants_install_after_add.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_constants_list.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_constants_outdated_refs_tags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_constants_why_lockfile.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_coverage_gaps.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_derive_source_name.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_discover.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_discover_source_names_missing_url.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_docs_embedded_architecture.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_docs_remaining_and_catalog.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_doctor.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_doctor_cache_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_doctor_completion_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_doctor_completion_staleness.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_doctor_consistency.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_doctor_coverage_gaps.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_doctor_effective_source.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_doctor_remote_reachability.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_env_isolation.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_envsubst_subcommand.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_git_runner.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_home_flag.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_include_walker.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_color_default.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_command.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_conflict_detection.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_https_enforcement.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_placeholder_validation.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_reconcile_decision.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_refresh_lock.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_refresh_lock_source.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_state_matrix.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_strict_flags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_strict_lock_orphan_naming.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_integration_testing_doc_manifest_paths.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_integration_testing_doc_s2_t14.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_integration_testing_doc_s2_t4.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_integration_testing_doc_s2_t5.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_integration_testing_doc_s2_t6.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_integration_testing_doc_s2_t7.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_integration_testing_doc_s2_tier1.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_isolation_fixtures.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_kanon_hash.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_kanonenv.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_kanonenv_advanced_edge_cases.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_kanonenv_edge_cases.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_kanonenv_writer.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_levenshtein.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_list.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_lock_file_path.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_lockfile.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_lockfile_coverage_gaps.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_lockfile_reconcile.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_lockfile_schema_migration.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_manifest.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_marketplace.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_marketplace_cmd.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_marketplace_install.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_marketplace_non_plugin_skip.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_metadata.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_midtoken_splitter.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_outdated.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_outdated_branch_pinned.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_outdated_fail_on_upgrade.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_outdated_format_json.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_pep440_filter.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_powershell.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_pre_push_hook.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_preamble.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_preamble_semver_tags.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_provider_agnosticism.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_pyproject_build_config.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_remote_url.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_remove.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_remove_dry_run.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_remove_force.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_remove_line_endings.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_repo.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_repo_abspath.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_repo_command.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_resolve_catalog_dir.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_revision_resolve.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_rx_catalog_sub_repo.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_sanitize.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_search.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_search_all_versions.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_search_coverage_gaps.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_search_detail.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_search_filter.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_search_format_json.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_search_tree.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_spawn.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_telemetry.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_update_check.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_url.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_validate.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_validate_command.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_validate_metadata.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_version.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_version_constraint_errors.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_why.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_why_ambiguity.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_why_format_json.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_why_suggestions.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_xml_validator.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tools/lint/check_no_comments.py +0 -0
- {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tools/test_tmp_monitor.py +0 -0
|
@@ -2,8 +2,137 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
## v3.3.3 (2026-08-06)
|
|
6
|
+
|
|
7
|
+
### Fix
|
|
8
|
+
|
|
9
|
+
* fix: scope linkfile dest rule by entry type, exempt direct-checkout marketplaces (#109)
|
|
10
|
+
|
|
11
|
+
* fix: scope marketplace linkfile dest rule to claude-marketplace entries
|
|
12
|
+
|
|
13
|
+
validate_linkfile_dest required every <linkfile dest> in every catalog
|
|
14
|
+
entry to start with ${CLAUDE_MARKETPLACES_DIR}/, ignoring the declared
|
|
15
|
+
<catalog-metadata><type>. Non-marketplace entries that install correctly
|
|
16
|
+
could not pass validation.
|
|
17
|
+
|
|
18
|
+
Closes #94
|
|
19
|
+
|
|
20
|
+
* fix: exempt direct-checkout entries, de-duplicate errors, align tests
|
|
21
|
+
|
|
22
|
+
Builds on ryano144's 0e75e27 (#99), which correctly identified issue #94:
|
|
23
|
+
validate_linkfile_dest required every <linkfile dest> to start with
|
|
24
|
+
${CLAUDE_MARKETPLACES_DIR}/ regardless of <catalog-metadata><type>, so a
|
|
25
|
+
non-marketplace entry that `kanon install` places correctly could not pass
|
|
26
|
+
validation. Scoping that rule by entry type is right and is kept as is.
|
|
27
|
+
|
|
28
|
+
Three problems remained.
|
|
29
|
+
|
|
30
|
+
1. The new "a claude-marketplace entry must land a dest under
|
|
31
|
+
${CLAUDE_MARKETPLACES_DIR}/" rule rejected an entry that declares no
|
|
32
|
+
<linkfile> at all. That is the direct-checkout shape:
|
|
33
|
+
register_direct_checkout_marketplaces registers a project whose checkout
|
|
34
|
+
carries .claude-plugin/marketplace.json and which has no <linkfile>
|
|
35
|
+
children, covered end to end by test_marketplace_direct_checkout.py. The
|
|
36
|
+
old validator accepted it, so the rule as written was a regression, and it
|
|
37
|
+
reproduced the very validator/install contradiction #94 reports, aimed at a
|
|
38
|
+
different entry shape. The rule now applies only when the entry declares at
|
|
39
|
+
least one <linkfile>; an entry declaring none is exempt. The useful half is
|
|
40
|
+
unchanged: an entry whose links all land elsewhere is still caught, and the
|
|
41
|
+
diagnostic now names the direct-checkout way out.
|
|
42
|
+
|
|
43
|
+
2. Linkfile checks follow each entry's <include> chain, so a defect in a
|
|
44
|
+
manifest shared by several entries was reported once per consumer. Three
|
|
45
|
+
entries including one broken packages.xml produced three identical errors
|
|
46
|
+
and a count of three for a single defect. Errors are de-duplicated within a
|
|
47
|
+
call (a manifest reachable by two include paths) and across the run.
|
|
48
|
+
Identical message text means the same file, project and reason, so
|
|
49
|
+
collapsing exact duplicates cannot hide a second real defect.
|
|
50
|
+
|
|
51
|
+
3. tests/functional/test_validate_marketplace.py still asserted the old
|
|
52
|
+
contract and was not touched by #99, so three parametrized cases failed:
|
|
53
|
+
relative/path, CLAUDE_MARKETPLACES_DIR/missing-dollar-brace and
|
|
54
|
+
${OTHER_VAR}/proj are contained dests on an entry with no <type> and are
|
|
55
|
+
now legal. Rather than delete the coverage, the class is split: the three
|
|
56
|
+
contained dests assert exit 0, and a new negative case asserts exit 1 for
|
|
57
|
+
the three shapes that escape the workspace (absolute, '..', empty).
|
|
58
|
+
|
|
59
|
+
Adds docs/integration-testing.md Category 11b (ET-01..ET-07) with runnable
|
|
60
|
+
manual reproductions, and tests/scenarios/test_et.py automating them through
|
|
61
|
+
the real `kanon validate marketplace` subprocess: the full 3x4 entry-type by
|
|
62
|
+
linkfile-shape matrix, containment across all three entry types, a linkfile
|
|
63
|
+
inside an <include>, a marketplace dest supplied by an include, single
|
|
64
|
+
reporting of a shared-include defect, and the mixed plugin-plus-standards
|
|
65
|
+
package from #94 with its negative counterpart.
|
|
66
|
+
|
|
67
|
+
Every documented scenario was also executed by hand against the built CLI and
|
|
68
|
+
matched its stated pass criteria.
|
|
69
|
+
|
|
70
|
+
Closes #94
|
|
71
|
+
|
|
72
|
+
* test: guard the single dependency-resolution path
|
|
73
|
+
|
|
74
|
+
Adds automated coverage for four invariants that were only ever verified by
|
|
75
|
+
hand while diagnosing the shtab CI drift and the 3.3.1 publish failure. Each
|
|
76
|
+
corresponds to a defect this repository actually hit, and none had a test.
|
|
77
|
+
|
|
78
|
+
1. A tool invoked through `uv run` is declared in [dependency-groups].
|
|
79
|
+
`make security-scan` was `uv run bandit` while bandit was declared nowhere,
|
|
80
|
+
so uv fell through to PATH and silently ran a system-wide bandit -- an
|
|
81
|
+
undeclared dependency deciding a security gate. `uv run` does not fail on an
|
|
82
|
+
undeclared executable, so nothing surfaced it.
|
|
83
|
+
|
|
84
|
+
2. No Make recipe invokes a tool directly. A bare `ruff check .` or
|
|
85
|
+
`pytest -m unit` resolves from PATH rather than uv.lock, which is precisely
|
|
86
|
+
the two-path split that let shtab 1.9.0 break the tiered CI jobs while the
|
|
87
|
+
uv-based jobs stayed green. Only the scenario target was previously guarded.
|
|
88
|
+
|
|
89
|
+
3. A dependency whose generated output is byte-compared against a committed
|
|
90
|
+
fixture carries an upper bound. `shtab>=1.7.0` allowed 1.9.0 to change its
|
|
91
|
+
completion output and break CI with no change to this repository.
|
|
92
|
+
|
|
93
|
+
4. The release job re-locks and stages uv.lock. semantic-release bumps
|
|
94
|
+
pyproject.toml and __init__.py but knows nothing about uv.lock, so without
|
|
95
|
+
the explicit refresh every release leaves the lock a version behind and
|
|
96
|
+
`uv sync --locked` fails on the tag -- how 3.3.1 failed to publish. Its
|
|
97
|
+
symptom is already guarded by test_uv_lock_records_the_declared_project_version;
|
|
98
|
+
this guards the mechanism that prevents it.
|
|
99
|
+
|
|
100
|
+
Each was verified RED by reverting the invariant it protects: removing bandit
|
|
101
|
+
from the dev group, rewriting `uv run ruff` as `ruff`, restoring `shtab>=1.7.0`,
|
|
102
|
+
dropping `uv lock` from the release job, and dropping uv.lock from its `git add`.
|
|
103
|
+
All five produce a message naming the file and the remedy.
|
|
104
|
+
|
|
105
|
+
* fix(test): replace the uv-run regex with linear tokenization
|
|
106
|
+
|
|
107
|
+
CodeQL flagged py/redos (high) on the pattern added in the previous commit:
|
|
108
|
+
|
|
109
|
+
\buv\s+run\s+(?:--[\w-]+(?:[= ]\S+)?\s+)*([A-Za-z][\w.-]*)
|
|
110
|
+
|
|
111
|
+
The repeated group holds an optional sub-match, so input with many repetitions
|
|
112
|
+
of ' --- ---' backtracks exponentially. Skipping uv's own flags is awkward to
|
|
113
|
+
express as a pattern and easy to get wrong in exactly this way.
|
|
114
|
+
|
|
115
|
+
Walking tokens does the same job in linear time and reads more plainly: find
|
|
116
|
+
`uv run`, skip following tokens that begin with '-', take the next one. A flag
|
|
117
|
+
with a detached value would misreport that value as the tool; no target uses
|
|
118
|
+
that form, and the assertion names the offending line, so it would be obvious
|
|
119
|
+
rather than silent. Documented on the helper.
|
|
120
|
+
|
|
121
|
+
Not suppressed: CLAUDE.md forbids annotating away a security finding, and the
|
|
122
|
+
finding was correct. Both guards were re-verified RED afterwards, and the
|
|
123
|
+
tokenizer returns in single-digit milliseconds on 40k adversarial tokens.
|
|
124
|
+
|
|
125
|
+
---------
|
|
126
|
+
|
|
127
|
+
Co-authored-by: Ryan Gross <ryan.gross@caylent.com> ([`ccfdfec`](https://github.com/caylent-solutions/kanon/commit/ccfdfecdbd7b3e366e1ca9c0579bd84aa70e66ae))
|
|
128
|
+
|
|
129
|
+
|
|
5
130
|
## v3.3.2 (2026-08-05)
|
|
6
131
|
|
|
132
|
+
### Chore
|
|
133
|
+
|
|
134
|
+
* chore(release): 3.3.2 ([`6f5ffe7`](https://github.com/caylent-solutions/kanon/commit/6f5ffe7c01553820a2e091cdc996151b5100c6cb))
|
|
135
|
+
|
|
7
136
|
### Fix
|
|
8
137
|
|
|
9
138
|
* fix(ci): refresh uv.lock during the release version bump (#107)
|
|
@@ -47,6 +176,12 @@ Note the existing 3.3.1 tag still points at a commit carrying the stale
|
|
|
47
176
|
lock, so republishing that exact tag will keep failing until the tag is
|
|
48
177
|
moved or a further release is cut. ([`00714e6`](https://github.com/caylent-solutions/kanon/commit/00714e648a42bea706945e7a38a66fa6dca8df28))
|
|
49
178
|
|
|
179
|
+
### Unknown
|
|
180
|
+
|
|
181
|
+
* Merge pull request #108 from caylent-solutions/release-3.3.2
|
|
182
|
+
|
|
183
|
+
Release 3.3.2 ([`fc48540`](https://github.com/caylent-solutions/kanon/commit/fc48540a5fc082e64c81ef9809f68d583a3a16e8))
|
|
184
|
+
|
|
50
185
|
|
|
51
186
|
## v3.3.1 (2026-08-04)
|
|
52
187
|
|
|
@@ -1521,6 +1521,197 @@ rm -rf "${VA06_DIR}"
|
|
|
1521
1521
|
|
|
1522
1522
|
---
|
|
1523
1523
|
|
|
1524
|
+
## 12b. Category 11b: Catalog Entry Type Validation (7 tests)
|
|
1525
|
+
|
|
1526
|
+
`kanon validate marketplace` enforces two linkfile rules. **Containment** applies
|
|
1527
|
+
to every entry: a `<linkfile dest>` names a symlink created relative to the top of
|
|
1528
|
+
the consumer tree, so it must land inside that tree. **The marketplace-dest rule**
|
|
1529
|
+
applies only to an entry whose `<catalog-metadata><type>` is `claude-marketplace`
|
|
1530
|
+
*and* which declares at least one `<linkfile>`: one of those dests must sit under
|
|
1531
|
+
`${CLAUDE_MARKETPLACES_DIR}/`.
|
|
1532
|
+
|
|
1533
|
+
The worked example throughout is a package of engineering standards containing a
|
|
1534
|
+
Claude Code plugin plus the repo-level assets a team expects at conventional
|
|
1535
|
+
paths: `.claude/rules/`, `.githooks/`, and a `.gitleaks.toml` at the repo root.
|
|
1536
|
+
|
|
1537
|
+
**Shared setup for this category:**
|
|
1538
|
+
|
|
1539
|
+
```bash
|
|
1540
|
+
export ET_DIR="${KANON_TEST_ROOT}/test-et"
|
|
1541
|
+
mkdir -p "${ET_DIR}"
|
|
1542
|
+
|
|
1543
|
+
# Writes a catalog entry: $1 file, $2 <type> (empty for none), $3.. linkfile dests.
|
|
1544
|
+
et_entry() {
|
|
1545
|
+
local file="$1" entry_type="$2"; shift 2
|
|
1546
|
+
local links="" type_el=""
|
|
1547
|
+
for dest in "$@"; do
|
|
1548
|
+
links="${links} <linkfile src=\"src\" dest=\"${dest}\" />
|
|
1549
|
+
"
|
|
1550
|
+
done
|
|
1551
|
+
[ -n "${entry_type}" ] && type_el=" <type>${entry_type}</type>
|
|
1552
|
+
"
|
|
1553
|
+
mkdir -p "$(dirname "${file}")"
|
|
1554
|
+
cat > "${file}" << ENTRYEOF
|
|
1555
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
1556
|
+
<manifest>
|
|
1557
|
+
<remote name="origin" fetch="https://example.com" />
|
|
1558
|
+
<project name="standards" path=".packages/standards" remote="origin" revision="refs/tags/ex/standards/1.0.0">
|
|
1559
|
+
${links} </project>
|
|
1560
|
+
<catalog-metadata>
|
|
1561
|
+
<name>standards</name>
|
|
1562
|
+
<display-name>Engineering Standards</display-name>
|
|
1563
|
+
<description>Plugin plus repo-level standards.</description>
|
|
1564
|
+
<version>1.0.0</version>
|
|
1565
|
+
${type_el} <owner-name>Example Org</owner-name>
|
|
1566
|
+
<owner-email>eng@example.com</owner-email>
|
|
1567
|
+
<keywords>standards</keywords>
|
|
1568
|
+
</catalog-metadata>
|
|
1569
|
+
</manifest>
|
|
1570
|
+
ENTRYEOF
|
|
1571
|
+
}
|
|
1572
|
+
```
|
|
1573
|
+
|
|
1574
|
+
### ET-01: Marketplace entry ships a plugin alongside repo-level standards
|
|
1575
|
+
|
|
1576
|
+
The case issue #94 was filed to unblock. One entry registers a Claude plugin and
|
|
1577
|
+
also places rules, hooks, a root dotfile, and a plain relative config.
|
|
1578
|
+
|
|
1579
|
+
```bash
|
|
1580
|
+
rm -rf "${ET_DIR}/c01" && et_entry "${ET_DIR}/c01/repo-specs/standards.xml" claude-marketplace \
|
|
1581
|
+
'${CLAUDE_MARKETPLACES_DIR}/standards' \
|
|
1582
|
+
'${PROJECT_ROOT}/.claude/rules' \
|
|
1583
|
+
'${PROJECT_ROOT}/.githooks' \
|
|
1584
|
+
'${PROJECT_ROOT}/.gitleaks.toml' \
|
|
1585
|
+
'config/lint.toml'
|
|
1586
|
+
|
|
1587
|
+
kanon validate marketplace --repo-root "${ET_DIR}/c01"
|
|
1588
|
+
```
|
|
1589
|
+
|
|
1590
|
+
**Pass criteria:** Exit code 0, stderr empty. Before the fix each of the four
|
|
1591
|
+
non-marketplace dests produced one error.
|
|
1592
|
+
|
|
1593
|
+
### ET-02: Non-marketplace entry links only into the project root
|
|
1594
|
+
|
|
1595
|
+
An entry declaring `<type>library</type>` ships no plugin at all.
|
|
1596
|
+
|
|
1597
|
+
```bash
|
|
1598
|
+
rm -rf "${ET_DIR}/c02" && et_entry "${ET_DIR}/c02/repo-specs/standards.xml" library \
|
|
1599
|
+
'${PROJECT_ROOT}/.claude/rules' '${PROJECT_ROOT}/.gitleaks.toml'
|
|
1600
|
+
|
|
1601
|
+
kanon validate marketplace --repo-root "${ET_DIR}/c02"
|
|
1602
|
+
```
|
|
1603
|
+
|
|
1604
|
+
**Pass criteria:** Exit code 0, stderr empty. An entry with no `<type>` at all
|
|
1605
|
+
behaves identically.
|
|
1606
|
+
|
|
1607
|
+
### ET-03: Direct-checkout marketplace entry declares no linkfiles
|
|
1608
|
+
|
|
1609
|
+
A `claude-marketplace` entry registered from a checked-out
|
|
1610
|
+
`.claude-plugin/marketplace.json`, with no `<linkfile>` elements. The
|
|
1611
|
+
marketplace-dest rule must not fire, or validation would reject an entry that
|
|
1612
|
+
`kanon install` registers correctly.
|
|
1613
|
+
|
|
1614
|
+
```bash
|
|
1615
|
+
rm -rf "${ET_DIR}/c03" && et_entry "${ET_DIR}/c03/repo-specs/standards.xml" claude-marketplace
|
|
1616
|
+
|
|
1617
|
+
kanon validate marketplace --repo-root "${ET_DIR}/c03"
|
|
1618
|
+
```
|
|
1619
|
+
|
|
1620
|
+
**Pass criteria:** Exit code 0, stderr empty.
|
|
1621
|
+
|
|
1622
|
+
### ET-04: Marketplace entry whose linkfiles all miss the marketplace directory
|
|
1623
|
+
|
|
1624
|
+
Declares itself a marketplace and uses linkfiles, but every dest lands elsewhere,
|
|
1625
|
+
so it registers nothing.
|
|
1626
|
+
|
|
1627
|
+
```bash
|
|
1628
|
+
rm -rf "${ET_DIR}/c04" && et_entry "${ET_DIR}/c04/repo-specs/standards.xml" claude-marketplace \
|
|
1629
|
+
'${PROJECT_ROOT}/.claude/rules' '${PROJECT_ROOT}/.githooks'
|
|
1630
|
+
|
|
1631
|
+
set +e
|
|
1632
|
+
kanon validate marketplace --repo-root "${ET_DIR}/c04"
|
|
1633
|
+
exit_code=$?
|
|
1634
|
+
set -e
|
|
1635
|
+
```
|
|
1636
|
+
|
|
1637
|
+
**Pass criteria:** Exit code non-zero. stderr contains `registers no marketplace`
|
|
1638
|
+
and names all three ways out, including `direct checkout`.
|
|
1639
|
+
|
|
1640
|
+
### ET-05: A dest that escapes the consumer workspace is rejected
|
|
1641
|
+
|
|
1642
|
+
Three shapes escape, for every entry type: an absolute path, a `..` component,
|
|
1643
|
+
and an empty dest.
|
|
1644
|
+
|
|
1645
|
+
```bash
|
|
1646
|
+
for bad in '/etc/kanon/rules' '../../outside/workspace' ''; do
|
|
1647
|
+
rm -rf "${ET_DIR}/c05" && et_entry "${ET_DIR}/c05/repo-specs/standards.xml" library "${bad}"
|
|
1648
|
+
set +e
|
|
1649
|
+
kanon validate marketplace --repo-root "${ET_DIR}/c05"
|
|
1650
|
+
echo "dest=${bad} exit=$?"
|
|
1651
|
+
set -e
|
|
1652
|
+
done
|
|
1653
|
+
```
|
|
1654
|
+
|
|
1655
|
+
**Pass criteria:** Exit code non-zero for each. stderr names the specific reason:
|
|
1656
|
+
`absolute path`, `'..' component`, or `dest is empty`. No error text on stdout.
|
|
1657
|
+
|
|
1658
|
+
### ET-06: A linkfile inside an `<include>` is validated like an inline one
|
|
1659
|
+
|
|
1660
|
+
`kanon install` resolves the whole include chain, so validation must see the same
|
|
1661
|
+
projects. The entry below is clean; only the included manifest is not.
|
|
1662
|
+
|
|
1663
|
+
```bash
|
|
1664
|
+
rm -rf "${ET_DIR}/c06" && mkdir -p "${ET_DIR}/c06/repo-specs"
|
|
1665
|
+
cat > "${ET_DIR}/c06/repo-specs/packages.xml" << 'INCEOF'
|
|
1666
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
1667
|
+
<manifest>
|
|
1668
|
+
<project name="shared" path=".packages/shared" remote="origin" revision="refs/tags/ex/shared/1.0.0">
|
|
1669
|
+
<linkfile src="src" dest="../escapes" />
|
|
1670
|
+
</project>
|
|
1671
|
+
</manifest>
|
|
1672
|
+
INCEOF
|
|
1673
|
+
et_entry "${ET_DIR}/c06/repo-specs/standards.xml" claude-marketplace '${CLAUDE_MARKETPLACES_DIR}/standards'
|
|
1674
|
+
sed -i.bak 's|<remote name="origin" fetch="https://example.com" />|<remote name="origin" fetch="https://example.com" />\n <include name="repo-specs/packages.xml" />|' \
|
|
1675
|
+
"${ET_DIR}/c06/repo-specs/standards.xml"
|
|
1676
|
+
|
|
1677
|
+
set +e
|
|
1678
|
+
kanon validate marketplace --repo-root "${ET_DIR}/c06"
|
|
1679
|
+
exit_code=$?
|
|
1680
|
+
set -e
|
|
1681
|
+
```
|
|
1682
|
+
|
|
1683
|
+
**Pass criteria:** Exit code non-zero. stderr contains `'..' component` and names
|
|
1684
|
+
`packages.xml`.
|
|
1685
|
+
|
|
1686
|
+
### ET-07: A defect in a shared `<include>` is reported once
|
|
1687
|
+
|
|
1688
|
+
Three entries include the same broken manifest. Reporting the identical message
|
|
1689
|
+
once per consumer inflates the count and buries the distinct failures.
|
|
1690
|
+
|
|
1691
|
+
```bash
|
|
1692
|
+
rm -rf "${ET_DIR}/c07" && mkdir -p "${ET_DIR}/c07/repo-specs"
|
|
1693
|
+
cp "${ET_DIR}/c06/repo-specs/packages.xml" "${ET_DIR}/c07/repo-specs/packages.xml"
|
|
1694
|
+
for name in alpha bravo charlie; do
|
|
1695
|
+
cp "${ET_DIR}/c06/repo-specs/standards.xml" "${ET_DIR}/c07/repo-specs/${name}.xml"
|
|
1696
|
+
done
|
|
1697
|
+
|
|
1698
|
+
set +e
|
|
1699
|
+
kanon validate marketplace --repo-root "${ET_DIR}/c07" 2>&1 | grep -c "'..' component"
|
|
1700
|
+
set -e
|
|
1701
|
+
```
|
|
1702
|
+
|
|
1703
|
+
**Pass criteria:** Exactly `1` occurrence, and stderr reports
|
|
1704
|
+
`Found 1 validation error(s)` despite three entries including the defect.
|
|
1705
|
+
|
|
1706
|
+
**Cleanup:**
|
|
1707
|
+
|
|
1708
|
+
```bash
|
|
1709
|
+
cd "${KANON_TEST_ROOT}"
|
|
1710
|
+
rm -rf "${ET_DIR}"
|
|
1711
|
+
```
|
|
1712
|
+
|
|
1713
|
+
---
|
|
1714
|
+
|
|
1524
1715
|
## 13. Category 12: Entry Points (2 tests)
|
|
1525
1716
|
|
|
1526
1717
|
### EP-01: python -m kanon_cli --version
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
"""Validate marketplace XML manifest files.
|
|
2
2
|
|
|
3
3
|
Checks:
|
|
4
|
-
-
|
|
5
|
-
|
|
4
|
+
- Every <linkfile dest> resolves inside the consumer workspace: an absolute
|
|
5
|
+
path, an empty dest, and a '..' traversal component are rejected. A dest
|
|
6
|
+
rooted at ${CLAUDE_MARKETPLACES_DIR}/, at any other ${VAR}, or at a plain
|
|
7
|
+
workspace-relative path is accepted -- an entry may ship non-plugin content
|
|
8
|
+
(shared rules, lint config, git hooks) alongside a Claude plugin.
|
|
9
|
+
- An entry whose <catalog-metadata><type> is 'claude-marketplace' AND which
|
|
10
|
+
declares at least one <linkfile> lands one of them under
|
|
11
|
+
${CLAUDE_MARKETPLACES_DIR}/, so an entry that declares itself a marketplace
|
|
12
|
+
actually registers one. An entry with no <linkfile> at all is exempt: that
|
|
13
|
+
is the direct-checkout shape that register_direct_checkout_marketplaces
|
|
14
|
+
handles. Entries of any other type (or none) carry no such requirement.
|
|
6
15
|
- All <include> chains are unbroken (every referenced file exists).
|
|
7
16
|
- All flattened project path names are unique across manifests.
|
|
8
17
|
- All <project revision> attributes are pinnable refs: an exact existing git
|
|
@@ -27,6 +36,7 @@ from collections.abc import Callable
|
|
|
27
36
|
from pathlib import Path
|
|
28
37
|
|
|
29
38
|
from kanon_cli.constants import (
|
|
39
|
+
CATALOG_TYPE_CLAUDE_MARKETPLACE,
|
|
30
40
|
GIT_RETRY_COUNT_DEFAULT,
|
|
31
41
|
GIT_RETRY_COUNT_ENV_VAR,
|
|
32
42
|
KANON_GIT_LS_REMOTE_TIMEOUT,
|
|
@@ -47,36 +57,196 @@ LsRemoteRunner = Callable[[str, str], tuple[int, str, str]]
|
|
|
47
57
|
_FULL_SHA_RE = re.compile(r"^[0-9a-f]{40}$")
|
|
48
58
|
|
|
49
59
|
|
|
50
|
-
def
|
|
51
|
-
"""
|
|
60
|
+
def read_entry_type(xml_path: Path) -> str | None:
|
|
61
|
+
"""Return the entry's ``<catalog-metadata><type>`` text, or None.
|
|
52
62
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
63
|
+
A lightweight, side-effect-free read of the one metadata field this module
|
|
64
|
+
needs. It deliberately does NOT reuse
|
|
65
|
+
:func:`kanon_cli.core.metadata._parse_catalog_metadata`: that parser raises
|
|
66
|
+
on any missing REQUIRED field and warns on stderr for missing RECOMMENDED
|
|
67
|
+
ones, which is ``kanon validate metadata``'s job (spec Section 3.5
|
|
68
|
+
soft-spot 1), not this module's. A metadata problem must be reported once,
|
|
69
|
+
by the command that owns it -- never as a spurious linkfile error here.
|
|
56
70
|
|
|
57
71
|
Args:
|
|
58
|
-
xml_path: Path to the
|
|
72
|
+
xml_path: Path to the catalog entry manifest.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
The stripped ``<type>`` text, or None when the file is unparseable, has
|
|
76
|
+
no ``<catalog-metadata>`` block, or declares no non-empty ``<type>``.
|
|
77
|
+
"""
|
|
78
|
+
try:
|
|
79
|
+
root = ET.parse(xml_path).getroot()
|
|
80
|
+
except ET.ParseError:
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
for block in root.findall("catalog-metadata"):
|
|
84
|
+
type_el = block.find("type")
|
|
85
|
+
if type_el is not None and type_el.text and type_el.text.strip():
|
|
86
|
+
return type_el.text.strip()
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _dest_containment_error(dest: str) -> str | None:
|
|
91
|
+
"""Return why *dest* escapes the consumer workspace, or None when it is safe.
|
|
92
|
+
|
|
93
|
+
A ``<linkfile dest>`` names a symlink created relative to the top of the
|
|
94
|
+
consumer tree. The property worth enforcing is containment -- the link must
|
|
95
|
+
land inside the workspace -- not which specific variable roots it. Three
|
|
96
|
+
shapes escape and are rejected:
|
|
97
|
+
|
|
98
|
+
- An empty dest (nothing to create).
|
|
99
|
+
- An absolute path (``/etc/...``), which writes outside the workspace
|
|
100
|
+
regardless of where kanon runs.
|
|
101
|
+
- Any ``..`` path component, which climbs out of the workspace.
|
|
102
|
+
|
|
103
|
+
A dest rooted at ``${CLAUDE_MARKETPLACES_DIR}/``, at another ``${VAR}``, or
|
|
104
|
+
at a plain relative path is contained and accepted. A ``${VAR}`` root is
|
|
105
|
+
resolved from the consumer's own ``.kanon``, so the consumer -- not the
|
|
106
|
+
catalog author -- chooses where it lands.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
dest: The raw ``dest`` attribute value, before variable expansion.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
A short reason string when *dest* escapes; None when it is safe.
|
|
113
|
+
"""
|
|
114
|
+
if not dest:
|
|
115
|
+
return "dest is empty"
|
|
116
|
+
if dest.startswith("/"):
|
|
117
|
+
return "dest is an absolute path; it must be relative to the consumer workspace root"
|
|
118
|
+
if ".." in dest.split("/"):
|
|
119
|
+
return "dest contains a '..' component that escapes the consumer workspace"
|
|
120
|
+
return None
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _collect_manifest_chain(xml_path: Path, repo_root: Path) -> list[Path]:
|
|
124
|
+
"""Return *xml_path* plus every manifest reachable through ``<include>``.
|
|
125
|
+
|
|
126
|
+
Depth-first and cycle-safe, mirroring the traversal in
|
|
127
|
+
:func:`validate_include_chain`. Linkfile checks must see the same set of
|
|
128
|
+
``<project>`` elements that ``kanon install`` acts on, and install resolves
|
|
129
|
+
the full include chain -- so a ``<project>`` moved into an included
|
|
130
|
+
``packages.xml`` is validated exactly like one written inline. Missing
|
|
131
|
+
includes are skipped here; :func:`validate_include_chain` owns that error.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
xml_path: The catalog entry manifest to start from.
|
|
135
|
+
repo_root: Repository root used to resolve ``<include name>`` paths.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
The entry manifest followed by each reachable include, in visit order.
|
|
139
|
+
"""
|
|
140
|
+
chain: list[Path] = []
|
|
141
|
+
visited: set[str] = set()
|
|
142
|
+
|
|
143
|
+
def _walk(current: Path) -> None:
|
|
144
|
+
resolved = str(current.resolve())
|
|
145
|
+
if resolved in visited:
|
|
146
|
+
return
|
|
147
|
+
visited.add(resolved)
|
|
148
|
+
chain.append(current)
|
|
149
|
+
try:
|
|
150
|
+
root = ET.parse(current).getroot()
|
|
151
|
+
except ET.ParseError:
|
|
152
|
+
return
|
|
153
|
+
for include in root.findall("include"):
|
|
154
|
+
name = include.get("name")
|
|
155
|
+
if not name:
|
|
156
|
+
continue
|
|
157
|
+
include_path = repo_root / name
|
|
158
|
+
if include_path.exists():
|
|
159
|
+
_walk(include_path)
|
|
160
|
+
|
|
161
|
+
_walk(xml_path)
|
|
162
|
+
return chain
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def validate_linkfile_dest(xml_path: Path, repo_root: Path) -> list[str]:
|
|
166
|
+
"""Validate the ``<linkfile dest>`` attributes reachable from a catalog entry.
|
|
167
|
+
|
|
168
|
+
Two rules, applied across the entry and its whole ``<include>`` chain:
|
|
169
|
+
|
|
170
|
+
1. **Containment (every entry).** Each dest must stay inside the consumer
|
|
171
|
+
workspace -- see :func:`_dest_containment_error`. A dest rooted at
|
|
172
|
+
``${CLAUDE_MARKETPLACES_DIR}/``, at another ``${VAR}``, or at a plain
|
|
173
|
+
relative path all pass. This is what the old blanket
|
|
174
|
+
``${CLAUDE_MARKETPLACES_DIR}/`` prefix requirement was standing in for,
|
|
175
|
+
and it no longer forbids an entry from shipping non-plugin content
|
|
176
|
+
(shared rules, lint config, git hooks) next to a Claude plugin.
|
|
177
|
+
|
|
178
|
+
2. **A marketplace entry that uses linkfiles points one at the marketplace.**
|
|
179
|
+
When the entry declares ``<catalog-metadata><type>claude-marketplace</type>``
|
|
180
|
+
-- the same field ``kanon add`` reads to set
|
|
181
|
+
``KANON_SOURCE_<alias>_MARKETPLACE`` -- and declares at least one
|
|
182
|
+
``<linkfile>``, one of those dests must sit under
|
|
183
|
+
``${CLAUDE_MARKETPLACES_DIR}/``. Otherwise the entry calls itself a
|
|
184
|
+
marketplace while every link it creates lands somewhere else.
|
|
185
|
+
|
|
186
|
+
An entry that declares **no** ``<linkfile>`` at all is exempt, because
|
|
187
|
+
that is the direct-checkout shape:
|
|
188
|
+
:func:`kanon_cli.core.marketplace.register_direct_checkout_marketplaces`
|
|
189
|
+
registers a project whose checkout carries
|
|
190
|
+
``.claude-plugin/marketplace.json`` and which has no ``<linkfile>``
|
|
191
|
+
children. Requiring a marketplace dest there would reject an entry that
|
|
192
|
+
``kanon install`` registers correctly -- the same validator/install
|
|
193
|
+
contradiction this function exists to remove, aimed at a different entry
|
|
194
|
+
shape. The catalog XML alone cannot prove that checkout carries a
|
|
195
|
+
``marketplace.json``, so the absence of linkfiles is the only signal
|
|
196
|
+
available here and validation defers to install rather than guessing.
|
|
197
|
+
|
|
198
|
+
An entry of any other type, or with no ``<type>``, carries no such
|
|
199
|
+
requirement.
|
|
200
|
+
|
|
201
|
+
Errors are de-duplicated before returning. A ``<project>`` reached through
|
|
202
|
+
``<include>`` is visited once per entry that includes it, so a single
|
|
203
|
+
defect in a shared include would otherwise be reported once per consumer.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
xml_path: Path to the catalog entry manifest.
|
|
207
|
+
repo_root: Repository root used to resolve ``<include name>`` paths.
|
|
59
208
|
|
|
60
209
|
Returns:
|
|
61
|
-
List of error messages
|
|
62
|
-
|
|
210
|
+
List of error messages, each naming the file, project, and dest,
|
|
211
|
+
in first-seen order with duplicates removed. Empty when the entry
|
|
212
|
+
passes.
|
|
63
213
|
"""
|
|
64
214
|
errors: list[str] = []
|
|
65
|
-
|
|
66
|
-
|
|
215
|
+
is_marketplace = read_entry_type(xml_path) == CATALOG_TYPE_CLAUDE_MARKETPLACE
|
|
216
|
+
linkfile_count = 0
|
|
217
|
+
marketplace_dest_count = 0
|
|
67
218
|
|
|
68
|
-
for
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
)
|
|
219
|
+
for manifest_path in _collect_manifest_chain(xml_path, repo_root):
|
|
220
|
+
try:
|
|
221
|
+
root = ET.parse(manifest_path).getroot()
|
|
222
|
+
except ET.ParseError:
|
|
223
|
+
continue
|
|
224
|
+
for project in root.findall("project"):
|
|
225
|
+
project_name = project.get("name", "<unknown>")
|
|
226
|
+
for linkfile in project.findall("linkfile"):
|
|
227
|
+
linkfile_count += 1
|
|
228
|
+
dest = linkfile.get("dest", "")
|
|
229
|
+
if dest.startswith(MARKETPLACE_DIR_PREFIX):
|
|
230
|
+
marketplace_dest_count += 1
|
|
231
|
+
continue
|
|
232
|
+
reason = _dest_containment_error(dest)
|
|
233
|
+
if reason is not None:
|
|
234
|
+
errors.append(
|
|
235
|
+
f"{manifest_path}: project '{project_name}' has invalid linkfile dest='{dest}' -- {reason}"
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
if is_marketplace and linkfile_count > 0 and marketplace_dest_count == 0:
|
|
239
|
+
errors.append(
|
|
240
|
+
f"{xml_path}: entry declares "
|
|
241
|
+
f"<catalog-metadata><type>{CATALOG_TYPE_CLAUDE_MARKETPLACE}</type> "
|
|
242
|
+
f"and declares <linkfile> elements, but none target "
|
|
243
|
+
f"{MARKETPLACE_DIR_PREFIX} -- such an entry registers no marketplace. "
|
|
244
|
+
f"Point one linkfile at {MARKETPLACE_DIR_PREFIX}, change <type> to a "
|
|
245
|
+
f"non-marketplace value, or drop the linkfiles to register the "
|
|
246
|
+
f"project as a direct checkout."
|
|
247
|
+
)
|
|
78
248
|
|
|
79
|
-
return errors
|
|
249
|
+
return list(dict.fromkeys(errors))
|
|
80
250
|
|
|
81
251
|
|
|
82
252
|
def validate_include_chain(
|
|
@@ -593,12 +763,20 @@ def validate_marketplace(
|
|
|
593
763
|
"""Validate all marketplace XML files found under repo-specs/.
|
|
594
764
|
|
|
595
765
|
Scans for catalog entry manifests (``*.xml`` with a ``<catalog-metadata>``
|
|
596
|
-
block) and validates each one for linkfile dest
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
766
|
+
block) and validates each one for linkfile dest containment (plus the
|
|
767
|
+
marketplace-dest rule for ``claude-marketplace`` entries that use
|
|
768
|
+
linkfiles), include chain integrity, project path uniqueness, pinnable
|
|
769
|
+
``<project revision>`` format (a deep-path tag, a ``refs/heads/<name>``
|
|
770
|
+
branch ref, or a 40-hex SHA; covering revisions inherited from
|
|
771
|
+
``<default revision>``), and two-tier + local-aware revision existence.
|
|
772
|
+
Exits with a non-zero code if any validation errors are found.
|
|
773
|
+
|
|
774
|
+
Errors are de-duplicated across the whole run before reporting. Linkfile
|
|
775
|
+
and include checks follow each entry's ``<include>`` chain, so a defect in
|
|
776
|
+
a manifest shared by several entries is reached once per entry; reporting
|
|
777
|
+
it once per consumer would inflate the count and bury the distinct
|
|
778
|
+
failures. Identical message text means the same file, project, and reason,
|
|
779
|
+
so collapsing exact duplicates cannot hide a second real defect.
|
|
602
780
|
|
|
603
781
|
Args:
|
|
604
782
|
repo_root: Repository root directory.
|
|
@@ -626,13 +804,15 @@ def validate_marketplace(
|
|
|
626
804
|
for xml_file in marketplace_files:
|
|
627
805
|
rel_path = xml_file.relative_to(repo_root)
|
|
628
806
|
print(f"Validating {rel_path}...")
|
|
629
|
-
all_errors.extend(validate_linkfile_dest(xml_file))
|
|
807
|
+
all_errors.extend(validate_linkfile_dest(xml_file, repo_root))
|
|
630
808
|
all_errors.extend(validate_include_chain(xml_file, repo_root))
|
|
631
809
|
|
|
632
810
|
all_errors.extend(validate_name_uniqueness(marketplace_files))
|
|
633
811
|
all_errors.extend(validate_tag_format(marketplace_files, repo_root))
|
|
634
812
|
all_errors.extend(validate_revision_existence(marketplace_files, repo_root, effective_env, runner))
|
|
635
813
|
|
|
814
|
+
all_errors = list(dict.fromkeys(all_errors))
|
|
815
|
+
|
|
636
816
|
if all_errors:
|
|
637
817
|
print(
|
|
638
818
|
f"\nFound {len(all_errors)} validation error(s):",
|