apm-cli 0.23.1__tar.gz → 0.24.0__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.
- {apm_cli-0.23.1/src/apm_cli.egg-info → apm_cli-0.24.0}/PKG-INFO +1 -1
- {apm_cli-0.23.1 → apm_cli-0.24.0}/pyproject.toml +1 -1
- apm_cli-0.24.0/src/apm_cli/bundle/attest.py +64 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/bundle/packer.py +43 -1
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/bundle/plugin_exporter.py +261 -24
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/cache/git_cache.py +35 -29
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/audit.py +6 -6
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/compile/cli.py +9 -3
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/config.py +76 -63
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/install.py +4 -4
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/mcp.py +3 -5
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/outdated.py +8 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/uninstall/cli.py +3 -3
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/compilation/agents_compiler.py +81 -24
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/compilation/claude_formatter.py +4 -3
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/compilation/context_optimizer.py +12 -2
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/compilation/template_builder.py +16 -5
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/apm_yml.py +1 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/target_detection.py +39 -15
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/download_strategies.py +97 -39
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/github_downloader.py +8 -2
- apm_cli-0.24.0/src/apm_cli/deps/outdated_ref_cache.py +107 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/tiered_ref_resolver.py +33 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/context.py +5 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/drift.py +2 -0
- apm_cli-0.24.0/src/apm_cli/install/helpers/ref_reuse.py +96 -0
- apm_cli-0.24.0/src/apm_cli/install/helpers/ref_seed.py +66 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/package_resolution.py +2 -2
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/phases/resolve.py +16 -17
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/plan.py +23 -12
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/validation.py +56 -0
- apm_cli-0.24.0/src/apm_cli/integration/hook_bundle.py +191 -0
- apm_cli-0.24.0/src/apm_cli/integration/hook_file_routing.py +217 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/hook_integrator.py +69 -39
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/instruction_integrator.py +52 -11
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/kiro_hook_integrator.py +27 -23
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/mcp_integrator_install.py +4 -2
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/skill_integrator.py +19 -14
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/targets.py +2 -1
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/output_mappers.py +64 -4
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/ref_resolver.py +0 -4
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/models/apm_package.py +1 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/models/dependency/identity.py +3 -0
- apm_cli-0.24.0/src/apm_cli/models/dependency/object_fields.py +63 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/models/dependency/reference.py +28 -39
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/policy/schema.py +3 -2
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/security/executables.py +22 -3
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/archive.py +11 -2
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/github_host.py +7 -1
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/yaml_io.py +67 -4
- {apm_cli-0.23.1 → apm_cli-0.24.0/src/apm_cli.egg-info}/PKG-INFO +1 -1
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli.egg-info/SOURCES.txt +6 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/tests/test_github_downloader_token_precedence.py +1 -1
- apm_cli-0.23.1/src/apm_cli/integration/hook_file_routing.py +0 -120
- {apm_cli-0.23.1 → apm_cli-0.24.0}/AUTHORS +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/LICENSE +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/NOTICE +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/README.md +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/setup.cfg +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/client/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/client/_mcp_runtime_args.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/client/antigravity.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/client/base.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/client/claude.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/client/codex.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/client/copilot.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/client/cursor.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/client/gemini.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/client/hermes.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/client/intellij.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/client/kiro.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/client/opencode.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/client/vscode.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/client/windsurf.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/package_manager/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/package_manager/base.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/adapters/package_manager/default_manager.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/bootstrap_mirror.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/bundle/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/bundle/local_bundle.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/bundle/lockfile_enrichment.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/bundle/unpacker.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/cache/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/cache/http_cache.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/cache/integrity.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/cache/locking.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/cache/paths.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/cache/url_normalize.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/cli.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/_apm_yml_writer.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/_helpers.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/approve.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/cache.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/compile/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/compile/watcher.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/deps/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/deps/_utils.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/deps/cli.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/deps/why.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/doctor.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/experimental.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/find.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/init.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/lifecycle.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/list_cmd.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/lock.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/marketplace/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/marketplace/audit.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/marketplace/check.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/marketplace/doctor.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/marketplace/init.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/marketplace/migrate.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/marketplace/outdated.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/marketplace/plugin/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/marketplace/plugin/add.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/marketplace/plugin/remove.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/marketplace/plugin/set.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/marketplace/validate.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/pack.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/plugin/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/plugin/init.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/policy.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/prune.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/publish.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/run.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/runtime.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/self_update.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/targets.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/uninstall/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/uninstall/engine.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/update.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/commands/view.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/compilation/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/compilation/build_id.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/compilation/constants.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/compilation/constitution.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/compilation/constitution_block.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/compilation/distributed_compiler.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/compilation/gemini_formatter.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/compilation/injector.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/compilation/link_resolver.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/compilation/managed_section.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/compilation/output_writer.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/compilation/user_root_context.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/config.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/constants.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/auth.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/azure_cli.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/build_orchestrator.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/command_logger.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/conflict_detector.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/docker_args.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/errors.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/experimental.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/install_audit.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/lifecycle_scripts.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/null_logger.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/operations.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/plugin_manifest.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/safe_installer.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/scope.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/script_executors.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/script_runner.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/script_trust.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/core/token_manager.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/_shared.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/aggregator.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/apm_resolver.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/artifactory_entry.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/artifactory_orchestrator.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/bare_cache.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/clone_engine.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/dependency_graph.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/git_auth_env.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/git_file_transport.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/git_reference_resolver.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/git_remote_ops.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/git_semver_resolver.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/github_downloader_validation.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/host_backends.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/installed_package.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/lockfile.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/outdated_row.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/package_validator.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/path_anchoring.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/plugin_parser.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/registry/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/registry/auth.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/registry/client.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/registry/config_loader.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/registry/extractor.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/registry/feature_gate.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/registry/outdated.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/registry/resolver.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/registry/semver.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/registry_proxy.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/revision_pins.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/shared_clone_cache.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/transport_selection.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/verifier.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/deps/why_walker.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/drift.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/export/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/export/authoring.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/export/declared_license.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/export/formats.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/export/purl.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/export/sbom.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/export/spdx.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/export/spdx_data.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/factory.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/artifactory_resolver.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/cache_pin.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/deployed_paths.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/errors.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/exec_gate.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/gitlab_resolver.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/heals/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/heals/base.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/heals/branch_ref_drift.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/heals/buggy_lockfile_recovery.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/helpers/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/helpers/security_scan.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/insecure_policy.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/integrity.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/local_bundle_handler.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/lsp/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/lsp/integration.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/manifest_reconcile.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/mcp/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/mcp/args.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/mcp/command.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/mcp/conflicts.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/mcp/entry.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/mcp/registry.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/mcp/warnings.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/mcp/writer.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/package_selection.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/phases/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/phases/_redownload.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/phases/_skip_logic.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/phases/audit.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/phases/cleanup.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/phases/download.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/phases/finalize.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/phases/heal.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/phases/integrate.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/phases/local_content.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/phases/lockfile.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/phases/policy_gate.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/phases/policy_target_check.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/phases/post_deps_local.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/phases/targets.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/pipeline.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/presentation/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/presentation/dry_run.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/registry_wiring.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/request.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/root_redirect.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/service.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/services.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/skill_path_migration.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/sources.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/summary.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/target_filter.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/install/template.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/_shared.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/agent_integrator.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/base_integrator.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/canvas_integrator.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/cleanup.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/command_integrator.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/copilot_app_db.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/copilot_app_project.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/copilot_app_workflow_integrator.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/copilot_app_ws.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/copilot_cowork_paths.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/coverage.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/dispatch.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/lsp_integrator.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/mcp_integrator.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/opencode_frontmatter.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/prompt_integrator.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/skill_transformer.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/integration/utils.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/_git_utils.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/_io.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/_shared.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/audit.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/auth_helpers.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/builder.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/client.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/diagnostics.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/drift_check.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/errors.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/git_stderr.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/init_template.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/migration.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/models.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/output_profiles.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/registry.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/resolver.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/semver.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/shadow_detector.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/tag_pattern.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/validator.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/version_check.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/version_pins.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/version_resolver.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/yml_editor.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/marketplace/yml_schema.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/models/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/models/dependency/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/models/dependency/lsp.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/models/dependency/mcp.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/models/dependency/subsets.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/models/dependency/types.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/models/format_detection.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/models/plugin.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/models/results.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/models/validation.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/output/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/output/formatters.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/output/models.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/output/script_formatters.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/policy/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/policy/_constraint_pinning.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/policy/_help_text.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/policy/_shared.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/policy/ci_checks.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/policy/discovery.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/policy/inheritance.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/policy/install_preflight.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/policy/matcher.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/policy/models.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/policy/outcome_routing.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/policy/parser.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/policy/policy_checks.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/policy/project_config.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/primitives/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/primitives/discovery.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/primitives/models.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/primitives/parser.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/registry/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/registry/client.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/registry/integration.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/registry/operations.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/runtime/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/runtime/base.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/runtime/codex_runtime.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/runtime/copilot_runtime.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/runtime/factory.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/runtime/llm_runtime.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/runtime/manager.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/runtime/utils.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/security/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/security/audit_report.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/security/content_scanner.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/security/external/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/security/external/base.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/security/external/gate.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/security/external/generic_sarif.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/security/external/options.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/security/external/registry.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/security/external/runner.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/security/external/sarif_ingest.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/security/external/skillspector.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/security/file_scanner.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/security/gate.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/update_policy.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/atomic_io.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/console.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/content_hash.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/diagnostics.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/exclude.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/file_ops.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/git_env.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/git_sparse.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/guards.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/helpers.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/install_tui.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/normalization.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/path_security.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/paths.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/patterns.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/perf_stats.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/reflink.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/short_sha.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/subprocess_env.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/utils/version_checker.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/version.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/workflow/__init__.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/workflow/discovery.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/workflow/parser.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli/workflow/runner.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli.egg-info/dependency_links.txt +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli.egg-info/entry_points.txt +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli.egg-info/requires.txt +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/src/apm_cli.egg-info/top_level.txt +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/tests/test_apm_package_models.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/tests/test_apm_resolver.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/tests/test_codex_docker_args_fix.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/tests/test_codex_empty_string_and_defaults.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/tests/test_collision_integration.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/tests/test_console.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/tests/test_distributed_compilation.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/tests/test_empty_string_and_defaults.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/tests/test_enhanced_discovery.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/tests/test_github_downloader.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/tests/test_gitlab_git_transport.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/tests/test_lockfile.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/tests/test_runnable_prompts.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/tests/test_runtime_manager_token_precedence.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/tests/test_token_manager.py +0 -0
- {apm_cli-0.23.1 → apm_cli-0.24.0}/tests/test_virtual_package_multi_install.py +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Shared per-file provenance verification for the pack pipelines (#2013).
|
|
2
|
+
|
|
3
|
+
Both pack formats copy dependency files that ``apm install`` recorded in
|
|
4
|
+
``apm.lock.yaml`` under ``deployed_files`` + ``deployed_file_hashes``:
|
|
5
|
+
|
|
6
|
+
* ``--format plugin`` (:mod:`apm_cli.bundle.plugin_exporter`)
|
|
7
|
+
* ``--format apm`` (:mod:`apm_cli.bundle.packer`)
|
|
8
|
+
|
|
9
|
+
Before a byte enters a bundle its on-disk copy is verified against the
|
|
10
|
+
attested SHA-256 recorded at install time. A file that was tampered or
|
|
11
|
+
corrupted after ``apm install`` must never enter a bundle silently. Keeping
|
|
12
|
+
the check in ONE place gives both pack paths identical semantics and avoids a
|
|
13
|
+
copy-pasted block that would trip the pylint R0801 duplication gate.
|
|
14
|
+
|
|
15
|
+
Tolerance rule (forward-compat): a file with *no* recorded hash -- either an
|
|
16
|
+
older lockfile with an empty ``deployed_file_hashes`` or a specific path with
|
|
17
|
+
no recorded entry -- is packed without verification. Absence of an attestation
|
|
18
|
+
is tolerated; a *mismatched* attestation is a hard error. The unverified gap
|
|
19
|
+
is surfaced as a debug diagnostic so ``apm audit``-minded users can see it.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import logging
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
from ..utils.content_hash import compute_file_hash
|
|
26
|
+
|
|
27
|
+
_logger = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def verify_attested_file(
|
|
31
|
+
source: Path,
|
|
32
|
+
expected_hash: str | None,
|
|
33
|
+
dep_label: str,
|
|
34
|
+
rel_display: str,
|
|
35
|
+
) -> None:
|
|
36
|
+
"""Fail loudly when *source* diverges from its attested SHA-256.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
source: On-disk file being packed.
|
|
40
|
+
expected_hash: The ``"sha256:<hex>"`` recorded in
|
|
41
|
+
``deployed_file_hashes``, or ``None`` when no hash was recorded.
|
|
42
|
+
dep_label: Dependency identifier (``repo_url``) for the error message.
|
|
43
|
+
rel_display: Human-readable path shown in diagnostics / errors.
|
|
44
|
+
|
|
45
|
+
Raises:
|
|
46
|
+
ValueError: When a recorded hash exists and the on-disk content does
|
|
47
|
+
not match it.
|
|
48
|
+
"""
|
|
49
|
+
if not expected_hash:
|
|
50
|
+
_logger.debug(
|
|
51
|
+
"no attested hash for %r from %s; packed without integrity "
|
|
52
|
+
"verification (older lockfile)",
|
|
53
|
+
rel_display,
|
|
54
|
+
dep_label,
|
|
55
|
+
)
|
|
56
|
+
return
|
|
57
|
+
actual = compute_file_hash(source)
|
|
58
|
+
if actual != expected_hash:
|
|
59
|
+
raise ValueError(
|
|
60
|
+
f"Cannot pack dependency {dep_label}: installed file {rel_display!r} "
|
|
61
|
+
"does not match the hash recorded in apm.lock.yaml. The installed "
|
|
62
|
+
"copy may be stale or tampered. Run 'apm install' to restore "
|
|
63
|
+
"attested content, then pack again."
|
|
64
|
+
)
|
|
@@ -13,6 +13,7 @@ from ..utils.archive import (
|
|
|
13
13
|
write_tar_archive,
|
|
14
14
|
write_zip_archive,
|
|
15
15
|
)
|
|
16
|
+
from .attest import verify_attested_file
|
|
16
17
|
from .lockfile_enrichment import _filter_files_by_target, enrich_lockfile_for_pack
|
|
17
18
|
|
|
18
19
|
|
|
@@ -158,10 +159,19 @@ def pack_bundle(
|
|
|
158
159
|
# not portable and is bundled separately via the project's own files
|
|
159
160
|
# (or rejected outright at L89-97 for manifest-declared local deps).
|
|
160
161
|
all_deployed: list[str] = []
|
|
162
|
+
# Provenance map: deployed-path -> (attested SHA-256, dependency label).
|
|
163
|
+
# ``deployed_file_hashes`` is keyed by the on-disk deployed path recorded
|
|
164
|
+
# at install time (see install/phases/lockfile.compute_deployed_hashes), so
|
|
165
|
+
# verification below must look up the on-disk path, not the bundle path.
|
|
166
|
+
deployed_hashes: dict[str, str] = {}
|
|
167
|
+
hash_dep_labels: dict[str, str] = {}
|
|
161
168
|
for dep in lockfile.get_all_dependencies():
|
|
162
169
|
if dep.source == "local":
|
|
163
170
|
continue
|
|
164
171
|
all_deployed.extend(dep.deployed_files)
|
|
172
|
+
for _dpath, _dhash in dep.deployed_file_hashes.items():
|
|
173
|
+
deployed_hashes[_dpath] = _dhash
|
|
174
|
+
hash_dep_labels[_dpath] = dep.repo_url
|
|
165
175
|
|
|
166
176
|
filtered_files, path_mappings = _filter_files_by_target(all_deployed, effective_target)
|
|
167
177
|
# Deduplicate while preserving order
|
|
@@ -250,7 +260,12 @@ def pack_bundle(
|
|
|
250
260
|
bundle_dir.mkdir(parents=True, exist_ok=True)
|
|
251
261
|
bundle_dir_resolved = bundle_dir.resolve()
|
|
252
262
|
|
|
253
|
-
# 7. Copy files preserving directory structure
|
|
263
|
+
# 7. Copy files preserving directory structure.
|
|
264
|
+
# Provenance gate (#2013): each dependency file recorded in the lockfile
|
|
265
|
+
# is verified against its attested SHA-256 before it enters the bundle --
|
|
266
|
+
# the same integrity guarantee the plugin format enforces, applied to the
|
|
267
|
+
# default/most-used ``apm`` format. Files with no recorded hash (older
|
|
268
|
+
# lockfiles) pack without verification; a mismatch fails loud.
|
|
254
269
|
for rel_path in unique_files:
|
|
255
270
|
# For cross-target mapped files, read from the original disk path
|
|
256
271
|
disk_path = path_mappings.get(rel_path, rel_path)
|
|
@@ -264,8 +279,35 @@ def pack_bundle(
|
|
|
264
279
|
if src.is_dir():
|
|
265
280
|
from ..security.gate import ignore_non_content
|
|
266
281
|
|
|
282
|
+
# Verify each contained file's attested hash and re-assert
|
|
283
|
+
# containment per child. copytree already drops symlinks via
|
|
284
|
+
# ignore_non_content, but the walk guards against a directory
|
|
285
|
+
# symlink whose target escapes the project root regardless of the
|
|
286
|
+
# walker's version-specific symlink-following behaviour.
|
|
287
|
+
disk_base = disk_path.rstrip("/")
|
|
288
|
+
for child in sorted(src.rglob("*")):
|
|
289
|
+
if not child.is_file() or child.is_symlink():
|
|
290
|
+
continue
|
|
291
|
+
if not child.resolve().is_relative_to(project_root_resolved):
|
|
292
|
+
raise ValueError(
|
|
293
|
+
f"Refusing to pack path that escapes project root: "
|
|
294
|
+
f"{child.relative_to(project_root)!r}"
|
|
295
|
+
)
|
|
296
|
+
child_key = f"{disk_base}/{child.relative_to(src).as_posix()}"
|
|
297
|
+
verify_attested_file(
|
|
298
|
+
child,
|
|
299
|
+
deployed_hashes.get(child_key),
|
|
300
|
+
hash_dep_labels.get(child_key, "dependency"),
|
|
301
|
+
child_key,
|
|
302
|
+
)
|
|
267
303
|
shutil.copytree(src, dest, dirs_exist_ok=True, ignore=ignore_non_content)
|
|
268
304
|
else:
|
|
305
|
+
verify_attested_file(
|
|
306
|
+
src,
|
|
307
|
+
deployed_hashes.get(disk_path),
|
|
308
|
+
hash_dep_labels.get(disk_path, "dependency"),
|
|
309
|
+
disk_path,
|
|
310
|
+
)
|
|
269
311
|
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
270
312
|
shutil.copy2(src, dest, follow_symlinks=False)
|
|
271
313
|
|
|
@@ -11,7 +11,7 @@ import hashlib
|
|
|
11
11
|
import json
|
|
12
12
|
import re
|
|
13
13
|
import shutil
|
|
14
|
-
from pathlib import Path, PurePosixPath
|
|
14
|
+
from pathlib import Path, PurePosixPath, PureWindowsPath
|
|
15
15
|
|
|
16
16
|
import yaml
|
|
17
17
|
|
|
@@ -30,6 +30,7 @@ from ..utils.archive import (
|
|
|
30
30
|
)
|
|
31
31
|
from ..utils.console import _rich_warning
|
|
32
32
|
from ..utils.path_security import PathTraversalError, ensure_path_within, safe_rmtree
|
|
33
|
+
from .attest import verify_attested_file
|
|
33
34
|
from .packer import PackResult
|
|
34
35
|
|
|
35
36
|
# ---------------------------------------------------------------------------
|
|
@@ -417,6 +418,217 @@ def _dep_install_path(dep: LockedDependency, apm_modules_dir: Path) -> Path:
|
|
|
417
418
|
return dep_ref.get_install_path(apm_modules_dir)
|
|
418
419
|
|
|
419
420
|
|
|
421
|
+
def _deployed_path_parts(rel_path: str) -> tuple[str, ...]:
|
|
422
|
+
"""Return safe POSIX path parts for a lockfile deployed_files entry."""
|
|
423
|
+
rel = rel_path.replace("\\", "/")
|
|
424
|
+
pure = PurePosixPath(rel)
|
|
425
|
+
if pure.is_absolute() or PureWindowsPath(rel).is_absolute():
|
|
426
|
+
raise ValueError(f"Refusing to pack absolute deployed file path: {rel_path!r}")
|
|
427
|
+
parts = pure.parts
|
|
428
|
+
if any(part in ("", ".", "..") for part in parts):
|
|
429
|
+
raise ValueError(f"Refusing to pack unsafe deployed file path: {rel_path!r}")
|
|
430
|
+
return parts
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def _skill_name_from_deployed_parts(parts: tuple[str, ...]) -> str | None:
|
|
434
|
+
"""Return the deployed skill name when *parts* point inside a skills dir."""
|
|
435
|
+
if len(parts) >= 3 and parts[0].startswith(".") and parts[1] == "skills":
|
|
436
|
+
return parts[2]
|
|
437
|
+
if len(parts) >= 2 and parts[0] == "skills":
|
|
438
|
+
return parts[1]
|
|
439
|
+
return None
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
def _plugin_rel_for_deployed_path(
|
|
443
|
+
rel_path: str,
|
|
444
|
+
skill_subset: set[str] | None,
|
|
445
|
+
) -> str | None:
|
|
446
|
+
"""Map an installed deployed_files path back to plugin-native output layout."""
|
|
447
|
+
parts = _deployed_path_parts(rel_path)
|
|
448
|
+
if not parts:
|
|
449
|
+
return None
|
|
450
|
+
|
|
451
|
+
if parts[0] == "skills":
|
|
452
|
+
skill_name = _skill_name_from_deployed_parts(parts)
|
|
453
|
+
if skill_subset and (skill_name is None or skill_name not in skill_subset):
|
|
454
|
+
return None
|
|
455
|
+
plugin_parts = list(parts)
|
|
456
|
+
elif parts[0] in {"agents", "commands", "instructions", "extensions"}:
|
|
457
|
+
plugin_parts = list(parts)
|
|
458
|
+
elif len(parts) >= 3 and parts[0].startswith("."):
|
|
459
|
+
skill_name = _skill_name_from_deployed_parts(parts)
|
|
460
|
+
if skill_name is not None:
|
|
461
|
+
if skill_subset and skill_name not in skill_subset:
|
|
462
|
+
return None
|
|
463
|
+
plugin_parts = ["skills", *parts[2:]]
|
|
464
|
+
elif parts[1] == "agents":
|
|
465
|
+
plugin_parts = ["agents", *parts[2:]]
|
|
466
|
+
elif parts[1] in {"commands", "prompts"}:
|
|
467
|
+
plugin_parts = ["commands", *parts[2:]]
|
|
468
|
+
elif parts[1] in {"instructions", "rules", "steering"}:
|
|
469
|
+
plugin_parts = ["instructions", *parts[2:]]
|
|
470
|
+
elif parts[1] == "extensions":
|
|
471
|
+
plugin_parts = ["extensions", *parts[2:]]
|
|
472
|
+
elif parts[1] == "hooks":
|
|
473
|
+
plugin_parts = ["hooks", *parts[2:]]
|
|
474
|
+
else:
|
|
475
|
+
return None
|
|
476
|
+
elif len(parts) >= 2 and parts[0].startswith(".") and parts[1] == "hooks.json":
|
|
477
|
+
plugin_parts = ["hooks.json"]
|
|
478
|
+
else:
|
|
479
|
+
return None
|
|
480
|
+
|
|
481
|
+
if plugin_parts[0] == "commands" and plugin_parts[-1].endswith(".prompt.md"):
|
|
482
|
+
plugin_parts[-1] = _rename_prompt(plugin_parts[-1])
|
|
483
|
+
return PurePosixPath(*plugin_parts).as_posix()
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
def _verify_attested_hash(
|
|
487
|
+
source: Path,
|
|
488
|
+
project_root: Path,
|
|
489
|
+
dep: LockedDependency,
|
|
490
|
+
) -> None:
|
|
491
|
+
"""Fail loudly when a packed deployed file diverges from its attested hash.
|
|
492
|
+
|
|
493
|
+
``deployed_file_hashes`` records the SHA-256 (``"sha256:<hex>"``) of each
|
|
494
|
+
file at install time. Verifying the on-disk copy before packing closes the
|
|
495
|
+
integrity half of the provenance hole: a deployed file that was tampered
|
|
496
|
+
or corrupted after ``apm install`` must never enter the bundle silently.
|
|
497
|
+
|
|
498
|
+
Files with no recorded hash (older lockfiles predating
|
|
499
|
+
``deployed_file_hashes``) are packed without verification -- absence of an
|
|
500
|
+
attestation is forward-compat tolerated, presence of a *mismatched* one is
|
|
501
|
+
a hard error. Delegates to the shared :func:`verify_attested_file` helper so
|
|
502
|
+
the plugin and archive pack paths share one implementation.
|
|
503
|
+
"""
|
|
504
|
+
rel = source.relative_to(project_root).as_posix()
|
|
505
|
+
expected = dep.deployed_file_hashes.get(rel) if dep.deployed_file_hashes else None
|
|
506
|
+
verify_attested_file(source, expected, dep.repo_url, rel)
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
def _append_deployed_component(
|
|
510
|
+
components: list[tuple[Path, str]],
|
|
511
|
+
source: Path,
|
|
512
|
+
output_rel: str,
|
|
513
|
+
seen_outputs: set[str],
|
|
514
|
+
project_root: Path,
|
|
515
|
+
dep: LockedDependency,
|
|
516
|
+
) -> None:
|
|
517
|
+
"""Append one deployed component unless it is unsafe or already mapped."""
|
|
518
|
+
if output_rel in seen_outputs or not _validate_output_rel(output_rel):
|
|
519
|
+
return
|
|
520
|
+
if source.is_file() and not source.is_symlink():
|
|
521
|
+
_verify_attested_hash(source, project_root, dep)
|
|
522
|
+
components.append((source, output_rel))
|
|
523
|
+
seen_outputs.add(output_rel)
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
def _collect_deployed_components(
|
|
527
|
+
project_root: Path,
|
|
528
|
+
dep: LockedDependency,
|
|
529
|
+
) -> list[tuple[Path, str]]:
|
|
530
|
+
"""Collect dependency components from lockfile deployed_files entries."""
|
|
531
|
+
components: list[tuple[Path, str]] = []
|
|
532
|
+
missing: list[str] = []
|
|
533
|
+
seen_outputs: set[str] = set()
|
|
534
|
+
skill_subset = set(dep.skill_subset) if dep.skill_subset else None
|
|
535
|
+
|
|
536
|
+
for rel_path in dep.deployed_files:
|
|
537
|
+
try:
|
|
538
|
+
plugin_rel = _plugin_rel_for_deployed_path(rel_path, skill_subset)
|
|
539
|
+
except ValueError as exc:
|
|
540
|
+
raise ValueError(f"Cannot pack dependency {dep.repo_url}: {exc}") from exc
|
|
541
|
+
if plugin_rel is None:
|
|
542
|
+
continue
|
|
543
|
+
source = project_root / rel_path
|
|
544
|
+
try:
|
|
545
|
+
source = ensure_path_within(source, project_root)
|
|
546
|
+
except PathTraversalError as exc:
|
|
547
|
+
raise ValueError(
|
|
548
|
+
f"Cannot pack dependency {dep.repo_url}: deployed file path "
|
|
549
|
+
f"escapes the project root: {rel_path!r}"
|
|
550
|
+
) from exc
|
|
551
|
+
if not source.exists():
|
|
552
|
+
missing.append(rel_path)
|
|
553
|
+
continue
|
|
554
|
+
if source.is_symlink():
|
|
555
|
+
continue
|
|
556
|
+
if source.is_dir():
|
|
557
|
+
for child in sorted(source.rglob("*")):
|
|
558
|
+
if not child.is_file() or child.is_symlink():
|
|
559
|
+
continue
|
|
560
|
+
# Defense-in-depth: rglob's symlink-following behaviour is
|
|
561
|
+
# Python-version dependent, so re-assert containment on every
|
|
562
|
+
# expanded child rather than trusting the walk. A planted
|
|
563
|
+
# directory symlink whose target escapes ``project_root`` is
|
|
564
|
+
# rejected here even if an intermediate component was a symlink.
|
|
565
|
+
try:
|
|
566
|
+
ensure_path_within(child, project_root)
|
|
567
|
+
except PathTraversalError:
|
|
568
|
+
continue
|
|
569
|
+
child_rel = child.relative_to(source).as_posix()
|
|
570
|
+
child_output = (PurePosixPath(plugin_rel) / child_rel).as_posix()
|
|
571
|
+
_append_deployed_component(
|
|
572
|
+
components, child, child_output, seen_outputs, project_root, dep
|
|
573
|
+
)
|
|
574
|
+
else:
|
|
575
|
+
_append_deployed_component(
|
|
576
|
+
components, source, plugin_rel, seen_outputs, project_root, dep
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
if missing:
|
|
580
|
+
shown_missing = missing[:10]
|
|
581
|
+
remaining = len(missing) - len(shown_missing)
|
|
582
|
+
suffix = f"\n ... and {remaining} more" if remaining else ""
|
|
583
|
+
raise ValueError(
|
|
584
|
+
f"Cannot pack dependency {dep.repo_url}: installed files recorded "
|
|
585
|
+
"in apm.lock.yaml are missing on disk. Run 'apm install' to "
|
|
586
|
+
"restore them, then pack again:\n"
|
|
587
|
+
+ "\n".join(f" - {path}" for path in shown_missing)
|
|
588
|
+
+ suffix
|
|
589
|
+
)
|
|
590
|
+
return components
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
def _cache_would_contribute_primitives(install_path: Path, dep: LockedDependency) -> bool:
|
|
594
|
+
"""Return True if the unattested apm_modules cache holds packable primitives.
|
|
595
|
+
|
|
596
|
+
Used ONLY to decide whether to fail loudly when a locked dependency records
|
|
597
|
+
no ``deployed_files``. This reads the cache to DETECT a provenance gap; it
|
|
598
|
+
never copies cache bytes into the bundle. A dependency that installed
|
|
599
|
+
real components but recorded none of them in the lockfile is a stale or
|
|
600
|
+
partial install -- packing its cache would leak unattested content, so we
|
|
601
|
+
refuse rather than silently pack it.
|
|
602
|
+
"""
|
|
603
|
+
if not install_path.is_dir():
|
|
604
|
+
return False
|
|
605
|
+
probe = _collect_apm_components(install_path / ".apm")
|
|
606
|
+
probe.extend(_collect_root_plugin_components(install_path))
|
|
607
|
+
_collect_bare_skill(install_path, dep, probe)
|
|
608
|
+
return bool(probe)
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
def _cache_would_contribute_hooks_or_mcp(install_path: Path) -> bool:
|
|
612
|
+
"""Return True if the unattested cache holds hooks-config or MCP-config.
|
|
613
|
+
|
|
614
|
+
Hooks/MCP *configuration* (``.apm/hooks/*.json``, root ``hooks.json`` /
|
|
615
|
+
``hooks/``, ``.mcp.json``) is merged into shared host settings by
|
|
616
|
+
``apm install`` and is never recorded in the lockfile ``deployed_files``.
|
|
617
|
+
Because plugin pack now emits only lockfile-attested content, such config
|
|
618
|
+
is dropped from the bundle. This probe drives a transition warning that
|
|
619
|
+
names the dependency whose cached config will NOT be packed; it never
|
|
620
|
+
copies cache bytes. Hook *scripts* recorded in ``deployed_files`` are
|
|
621
|
+
unaffected and still pack.
|
|
622
|
+
"""
|
|
623
|
+
if not install_path.is_dir():
|
|
624
|
+
return False
|
|
625
|
+
if _collect_mcp(install_path):
|
|
626
|
+
return True
|
|
627
|
+
if _collect_hooks_from_apm(install_path / ".apm"):
|
|
628
|
+
return True
|
|
629
|
+
return bool(_collect_hooks_from_root(install_path))
|
|
630
|
+
|
|
631
|
+
|
|
420
632
|
# ---------------------------------------------------------------------------
|
|
421
633
|
# Main exporter
|
|
422
634
|
# ---------------------------------------------------------------------------
|
|
@@ -500,34 +712,59 @@ def export_plugin_bundle(
|
|
|
500
712
|
):
|
|
501
713
|
continue
|
|
502
714
|
|
|
503
|
-
install_path = _dep_install_path(dep, apm_modules_dir)
|
|
504
|
-
if not install_path.is_dir():
|
|
505
|
-
continue
|
|
506
|
-
|
|
507
715
|
dep_name = dep.repo_url
|
|
508
716
|
|
|
509
|
-
#
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
#
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
717
|
+
# Provenance rule (issue #1999 follow-up): a dependency's content
|
|
718
|
+
# is packed EXCLUSIVELY from what the lockfile attests via
|
|
719
|
+
# ``deployed_files`` (+ per-file ``deployed_file_hashes``).
|
|
720
|
+
# ``apm_modules`` is an unattested cache -- it carries no integrity
|
|
721
|
+
# or provenance guarantee, so no bytes from it may reach the bundle.
|
|
722
|
+
install_path = _dep_install_path(dep, apm_modules_dir)
|
|
723
|
+
if dep.deployed_files:
|
|
724
|
+
dep_components = _collect_deployed_components(project_root, dep)
|
|
725
|
+
if dep.skill_subset and not dep_components:
|
|
726
|
+
declared_skills = ", ".join(dep.skill_subset)
|
|
727
|
+
raise ValueError(
|
|
728
|
+
f"Cannot pack dependency {dep.repo_url}: the skills "
|
|
729
|
+
f"recorded in apm.lock.yaml (skill_subset: {declared_skills}) "
|
|
730
|
+
"were not found among its installed files. Run 'apm install' "
|
|
731
|
+
"to re-deploy the expected skills, then pack again."
|
|
732
|
+
)
|
|
733
|
+
elif _cache_would_contribute_primitives(install_path, dep):
|
|
734
|
+
# Unattested primitives sit in the cache but the lockfile
|
|
735
|
+
# recorded none of them: a stale or partial install. Refuse
|
|
736
|
+
# to pack the cache -- fail loudly with a fix.
|
|
737
|
+
raise ValueError(
|
|
738
|
+
f"Cannot pack dependency {dep.repo_url}: the lockfile records "
|
|
739
|
+
"no deployed files for it, but installed content that cannot "
|
|
740
|
+
"be verified exists in the apm_modules cache (a stale or "
|
|
741
|
+
"partial install). Run 'apm install' to record provenance in "
|
|
742
|
+
"apm.lock.yaml, then pack again."
|
|
743
|
+
)
|
|
744
|
+
else:
|
|
745
|
+
# No attested content and nothing packable in the cache: the
|
|
746
|
+
# dependency contributes no plugin primitives (e.g. an
|
|
747
|
+
# MCP-only or hooks-config-only package). Skip it cleanly.
|
|
748
|
+
dep_components = []
|
|
749
|
+
|
|
750
|
+
# Transition warning (#2013): dependency hooks/MCP *config* lives in
|
|
751
|
+
# the unattested cache and is never packed. Name the dependency so
|
|
752
|
+
# an author who relied on it merging into shared settings is not
|
|
753
|
+
# surprised by the silent exclusion. Attested primitives are packed
|
|
754
|
+
# regardless of this warning.
|
|
755
|
+
if _cache_would_contribute_hooks_or_mcp(install_path):
|
|
756
|
+
_warn = (
|
|
757
|
+
f"dependency {dep.repo_url} contributed hooks/MCP config that "
|
|
758
|
+
"is not attested in apm.lock.yaml; it will NOT be packed. "
|
|
759
|
+
"Attested primitives (skills/agents/etc.) are unaffected."
|
|
760
|
+
)
|
|
761
|
+
if logger:
|
|
762
|
+
logger.warning(_warn)
|
|
763
|
+
else:
|
|
764
|
+
_rich_warning(_warn, symbol="warning")
|
|
518
765
|
|
|
519
766
|
_merge_file_map(file_map, dep_components, dep_name, force, collisions)
|
|
520
767
|
|
|
521
|
-
# Hooks -- deps merge (first wins among deps)
|
|
522
|
-
dep_hooks = _collect_hooks_from_apm(dep_apm_dir)
|
|
523
|
-
dep_hooks_root = _collect_hooks_from_root(install_path)
|
|
524
|
-
_deep_merge(dep_hooks, dep_hooks_root, overwrite=False)
|
|
525
|
-
_deep_merge(merged_hooks, dep_hooks, overwrite=False)
|
|
526
|
-
|
|
527
|
-
# MCP -- deps merge (first wins among deps)
|
|
528
|
-
dep_mcp = _collect_mcp(install_path)
|
|
529
|
-
_deep_merge(merged_mcp, dep_mcp, overwrite=False)
|
|
530
|
-
|
|
531
768
|
# 6. Collect own components (.apm/ and root-level)
|
|
532
769
|
own_apm_dir = project_root / ".apm"
|
|
533
770
|
own_components = _collect_apm_components(own_apm_dir)
|
|
@@ -535,7 +535,12 @@ class GitCache:
|
|
|
535
535
|
subprocess_env = env if env is not None else git_subprocess_env()
|
|
536
536
|
|
|
537
537
|
try:
|
|
538
|
-
# Clone from local bare repo (fast, no network)
|
|
538
|
+
# Clone from local bare repo (fast, no network).
|
|
539
|
+
# ``promisor`` and ``partialclonefilter`` ride on the clone
|
|
540
|
+
# via ``-c key=val`` (one spawn). ``remote.origin.url``
|
|
541
|
+
# needs a separate post-clone ``git config`` because git
|
|
542
|
+
# clone always rewrites it to the clone source after
|
|
543
|
+
# applying ``-c`` overrides.
|
|
539
544
|
subprocess.run(
|
|
540
545
|
[
|
|
541
546
|
git_exe,
|
|
@@ -545,6 +550,16 @@ class GitCache:
|
|
|
545
550
|
"--shared",
|
|
546
551
|
"--no-checkout",
|
|
547
552
|
"--no-recurse-submodules",
|
|
553
|
+
*(
|
|
554
|
+
[
|
|
555
|
+
"-c",
|
|
556
|
+
"remote.origin.promisor=true",
|
|
557
|
+
"-c",
|
|
558
|
+
"remote.origin.partialclonefilter=blob:none",
|
|
559
|
+
]
|
|
560
|
+
if promisor_url
|
|
561
|
+
else []
|
|
562
|
+
),
|
|
548
563
|
str(bare_dir),
|
|
549
564
|
str(staged),
|
|
550
565
|
],
|
|
@@ -555,34 +570,25 @@ class GitCache:
|
|
|
555
570
|
check=True,
|
|
556
571
|
)
|
|
557
572
|
if promisor_url:
|
|
558
|
-
#
|
|
559
|
-
#
|
|
560
|
-
#
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
"config",
|
|
578
|
-
*cfg_args,
|
|
579
|
-
],
|
|
580
|
-
capture_output=True,
|
|
581
|
-
text=True,
|
|
582
|
-
timeout=10,
|
|
583
|
-
env=subprocess_env,
|
|
584
|
-
check=True,
|
|
585
|
-
)
|
|
573
|
+
# Point origin at the real upstream (clone set it to the
|
|
574
|
+
# local bare). Single config call; the other two promisor
|
|
575
|
+
# keys were already applied via ``-c`` above.
|
|
576
|
+
subprocess.run(
|
|
577
|
+
[
|
|
578
|
+
git_exe,
|
|
579
|
+
*_safe_git_args(),
|
|
580
|
+
"-C",
|
|
581
|
+
str(staged),
|
|
582
|
+
"config",
|
|
583
|
+
"remote.origin.url",
|
|
584
|
+
promisor_url,
|
|
585
|
+
],
|
|
586
|
+
capture_output=True,
|
|
587
|
+
text=True,
|
|
588
|
+
timeout=10,
|
|
589
|
+
env=subprocess_env,
|
|
590
|
+
check=True,
|
|
591
|
+
)
|
|
586
592
|
if sparse_paths:
|
|
587
593
|
# Sparse-cone setup BEFORE checkout. Failures raise
|
|
588
594
|
# (not silently fallen back to full checkout) because
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
"""APM audit command -- content integrity scanning for
|
|
1
|
+
"""APM audit command -- content integrity scanning for installed primitives.
|
|
2
2
|
|
|
3
|
-
Scans installed APM
|
|
4
|
-
characters
|
|
5
|
-
pillar of ``apm audit``; lock-file consistency (``--ci``) and drift
|
|
6
|
-
detection (``--drift``) are planned as future modes.
|
|
3
|
+
Scans installed APM primitives (or arbitrary files) for hidden Unicode
|
|
4
|
+
characters, drift, and lockfile/policy violations.
|
|
7
5
|
|
|
8
6
|
Exit codes:
|
|
9
7
|
0 -- clean (no findings, or info-only)
|
|
@@ -1036,7 +1034,9 @@ def _audit_content_scan(
|
|
|
1036
1034
|
# -- Command --------------------------------------------------------
|
|
1037
1035
|
|
|
1038
1036
|
|
|
1039
|
-
@click.command(
|
|
1037
|
+
@click.command(
|
|
1038
|
+
help="Scan installed primitives for hidden Unicode, drift, and lockfile/policy violations"
|
|
1039
|
+
)
|
|
1040
1040
|
@click.argument("package", required=False)
|
|
1041
1041
|
@click.option(
|
|
1042
1042
|
"--file",
|
|
@@ -250,6 +250,11 @@ def _resolve_compile_target(target):
|
|
|
250
250
|
if not has_non_vscode_agents:
|
|
251
251
|
return "vscode"
|
|
252
252
|
return frozenset(families)
|
|
253
|
+
if families == {"agents"} and "antigravity" in target_set and len(target_set) > 1:
|
|
254
|
+
# Mixed Antigravity + AGENTS.md-only consumers share AGENTS.md but
|
|
255
|
+
# do not all read .agents/rules/. Preserve mixed-target context so
|
|
256
|
+
# downstream dedup stays disabled for AGENTS.md-only consumers.
|
|
257
|
+
return frozenset({"agents"})
|
|
253
258
|
if "claude" in families:
|
|
254
259
|
return "claude"
|
|
255
260
|
if "gemini" in families:
|
|
@@ -957,9 +962,10 @@ def _run_compilation(
|
|
|
957
962
|
help=(
|
|
958
963
|
"Include the instructions section in CLAUDE.md even when .claude/rules/ is "
|
|
959
964
|
"already populated, and in AGENTS.md even when .github/instructions/ is "
|
|
960
|
-
"already populated
|
|
961
|
-
"
|
|
962
|
-
"
|
|
965
|
+
"already populated, or .agents/rules/ for Antigravity. Overrides the "
|
|
966
|
+
"default deduplication that normally omits these sections to avoid "
|
|
967
|
+
"duplicate context. Affects the Claude, Copilot, and Antigravity "
|
|
968
|
+
"deduplication paths. Alias: --no-dedup."
|
|
963
969
|
),
|
|
964
970
|
)
|
|
965
971
|
@click.option(
|