apm-cli 0.18.0__tar.gz → 0.19.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.18.0 → apm_cli-0.19.0}/AUTHORS +1 -0
- {apm_cli-0.18.0/src/apm_cli.egg-info → apm_cli-0.19.0}/PKG-INFO +1 -1
- {apm_cli-0.18.0 → apm_cli-0.19.0}/pyproject.toml +1 -1
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/base.py +8 -5
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/claude.py +1 -6
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/codex.py +1 -13
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/copilot.py +1 -13
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/bundle/lockfile_enrichment.py +3 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/cli.py +57 -1
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/audit.py +82 -23
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/compile/cli.py +14 -3
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/experimental.py +2 -2
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/publish.py +34 -34
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/agents_compiler.py +25 -8
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/auth.py +148 -18
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/experimental.py +10 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/safe_installer.py +2 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/target_detection.py +31 -1
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/download_strategies.py +48 -3
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/plugin_parser.py +123 -15
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/drift.py +19 -2
- apm_cli-0.19.0/src/apm_cli/install/manifest_reconcile.py +112 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/local_content.py +109 -13
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/lockfile.py +46 -10
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/post_deps_local.py +17 -3
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/targets.py +248 -268
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/services.py +88 -4
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/base_integrator.py +7 -1
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/hook_integrator.py +131 -4
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/instruction_integrator.py +83 -21
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/skill_integrator.py +33 -7
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/targets.py +103 -3
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/dependency/mcp.py +29 -1
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/dependency/reference.py +9 -3
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/skillspector.py +18 -5
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/github_host.py +24 -5
- {apm_cli-0.18.0 → apm_cli-0.19.0/src/apm_cli.egg-info}/PKG-INFO +1 -1
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli.egg-info/SOURCES.txt +1 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/LICENSE +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/NOTICE +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/README.md +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/setup.cfg +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/_mcp_runtime_args.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/cursor.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/gemini.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/intellij.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/opencode.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/vscode.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/windsurf.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/package_manager/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/package_manager/base.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/package_manager/default_manager.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/bundle/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/bundle/local_bundle.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/bundle/packer.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/bundle/plugin_exporter.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/bundle/unpacker.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/cache/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/cache/git_cache.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/cache/http_cache.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/cache/integrity.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/cache/locking.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/cache/paths.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/cache/url_normalize.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/_apm_yml_writer.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/_helpers.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/cache.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/compile/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/compile/watcher.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/config.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/deps/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/deps/_utils.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/deps/cli.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/deps/why.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/doctor.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/find.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/init.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/install.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/list_cmd.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/lock.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/audit.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/check.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/doctor.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/init.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/migrate.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/outdated.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/plugin/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/plugin/add.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/plugin/remove.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/plugin/set.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/publish.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/validate.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/mcp.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/outdated.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/pack.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/plugin/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/plugin/init.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/policy.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/prune.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/run.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/runtime.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/self_update.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/targets.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/uninstall/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/uninstall/cli.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/uninstall/engine.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/update.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/view.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/build_id.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/claude_formatter.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/constants.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/constitution.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/constitution_block.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/context_optimizer.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/distributed_compiler.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/gemini_formatter.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/injector.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/link_resolver.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/managed_section.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/output_writer.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/template_builder.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/config.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/constants.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/apm_yml.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/azure_cli.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/build_orchestrator.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/command_logger.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/conflict_detector.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/docker_args.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/errors.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/install_audit.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/null_logger.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/operations.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/plugin_manifest.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/scope.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/script_runner.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/token_manager.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/_shared.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/aggregator.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/apm_resolver.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/artifactory_entry.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/artifactory_orchestrator.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/bare_cache.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/clone_engine.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/dependency_graph.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/git_auth_env.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/git_reference_resolver.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/git_remote_ops.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/git_semver_resolver.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/github_downloader.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/github_downloader_validation.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/host_backends.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/installed_package.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/lockfile.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/outdated_row.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/package_validator.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/path_anchoring.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/auth.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/client.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/config_loader.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/extractor.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/feature_gate.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/outdated.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/resolver.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/semver.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry_proxy.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/shared_clone_cache.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/tiered_ref_resolver.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/transport_selection.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/verifier.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/why_walker.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/drift.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/factory.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/artifactory_resolver.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/cache_pin.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/context.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/errors.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/gitlab_resolver.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/heals/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/heals/base.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/heals/branch_ref_drift.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/heals/buggy_lockfile_recovery.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/helpers/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/helpers/security_scan.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/insecure_policy.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/local_bundle_handler.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/lsp/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/lsp/integration.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/args.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/command.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/conflicts.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/entry.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/registry.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/warnings.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/writer.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/package_resolution.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/package_selection.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/_redownload.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/_skip_logic.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/audit.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/cleanup.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/download.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/finalize.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/heal.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/integrate.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/policy_gate.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/policy_target_check.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/resolve.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/pipeline.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/plan.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/presentation/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/presentation/dry_run.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/registry_wiring.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/request.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/root_redirect.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/service.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/skill_path_migration.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/sources.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/summary.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/template.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/validation.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/_shared.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/agent_integrator.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/cleanup.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/command_integrator.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/copilot_app_db.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/copilot_app_project.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/copilot_app_workflow_integrator.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/copilot_app_ws.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/copilot_cowork_paths.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/coverage.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/dispatch.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/lsp_integrator.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/mcp_integrator.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/mcp_integrator_install.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/opencode_frontmatter.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/prompt_integrator.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/skill_transformer.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/utils.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/_git_utils.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/_io.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/_shared.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/audit.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/builder.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/client.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/diagnostics.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/drift_check.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/errors.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/git_stderr.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/init_template.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/migration.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/models.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/output_mappers.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/output_profiles.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/pr_integration.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/publisher.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/ref_resolver.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/registry.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/resolver.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/semver.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/shadow_detector.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/tag_pattern.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/validator.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/version_check.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/version_pins.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/version_resolver.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/yml_editor.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/yml_schema.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/apm_package.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/dependency/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/dependency/lsp.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/dependency/types.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/format_detection.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/plugin.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/results.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/validation.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/output/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/output/formatters.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/output/models.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/output/script_formatters.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/_constraint_pinning.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/_help_text.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/_shared.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/ci_checks.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/discovery.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/inheritance.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/install_preflight.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/matcher.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/models.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/outcome_routing.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/parser.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/policy_checks.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/project_config.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/schema.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/primitives/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/primitives/discovery.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/primitives/models.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/primitives/parser.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/registry/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/registry/client.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/registry/integration.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/registry/operations.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/runtime/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/runtime/base.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/runtime/codex_runtime.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/runtime/copilot_runtime.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/runtime/factory.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/runtime/llm_runtime.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/runtime/manager.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/runtime/utils.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/audit_report.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/content_scanner.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/base.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/gate.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/generic_sarif.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/options.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/registry.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/runner.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/sarif_ingest.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/file_scanner.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/gate.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/update_policy.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/atomic_io.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/console.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/content_hash.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/diagnostics.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/exclude.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/file_ops.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/git_env.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/git_sparse.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/guards.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/helpers.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/install_tui.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/normalization.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/path_security.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/paths.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/patterns.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/perf_stats.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/reflink.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/short_sha.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/subprocess_env.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/version_checker.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/yaml_io.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/version.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/workflow/__init__.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/workflow/discovery.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/workflow/parser.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/workflow/runner.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli.egg-info/dependency_links.txt +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli.egg-info/entry_points.txt +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli.egg-info/requires.txt +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli.egg-info/top_level.txt +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_apm_package_models.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_apm_resolver.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_codex_docker_args_fix.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_codex_empty_string_and_defaults.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_collision_integration.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_console.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_distributed_compilation.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_empty_string_and_defaults.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_enhanced_discovery.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_github_downloader.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_github_downloader_token_precedence.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_lockfile.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_runnable_prompts.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_runtime_manager_token_precedence.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_token_manager.py +0 -0
- {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_virtual_package_multi_install.py +0 -0
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
* Daniel Meppiel (@danielmeppiel) — Microsoft
|
|
6
6
|
* Sergio Sisternes (@sergio-sisternes-epam) — EPAM Systems
|
|
7
|
+
* Nadav Yogev (@nadav-y) — JFrog
|
|
7
8
|
|
|
8
9
|
Maintainers' work on APM is supported by their employers. Project
|
|
9
10
|
decisions are made in the interest of APM and its users, independent
|
|
@@ -633,22 +633,25 @@ class MCPClientAdapter(ABC):
|
|
|
633
633
|
return server_info
|
|
634
634
|
|
|
635
635
|
@staticmethod
|
|
636
|
-
def _determine_config_key(server_url: str, server_name: str) -> str:
|
|
636
|
+
def _determine_config_key(server_url: str, server_name: str | None) -> str:
|
|
637
637
|
"""Return the configuration key to use for *server_url*/*server_name*.
|
|
638
638
|
|
|
639
|
-
The caller-supplied *server_name* takes precedence
|
|
640
|
-
|
|
641
|
-
convention ``owner/repo -> repo
|
|
639
|
+
The caller-supplied *server_name* takes precedence. If it is absent,
|
|
640
|
+
preserve npm-style scoped names such as ``@scope/name`` (one slash by
|
|
641
|
+
npm convention) while keeping the historical ``owner/repo -> repo``
|
|
642
|
+
fallback for registry paths.
|
|
642
643
|
|
|
643
644
|
Args:
|
|
644
645
|
server_url: Registry reference used as fallback source.
|
|
645
|
-
server_name: Explicit caller-supplied name
|
|
646
|
+
server_name: Explicit caller-supplied name, if any.
|
|
646
647
|
|
|
647
648
|
Returns:
|
|
648
649
|
Non-empty configuration key string.
|
|
649
650
|
"""
|
|
650
651
|
if server_name:
|
|
651
652
|
return server_name
|
|
653
|
+
if server_url.startswith("@") and server_url.count("/") == 1:
|
|
654
|
+
return server_url
|
|
652
655
|
if "/" in server_url:
|
|
653
656
|
return server_url.split("/")[-1]
|
|
654
657
|
return server_url
|
|
@@ -239,12 +239,7 @@ class ClaudeClientAdapter(CopilotClientAdapter):
|
|
|
239
239
|
_rich_error(f"MCP server '{server_url}' not found in registry")
|
|
240
240
|
return False
|
|
241
241
|
|
|
242
|
-
|
|
243
|
-
config_key = server_name
|
|
244
|
-
elif "/" in server_url:
|
|
245
|
-
config_key = server_url.split("/")[-1]
|
|
246
|
-
else:
|
|
247
|
-
config_key = server_url
|
|
242
|
+
config_key = self._determine_config_key(server_url, server_name)
|
|
248
243
|
|
|
249
244
|
server_config = self._format_server_config(server_info, env_overrides, runtime_vars)
|
|
250
245
|
ok = self.update_config({config_key: server_config})
|
|
@@ -150,19 +150,7 @@ class CodexClientAdapter(MCPClientAdapter):
|
|
|
150
150
|
if server_info is None:
|
|
151
151
|
return False
|
|
152
152
|
|
|
153
|
-
|
|
154
|
-
if server_name:
|
|
155
|
-
# Use explicitly provided server name
|
|
156
|
-
config_key = server_name
|
|
157
|
-
else: # noqa: PLR5501
|
|
158
|
-
# Extract name from server_url (part after last slash)
|
|
159
|
-
# For URLs like "microsoft/azure-devops-mcp" -> "azure-devops-mcp"
|
|
160
|
-
# For URLs like "github/github-mcp-server" -> "github-mcp-server"
|
|
161
|
-
if "/" in server_url: # noqa: SIM108
|
|
162
|
-
config_key = server_url.split("/")[-1]
|
|
163
|
-
else:
|
|
164
|
-
# Fallback to full server_url if no slash
|
|
165
|
-
config_key = server_url
|
|
153
|
+
config_key = self._determine_config_key(server_url, server_name)
|
|
166
154
|
|
|
167
155
|
# Generate server configuration with environment variable resolution
|
|
168
156
|
server_config = self._format_server_config(server_info, env_overrides, runtime_vars)
|
|
@@ -206,19 +206,7 @@ class CopilotClientAdapter(MCPClientAdapter):
|
|
|
206
206
|
# Generate server configuration with environment and runtime variable resolution
|
|
207
207
|
server_config = self._format_server_config(server_info, env_overrides, runtime_vars)
|
|
208
208
|
|
|
209
|
-
|
|
210
|
-
if server_name:
|
|
211
|
-
# Use explicitly provided server name
|
|
212
|
-
config_key = server_name
|
|
213
|
-
else: # noqa: PLR5501
|
|
214
|
-
# Extract name from server_url (part after last slash)
|
|
215
|
-
# For URLs like "microsoft/azure-devops-mcp" -> "azure-devops-mcp"
|
|
216
|
-
# For URLs like "github/github-mcp-server" -> "github-mcp-server"
|
|
217
|
-
if "/" in server_url: # noqa: SIM108
|
|
218
|
-
config_key = server_url.split("/")[-1]
|
|
219
|
-
else:
|
|
220
|
-
# Fallback to full server_url if no slash
|
|
221
|
-
config_key = server_url
|
|
209
|
+
config_key = self._determine_config_key(server_url, server_name)
|
|
222
210
|
|
|
223
211
|
# Update configuration using the chosen key
|
|
224
212
|
self.update_config({config_key: server_config})
|
|
@@ -4,6 +4,7 @@ Thin wiring layer -- all command logic lives in ``apm_cli.commands.*`` modules.
|
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
import ctypes
|
|
7
|
+
import logging
|
|
7
8
|
import os
|
|
8
9
|
import sys
|
|
9
10
|
import warnings
|
|
@@ -61,6 +62,48 @@ _CLI_EPILOG = (
|
|
|
61
62
|
)
|
|
62
63
|
|
|
63
64
|
|
|
65
|
+
def _configure_logging(verbose: bool = False) -> None:
|
|
66
|
+
"""Configure stdlib logging for the ``apm_cli`` package.
|
|
67
|
+
|
|
68
|
+
Two mechanisms activate debug-level output (either is sufficient):
|
|
69
|
+
|
|
70
|
+
* ``--verbose`` / ``-v`` flag on the ``apm`` command.
|
|
71
|
+
* ``APM_LOG_LEVEL=DEBUG`` environment variable (accepts any stdlib
|
|
72
|
+
level name: DEBUG, INFO, WARNING, ERROR, CRITICAL).
|
|
73
|
+
|
|
74
|
+
When neither is set the ``apm_cli`` logger defaults to WARNING so
|
|
75
|
+
routine runs stay silent. A :class:`~apm_cli.core.auth.SecretRedactionFilter`
|
|
76
|
+
is always installed on the ``apm_cli`` logger to strip token-bearing
|
|
77
|
+
exception strings from debug records regardless of which mechanism
|
|
78
|
+
activated debug mode.
|
|
79
|
+
"""
|
|
80
|
+
env_level_str = os.environ.get("APM_LOG_LEVEL", "").strip().upper()
|
|
81
|
+
env_level: int | None = (
|
|
82
|
+
getattr(logging, env_level_str, None) if env_level_str.isalpha() else None
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if verbose:
|
|
86
|
+
level = logging.DEBUG
|
|
87
|
+
elif env_level is not None:
|
|
88
|
+
level = env_level
|
|
89
|
+
else:
|
|
90
|
+
level = logging.WARNING
|
|
91
|
+
|
|
92
|
+
logging.basicConfig(
|
|
93
|
+
level=level,
|
|
94
|
+
format="%(levelname)s %(name)s %(message)s",
|
|
95
|
+
stream=sys.stderr,
|
|
96
|
+
)
|
|
97
|
+
apm_logger = logging.getLogger("apm_cli")
|
|
98
|
+
apm_logger.setLevel(level)
|
|
99
|
+
|
|
100
|
+
# Install secret-redaction filter (idempotent: skip if already present).
|
|
101
|
+
from apm_cli.core.auth import SecretRedactionFilter
|
|
102
|
+
|
|
103
|
+
if not any(isinstance(f, SecretRedactionFilter) for f in apm_logger.filters):
|
|
104
|
+
apm_logger.addFilter(SecretRedactionFilter())
|
|
105
|
+
|
|
106
|
+
|
|
64
107
|
@click.group(
|
|
65
108
|
help="Agent Package Manager (APM): The package manager for AI-Native Development",
|
|
66
109
|
epilog=_CLI_EPILOG,
|
|
@@ -73,10 +116,22 @@ _CLI_EPILOG = (
|
|
|
73
116
|
is_eager=True,
|
|
74
117
|
help="Show version and exit.",
|
|
75
118
|
)
|
|
119
|
+
@click.option(
|
|
120
|
+
"--verbose",
|
|
121
|
+
"-v",
|
|
122
|
+
is_flag=True,
|
|
123
|
+
default=False,
|
|
124
|
+
help="Enable debug-level logging (equivalent to APM_LOG_LEVEL=DEBUG).",
|
|
125
|
+
)
|
|
76
126
|
@click.pass_context
|
|
77
|
-
def cli(ctx):
|
|
127
|
+
def cli(ctx, verbose: bool) -> None:
|
|
78
128
|
"""Main entry point for the APM CLI."""
|
|
79
129
|
ctx.ensure_object(dict)
|
|
130
|
+
ctx.obj["verbose"] = verbose
|
|
131
|
+
|
|
132
|
+
if verbose:
|
|
133
|
+
# Upgrade to DEBUG when the flag is set; env-var path runs in main().
|
|
134
|
+
_configure_logging(verbose=True)
|
|
80
135
|
|
|
81
136
|
# Suppress only the agents-target deprecation warning so CLI users see
|
|
82
137
|
# the formatted logger.warning() in the install phase, not a double print.
|
|
@@ -267,6 +322,7 @@ def _configure_encoding() -> None:
|
|
|
267
322
|
|
|
268
323
|
def main():
|
|
269
324
|
"""Main entry point for the CLI."""
|
|
325
|
+
_configure_logging() # honours APM_LOG_LEVEL env var; --verbose upgrades in cli()
|
|
270
326
|
_configure_encoding()
|
|
271
327
|
try:
|
|
272
328
|
cli(obj={})
|
|
@@ -103,6 +103,39 @@ def _has_actionable_findings(
|
|
|
103
103
|
)
|
|
104
104
|
|
|
105
105
|
|
|
106
|
+
def _finding_source(finding: ScanFinding) -> str:
|
|
107
|
+
"""Derive the scanner source from a finding's category prefix."""
|
|
108
|
+
if "/" in finding.category:
|
|
109
|
+
prefix = finding.category.split("/", 1)[0]
|
|
110
|
+
if prefix != "apm":
|
|
111
|
+
return prefix
|
|
112
|
+
return "apm"
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _has_external_findings(rows: list[ScanFinding]) -> bool:
|
|
116
|
+
"""Return True if any finding originates from an external scanner."""
|
|
117
|
+
return any(_finding_source(f) != "apm" for f in rows)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _source_counts(rows: list[ScanFinding]) -> dict[str, int]:
|
|
121
|
+
"""Count findings by source for the table title."""
|
|
122
|
+
counts: dict[str, int] = {}
|
|
123
|
+
for f in rows:
|
|
124
|
+
src = _finding_source(f)
|
|
125
|
+
counts[src] = counts.get(src, 0) + 1
|
|
126
|
+
return counts
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _findings_title(rows: list[ScanFinding], has_external: bool) -> str:
|
|
130
|
+
"""Build the findings table title, with per-source counts when mixed."""
|
|
131
|
+
base = f"{STATUS_SYMBOLS['search']} Audit Findings"
|
|
132
|
+
if not has_external:
|
|
133
|
+
return f"{STATUS_SYMBOLS['search']} Content Scan Findings"
|
|
134
|
+
counts = _source_counts(rows)
|
|
135
|
+
parts = [f"{src}: {n}" for src, n in sorted(counts.items())]
|
|
136
|
+
return f"{base} ({', '.join(parts)})"
|
|
137
|
+
|
|
138
|
+
|
|
106
139
|
def _render_findings_table(
|
|
107
140
|
findings_by_file: dict[str, list[ScanFinding]],
|
|
108
141
|
verbose: bool = False,
|
|
@@ -124,6 +157,9 @@ def _render_findings_table(
|
|
|
124
157
|
if not rows:
|
|
125
158
|
return
|
|
126
159
|
|
|
160
|
+
has_external = _has_external_findings(rows)
|
|
161
|
+
title = _findings_title(rows, has_external)
|
|
162
|
+
|
|
127
163
|
if console:
|
|
128
164
|
try:
|
|
129
165
|
from rich.table import Table
|
|
@@ -131,14 +167,19 @@ def _render_findings_table(
|
|
|
131
167
|
from ..security.audit_report import relative_path_for_report
|
|
132
168
|
|
|
133
169
|
table = Table(
|
|
134
|
-
title=
|
|
170
|
+
title=title,
|
|
135
171
|
show_header=True,
|
|
136
172
|
header_style="bold cyan",
|
|
137
173
|
)
|
|
138
174
|
table.add_column("Severity", style="bold", width=10)
|
|
175
|
+
if has_external:
|
|
176
|
+
table.add_column("Source", style="cyan", width=14)
|
|
139
177
|
table.add_column("File", style="white")
|
|
140
178
|
table.add_column("Location", style="dim", width=10)
|
|
141
|
-
|
|
179
|
+
if has_external:
|
|
180
|
+
table.add_column("Category", style="bold white")
|
|
181
|
+
else:
|
|
182
|
+
table.add_column("Codepoint", style="bold white", width=10)
|
|
142
183
|
table.add_column("Description", style="white")
|
|
143
184
|
|
|
144
185
|
sev_styles = {
|
|
@@ -147,12 +188,26 @@ def _render_findings_table(
|
|
|
147
188
|
"info": "dim",
|
|
148
189
|
}
|
|
149
190
|
for f in rows:
|
|
191
|
+
category_or_codepoint = (
|
|
192
|
+
f.category.split("/", 1)[1]
|
|
193
|
+
if has_external and "/" in f.category
|
|
194
|
+
else f.category
|
|
195
|
+
if has_external
|
|
196
|
+
else f.codepoint
|
|
197
|
+
)
|
|
198
|
+
row_cells = [f.severity.upper()]
|
|
199
|
+
if has_external:
|
|
200
|
+
row_cells.append(_finding_source(f))
|
|
201
|
+
row_cells.extend(
|
|
202
|
+
[
|
|
203
|
+
relative_path_for_report(f.file),
|
|
204
|
+
f"{f.line}:{f.column}",
|
|
205
|
+
category_or_codepoint,
|
|
206
|
+
f.description,
|
|
207
|
+
]
|
|
208
|
+
)
|
|
150
209
|
table.add_row(
|
|
151
|
-
|
|
152
|
-
relative_path_for_report(f.file),
|
|
153
|
-
f"{f.line}:{f.column}",
|
|
154
|
-
f.codepoint,
|
|
155
|
-
f.description,
|
|
210
|
+
*row_cells,
|
|
156
211
|
style=sev_styles.get(f.severity, "white"),
|
|
157
212
|
)
|
|
158
213
|
console.print()
|
|
@@ -163,18 +218,17 @@ def _render_findings_table(
|
|
|
163
218
|
|
|
164
219
|
# Fallback: plain text
|
|
165
220
|
_rich_echo("")
|
|
166
|
-
_rich_echo(
|
|
167
|
-
f"{STATUS_SYMBOLS['search']} Content Scan Findings",
|
|
168
|
-
color="cyan",
|
|
169
|
-
bold=True,
|
|
170
|
-
)
|
|
221
|
+
_rich_echo(title, color="cyan", bold=True)
|
|
171
222
|
for f in rows:
|
|
172
223
|
sev_label = f.severity.upper()
|
|
173
224
|
color = (
|
|
174
225
|
"red" if f.severity == "critical" else ("yellow" if f.severity == "warning" else "dim")
|
|
175
226
|
)
|
|
227
|
+
source_part = f" [{_finding_source(f)}]" if has_external else ""
|
|
228
|
+
detail = f.category if has_external else f.codepoint
|
|
176
229
|
_rich_echo(
|
|
177
|
-
f" {sev_label:<10} {f.file} {f.line}:{f.column} {
|
|
230
|
+
f" {sev_label:<10}{source_part} {f.file} {f.line}:{f.column} {detail} "
|
|
231
|
+
f"{f.description}",
|
|
178
232
|
color=color,
|
|
179
233
|
)
|
|
180
234
|
|
|
@@ -669,7 +723,7 @@ def _run_external_scanners(
|
|
|
669
723
|
require_external_scanners_enabled("Ingesting external scanners with --external")
|
|
670
724
|
except ExternalScannersFeatureDisabledError as exc:
|
|
671
725
|
logger.error(str(exc))
|
|
672
|
-
sys.exit(
|
|
726
|
+
sys.exit(3)
|
|
673
727
|
|
|
674
728
|
try:
|
|
675
729
|
return run_external_scanners(
|
|
@@ -681,7 +735,7 @@ def _run_external_scanners(
|
|
|
681
735
|
)
|
|
682
736
|
except ExternalScanError as exc:
|
|
683
737
|
logger.error(str(exc))
|
|
684
|
-
sys.exit(
|
|
738
|
+
sys.exit(3)
|
|
685
739
|
|
|
686
740
|
|
|
687
741
|
def _audit_content_scan(
|
|
@@ -713,8 +767,9 @@ def _audit_content_scan(
|
|
|
713
767
|
|
|
714
768
|
# --format json/sarif/markdown is incompatible with --strip / --dry-run
|
|
715
769
|
if effective_format != "text" and (strip or dry_run):
|
|
716
|
-
|
|
717
|
-
|
|
770
|
+
raise click.UsageError(
|
|
771
|
+
f"--format {effective_format} cannot be combined with --strip or --dry-run"
|
|
772
|
+
)
|
|
718
773
|
|
|
719
774
|
if file_path:
|
|
720
775
|
# -- File mode: scan a single arbitrary file --
|
|
@@ -997,6 +1052,7 @@ def _audit_content_scan(
|
|
|
997
1052
|
help=(
|
|
998
1053
|
"Ingest findings from an external SARIF-native scanner "
|
|
999
1054
|
"(repeatable). Names: skillspector, sarif. "
|
|
1055
|
+
"Not supported with --ci. "
|
|
1000
1056
|
"Requires 'apm experimental enable external-scanners'. [experimental]"
|
|
1001
1057
|
),
|
|
1002
1058
|
)
|
|
@@ -1070,6 +1126,8 @@ def audit( # noqa: PLR0913 -- Click handler
|
|
|
1070
1126
|
(including drift in --ci mode)
|
|
1071
1127
|
2 Warning-only findings (suspicious but not critical), or
|
|
1072
1128
|
usage error (mutually exclusive flags)
|
|
1129
|
+
3 Configuration or infrastructure error (experimental feature
|
|
1130
|
+
disabled, external scanner not installed or unavailable)
|
|
1073
1131
|
|
|
1074
1132
|
\b
|
|
1075
1133
|
Examples:
|
|
@@ -1084,6 +1142,8 @@ def audit( # noqa: PLR0913 -- Click handler
|
|
|
1084
1142
|
apm audit --ci -f json # JSON CI report
|
|
1085
1143
|
apm audit --ci -f sarif # SARIF for GitHub Code Scanning
|
|
1086
1144
|
apm audit -o report.sarif # Write SARIF to file
|
|
1145
|
+
apm audit --external skillspector # SkillSpector
|
|
1146
|
+
apm audit --external sarif --external-sarif r.sarif # Any SARIF
|
|
1087
1147
|
"""
|
|
1088
1148
|
project_root = Path.cwd()
|
|
1089
1149
|
logger = CommandLogger("audit", verbose=verbose)
|
|
@@ -1110,17 +1170,17 @@ def audit( # noqa: PLR0913 -- Click handler
|
|
|
1110
1170
|
if verbose:
|
|
1111
1171
|
logger.warning("--verbose has no effect in --ci mode (output is structured)")
|
|
1112
1172
|
if strip or dry_run or file_path or package:
|
|
1113
|
-
|
|
1114
|
-
|
|
1173
|
+
raise click.UsageError(
|
|
1174
|
+
"--ci cannot be combined with --strip, --dry-run, --file, or PACKAGE"
|
|
1175
|
+
)
|
|
1115
1176
|
if output_format == "markdown":
|
|
1116
1177
|
logger.error("--ci does not support --format markdown. Use json or sarif.")
|
|
1117
1178
|
sys.exit(1)
|
|
1118
1179
|
if external:
|
|
1119
|
-
|
|
1180
|
+
raise click.UsageError(
|
|
1120
1181
|
"--ci does not support --external scanners yet. "
|
|
1121
1182
|
"Run external scanners in bare 'apm audit' mode."
|
|
1122
1183
|
)
|
|
1123
|
-
sys.exit(1)
|
|
1124
1184
|
|
|
1125
1185
|
_audit_ci_gate(cfg, policy_source, no_cache, no_policy, no_fail_fast, no_drift)
|
|
1126
1186
|
return # _audit_ci_gate calls sys.exit; return guards against fall-through
|
|
@@ -1129,8 +1189,7 @@ def audit( # noqa: PLR0913 -- Click handler
|
|
|
1129
1189
|
# They cannot be combined with --strip/--dry-run (APM only knows how to
|
|
1130
1190
|
# strip the Unicode characters its own scanner detects).
|
|
1131
1191
|
if external and (strip or dry_run):
|
|
1132
|
-
|
|
1133
|
-
sys.exit(1)
|
|
1192
|
+
raise click.UsageError("--external cannot be combined with --strip or --dry-run")
|
|
1134
1193
|
if external_sarif and not external:
|
|
1135
1194
|
raise click.UsageError("--external-sarif requires '--external sarif'")
|
|
1136
1195
|
# Orphan-flag guards: scanner-config flags are meaningless without a
|
|
@@ -234,10 +234,21 @@ def _resolve_compile_target(target):
|
|
|
234
234
|
families.add("agents")
|
|
235
235
|
|
|
236
236
|
if len(families) >= 2:
|
|
237
|
-
#
|
|
238
|
-
#
|
|
237
|
+
# Collapse {"vscode","agents"} to bare "vscode" ONLY when the
|
|
238
|
+
# original target list contains no non-Copilot agents-family
|
|
239
|
+
# targets (e.g. codex, opencode, windsurf). When mixed targets
|
|
240
|
+
# like [copilot, codex] are requested, keep the frozenset so
|
|
241
|
+
# downstream dedup logic knows non-Copilot targets also consume
|
|
242
|
+
# AGENTS.md (issue #1678).
|
|
239
243
|
if families == {"vscode", "agents"}:
|
|
240
|
-
|
|
244
|
+
_vscode_names = {"copilot", "vscode", "agents"}
|
|
245
|
+
has_non_vscode_agents = any(
|
|
246
|
+
name in target_set
|
|
247
|
+
for name, profile in KNOWN_TARGETS.items()
|
|
248
|
+
if profile.compile_family == "agents" and name not in _vscode_names
|
|
249
|
+
)
|
|
250
|
+
if not has_non_vscode_agents:
|
|
251
|
+
return "vscode"
|
|
241
252
|
return frozenset(families)
|
|
242
253
|
if "claude" in families:
|
|
243
254
|
return "claude"
|
|
@@ -244,7 +244,7 @@ def enable_flag(ctx, name: str, verbose: bool):
|
|
|
244
244
|
from ..core.experimental import is_enabled
|
|
245
245
|
|
|
246
246
|
if is_enabled(normalised):
|
|
247
|
-
logger.
|
|
247
|
+
logger.progress(f"{display_name(normalised)} is already enabled.")
|
|
248
248
|
return
|
|
249
249
|
|
|
250
250
|
flag = _enable_flag(normalised)
|
|
@@ -274,7 +274,7 @@ def disable_flag(ctx, name: str, verbose: bool):
|
|
|
274
274
|
from ..core.experimental import is_enabled
|
|
275
275
|
|
|
276
276
|
if not is_enabled(normalised):
|
|
277
|
-
logger.
|
|
277
|
+
logger.progress(f"{display_name(normalised)} is already disabled.")
|
|
278
278
|
return
|
|
279
279
|
|
|
280
280
|
_disable_flag(normalised)
|
|
@@ -10,20 +10,21 @@ resolver (``apm experimental enable registries``).
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
12
|
import re
|
|
13
|
-
import
|
|
13
|
+
import zipfile
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
|
|
16
16
|
import click
|
|
17
17
|
|
|
18
18
|
from ..core.command_logger import CommandLogger
|
|
19
19
|
from ..deps.registry.feature_gate import require_package_registry_enabled
|
|
20
|
+
from ..utils.paths import portable_relpath
|
|
20
21
|
|
|
21
22
|
_PUBLISH_HELP = """\
|
|
22
23
|
Publish a package to a registry.
|
|
23
24
|
|
|
24
|
-
Reads apm.yml for the package name/version, packs a flat registry archive
|
|
25
|
-
(``apm.yml`` + ``.apm/`` at the
|
|
26
|
-
or uses a pre-built
|
|
25
|
+
Reads apm.yml for the package name/version, packs a flat registry zip archive
|
|
26
|
+
(``apm.yml`` + ``.apm/`` at the archive root — not ``apm pack`` plugin bundles),
|
|
27
|
+
or uses a pre-built zip via --zip, then uploads to the registry via
|
|
27
28
|
PUT /v1/packages/{owner}/{repo}/versions/{version}.
|
|
28
29
|
|
|
29
30
|
Requires the 'registries' experimental feature:
|
|
@@ -37,8 +38,8 @@ Examples:
|
|
|
37
38
|
# Choose a registry when multiple are configured:
|
|
38
39
|
apm publish --registry corp-main
|
|
39
40
|
|
|
40
|
-
# Publish a pre-built
|
|
41
|
-
apm publish --
|
|
41
|
+
# Publish a pre-built zip (skip the pack step):
|
|
42
|
+
apm publish --zip ./build/my-package-1.0.0.zip
|
|
42
43
|
|
|
43
44
|
# Preview what would be uploaded:
|
|
44
45
|
apm publish --dry-run
|
|
@@ -60,16 +61,16 @@ Examples:
|
|
|
60
61
|
help="Package identity to publish as (owner/repo, e.g. acme/my-skill).",
|
|
61
62
|
)
|
|
62
63
|
@click.option(
|
|
63
|
-
"--
|
|
64
|
-
"
|
|
64
|
+
"--zip",
|
|
65
|
+
"zip_path",
|
|
65
66
|
type=click.Path(exists=True, dir_okay=False),
|
|
66
67
|
default=None,
|
|
67
|
-
help="Path to a pre-built .
|
|
68
|
+
help="Path to a pre-built .zip archive. Skips the pack step.",
|
|
68
69
|
)
|
|
69
70
|
@click.option("--dry-run", is_flag=True, default=False, help="Preview without uploading.")
|
|
70
71
|
@click.option("--verbose", "-v", is_flag=True, help="Show detailed output.")
|
|
71
72
|
@click.pass_context
|
|
72
|
-
def publish_cmd(ctx, registry_name, package_id,
|
|
73
|
+
def publish_cmd(ctx, registry_name, package_id, zip_path, dry_run, verbose):
|
|
73
74
|
"""Publish a package version to a registry."""
|
|
74
75
|
require_package_registry_enabled("apm publish")
|
|
75
76
|
|
|
@@ -100,18 +101,18 @@ def publish_cmd(ctx, registry_name, package_id, tarball_path, dry_run, verbose):
|
|
|
100
101
|
registry_name = _resolve_registry_name(registry_name, registries)
|
|
101
102
|
base_url = registries[registry_name]
|
|
102
103
|
|
|
103
|
-
# -----------------------------------------------------------
|
|
104
|
-
if
|
|
105
|
-
|
|
104
|
+
# ----------------------------------------------------------- zip archive
|
|
105
|
+
if zip_path:
|
|
106
|
+
archive = Path(zip_path)
|
|
106
107
|
else:
|
|
107
|
-
|
|
108
|
+
archive = _pack_archive(project_root, apm_yml_path, pkg, logger, verbose)
|
|
108
109
|
|
|
109
|
-
|
|
110
|
+
archive_size = archive.stat().st_size
|
|
110
111
|
|
|
111
112
|
# ----------------------------------------------------------- dry-run
|
|
112
113
|
if dry_run:
|
|
113
114
|
logger.info(f"Would publish {owner}/{repo}@{version} to {registry_name} ({base_url})")
|
|
114
|
-
logger.info(f"
|
|
115
|
+
logger.info(f" archive : {archive} ({archive_size:,} bytes)")
|
|
115
116
|
logger.info("(dry-run — nothing uploaded)")
|
|
116
117
|
return
|
|
117
118
|
|
|
@@ -124,9 +125,9 @@ def publish_cmd(ctx, registry_name, package_id, tarball_path, dry_run, verbose):
|
|
|
124
125
|
|
|
125
126
|
logger.info(f"Publishing {owner}/{repo}@{version} to {registry_name} …")
|
|
126
127
|
|
|
127
|
-
|
|
128
|
+
archive_bytes = archive.read_bytes()
|
|
128
129
|
try:
|
|
129
|
-
result = client.publish_version(owner, repo, version,
|
|
130
|
+
result = client.publish_version(owner, repo, version, archive_bytes)
|
|
130
131
|
except RegistryError as exc:
|
|
131
132
|
_handle_publish_error(exc, owner, repo, version, registry_name, base_url)
|
|
132
133
|
|
|
@@ -184,14 +185,14 @@ def _resolve_registry_name(name: str | None, registries: dict[str, str]) -> str:
|
|
|
184
185
|
|
|
185
186
|
|
|
186
187
|
def _pack_archive(project_root: Path, apm_yml_path: Path, pkg, logger, verbose: bool) -> Path:
|
|
187
|
-
"""Build a flat registry
|
|
188
|
+
"""Build a flat registry zip archive (``apm.yml`` + ``.apm/`` at archive root).
|
|
188
189
|
|
|
189
190
|
Also includes ``README.md``, ``CHANGELOG.md``, and ``LICENSE`` (case-
|
|
190
191
|
insensitive, no extension required for LICENSE) when present — matching
|
|
191
192
|
npm's behaviour of bundling standard root-level documentation files.
|
|
192
193
|
|
|
193
194
|
Registry servers and ``apm install`` expect the APM source layout at the
|
|
194
|
-
|
|
195
|
+
archive root — not the ``apm pack --archive`` plugin bundle wrapper
|
|
195
196
|
(``{name}-{version}/plugin.json``). See registry HTTP API §6.
|
|
196
197
|
"""
|
|
197
198
|
apm_dir = project_root / ".apm"
|
|
@@ -199,10 +200,10 @@ def _pack_archive(project_root: Path, apm_yml_path: Path, pkg, logger, verbose:
|
|
|
199
200
|
raise click.ClickException(
|
|
200
201
|
"Registry publish requires a flat APM package (.apm/ directory).\n"
|
|
201
202
|
"Add .apm/ with your primitives (skills, instructions, etc.), "
|
|
202
|
-
"or pass --
|
|
203
|
+
"or pass --zip with a pre-built flat archive."
|
|
203
204
|
)
|
|
204
205
|
|
|
205
|
-
archive_name = f"{pkg.name}-{pkg.version}.
|
|
206
|
+
archive_name = f"{pkg.name}-{pkg.version}.zip"
|
|
206
207
|
dest = project_root / archive_name
|
|
207
208
|
if dest.exists():
|
|
208
209
|
dest.unlink()
|
|
@@ -210,21 +211,20 @@ def _pack_archive(project_root: Path, apm_yml_path: Path, pkg, logger, verbose:
|
|
|
210
211
|
if verbose:
|
|
211
212
|
logger.info(f"Packing flat registry archive -> {dest.name}")
|
|
212
213
|
|
|
213
|
-
def
|
|
214
|
-
# Skip macOS AppleDouble sidecars (._*) that break registry validation.
|
|
215
|
-
|
|
216
|
-
return None
|
|
217
|
-
if Path(ti.name).name == ".DS_Store":
|
|
218
|
-
return None
|
|
219
|
-
return ti
|
|
214
|
+
def _should_skip(path: Path) -> bool:
|
|
215
|
+
# Skip macOS AppleDouble sidecars (._*) and .DS_Store that break registry validation.
|
|
216
|
+
return any(part.startswith("._") for part in path.parts) or path.name == ".DS_Store"
|
|
220
217
|
|
|
221
218
|
# Standard root-level doc files included when present (npm parity).
|
|
222
219
|
# Matched case-insensitively; LICENSE has no required extension.
|
|
223
220
|
_DOC_CANDIDATES = ("README.md", "CHANGELOG.md", "LICENSE", "LICENCE")
|
|
224
221
|
|
|
225
|
-
with
|
|
226
|
-
|
|
227
|
-
|
|
222
|
+
with zipfile.ZipFile(dest, mode="w", compression=zipfile.ZIP_DEFLATED) as zf:
|
|
223
|
+
if not _should_skip(apm_yml_path):
|
|
224
|
+
zf.write(apm_yml_path, arcname="apm.yml")
|
|
225
|
+
for file in sorted(apm_dir.rglob("*")):
|
|
226
|
+
if file.is_file() and not file.is_symlink() and not _should_skip(file):
|
|
227
|
+
zf.write(file, arcname=portable_relpath(file, project_root))
|
|
228
228
|
for candidate in _DOC_CANDIDATES:
|
|
229
229
|
# Case-insensitive match against actual filenames in project root.
|
|
230
230
|
match = next(
|
|
@@ -235,8 +235,8 @@ def _pack_archive(project_root: Path, apm_yml_path: Path, pkg, logger, verbose:
|
|
|
235
235
|
),
|
|
236
236
|
None,
|
|
237
237
|
)
|
|
238
|
-
if match:
|
|
239
|
-
|
|
238
|
+
if match and not _should_skip(match):
|
|
239
|
+
zf.write(match, arcname=match.name)
|
|
240
240
|
if verbose:
|
|
241
241
|
logger.info(f" bundling {match.name}")
|
|
242
242
|
|