apm-cli 0.14.1__tar.gz → 0.14.2__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.14.1 → apm_cli-0.14.2}/NOTICE +40 -0
- {apm_cli-0.14.1/src/apm_cli.egg-info → apm_cli-0.14.2}/PKG-INFO +2 -3
- {apm_cli-0.14.1 → apm_cli-0.14.2}/README.md +0 -2
- {apm_cli-0.14.1 → apm_cli-0.14.2}/pyproject.toml +3 -1
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/adapters/client/base.py +405 -3
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/adapters/client/codex.py +93 -87
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/adapters/client/copilot.py +22 -207
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/adapters/client/cursor.py +1 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/adapters/client/gemini.py +17 -2
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/adapters/client/vscode.py +41 -8
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/cache/git_cache.py +248 -33
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/cache/locking.py +26 -10
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/cache/url_normalize.py +30 -15
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/install.py +29 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/view.py +21 -16
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/compilation/context_optimizer.py +23 -5
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/core/azure_cli.py +32 -3
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/core/command_logger.py +75 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/core/conflict_detector.py +3 -1
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/core/errors.py +3 -1
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/core/target_detection.py +4 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/bare_cache.py +15 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/github_downloader.py +110 -3
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/plugin_parser.py +85 -23
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/drift.py +8 -0
- apm_cli-0.14.2/src/apm_cli/install/phases/_redownload.py +37 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/phases/download.py +3 -4
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/phases/integrate.py +7 -12
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/phases/resolve.py +17 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/phases/targets.py +57 -21
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/pipeline.py +74 -21
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/services.py +15 -3
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/integration/agent_integrator.py +1 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/integration/command_integrator.py +1 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/integration/copilot_app_db.py +163 -96
- apm_cli-0.14.2/src/apm_cli/integration/copilot_app_project.py +404 -0
- apm_cli-0.14.1/src/apm_cli/integration/prompt_integrator.py → apm_cli-0.14.2/src/apm_cli/integration/copilot_app_workflow_integrator.py +387 -433
- apm_cli-0.14.2/src/apm_cli/integration/copilot_app_ws.py +531 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/integration/hook_integrator.py +379 -21
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/integration/instruction_integrator.py +22 -11
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/integration/mcp_integrator.py +0 -6
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/integration/mcp_integrator_install.py +198 -139
- apm_cli-0.14.2/src/apm_cli/integration/prompt_integrator.py +366 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/policy/ci_checks.py +9 -3
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/primitives/discovery.py +44 -6
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/atomic_io.py +10 -4
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/git_env.py +17 -0
- apm_cli-0.14.2/src/apm_cli/utils/git_sparse.py +62 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/github_host.py +48 -0
- apm_cli-0.14.2/src/apm_cli/utils/patterns.py +91 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2/src/apm_cli.egg-info}/PKG-INFO +2 -3
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli.egg-info/SOURCES.txt +6 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli.egg-info/requires.txt +1 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/tests/test_codex_empty_string_and_defaults.py +89 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/AUTHORS +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/LICENSE +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/setup.cfg +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/adapters/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/adapters/client/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/adapters/client/claude.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/adapters/client/opencode.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/adapters/client/windsurf.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/adapters/package_manager/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/adapters/package_manager/base.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/adapters/package_manager/default_manager.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/bundle/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/bundle/local_bundle.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/bundle/lockfile_enrichment.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/bundle/packer.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/bundle/plugin_exporter.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/bundle/unpacker.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/cache/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/cache/http_cache.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/cache/integrity.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/cache/paths.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/cli.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/_apm_yml_writer.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/_helpers.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/audit.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/cache.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/compile/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/compile/cli.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/compile/watcher.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/config.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/deps/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/deps/_utils.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/deps/cli.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/experimental.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/init.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/list_cmd.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/marketplace/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/marketplace/check.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/marketplace/doctor.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/marketplace/init.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/marketplace/migrate.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/marketplace/outdated.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/marketplace/plugin/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/marketplace/plugin/add.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/marketplace/plugin/remove.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/marketplace/plugin/set.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/marketplace/publish.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/marketplace/validate.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/mcp.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/outdated.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/pack.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/plugin/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/plugin/init.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/policy.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/prune.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/run.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/runtime.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/self_update.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/targets.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/uninstall/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/uninstall/cli.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/uninstall/engine.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/commands/update.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/compilation/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/compilation/agents_compiler.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/compilation/build_id.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/compilation/claude_formatter.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/compilation/constants.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/compilation/constitution.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/compilation/constitution_block.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/compilation/distributed_compiler.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/compilation/gemini_formatter.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/compilation/injector.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/compilation/link_resolver.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/compilation/output_writer.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/compilation/template_builder.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/config.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/constants.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/core/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/core/apm_yml.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/core/auth.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/core/build_orchestrator.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/core/docker_args.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/core/experimental.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/core/null_logger.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/core/operations.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/core/safe_installer.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/core/scope.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/core/script_runner.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/core/token_manager.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/_shared.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/aggregator.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/apm_resolver.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/artifactory_entry.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/artifactory_orchestrator.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/clone_engine.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/dependency_graph.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/download_strategies.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/git_auth_env.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/git_reference_resolver.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/git_remote_ops.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/github_downloader_validation.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/host_backends.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/installed_package.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/lockfile.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/package_validator.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/registry_proxy.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/shared_clone_cache.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/tiered_ref_resolver.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/transport_selection.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/deps/verifier.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/drift.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/factory.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/cache_pin.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/context.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/errors.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/gitlab_resolver.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/heals/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/heals/base.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/heals/branch_ref_drift.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/heals/buggy_lockfile_recovery.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/helpers/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/helpers/security_scan.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/insecure_policy.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/local_bundle_handler.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/mcp/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/mcp/args.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/mcp/command.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/mcp/conflicts.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/mcp/entry.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/mcp/registry.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/mcp/warnings.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/mcp/writer.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/package_resolution.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/phases/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/phases/cleanup.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/phases/finalize.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/phases/heal.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/phases/local_content.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/phases/lockfile.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/phases/policy_gate.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/phases/policy_target_check.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/phases/post_deps_local.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/plan.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/presentation/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/presentation/dry_run.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/request.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/service.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/skill_path_migration.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/sources.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/summary.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/template.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/install/validation.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/integration/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/integration/base_integrator.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/integration/cleanup.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/integration/copilot_cowork_paths.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/integration/coverage.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/integration/dispatch.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/integration/skill_integrator.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/integration/skill_transformer.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/integration/targets.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/integration/utils.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/_git_utils.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/_io.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/_shared.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/builder.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/client.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/diagnostics.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/drift_check.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/errors.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/git_stderr.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/init_template.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/migration.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/models.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/output_mappers.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/output_profiles.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/pr_integration.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/publisher.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/ref_resolver.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/registry.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/resolver.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/semver.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/shadow_detector.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/tag_pattern.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/validator.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/version_check.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/version_pins.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/yml_editor.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/marketplace/yml_schema.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/models/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/models/apm_package.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/models/dependency/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/models/dependency/mcp.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/models/dependency/reference.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/models/dependency/types.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/models/plugin.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/models/results.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/models/validation.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/output/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/output/formatters.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/output/models.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/output/script_formatters.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/policy/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/policy/_help_text.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/policy/_shared.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/policy/discovery.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/policy/inheritance.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/policy/install_preflight.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/policy/matcher.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/policy/models.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/policy/outcome_routing.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/policy/parser.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/policy/policy_checks.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/policy/project_config.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/policy/schema.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/primitives/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/primitives/models.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/primitives/parser.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/registry/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/registry/client.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/registry/integration.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/registry/operations.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/runtime/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/runtime/base.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/runtime/codex_runtime.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/runtime/copilot_runtime.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/runtime/factory.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/runtime/llm_runtime.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/runtime/manager.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/runtime/utils.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/security/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/security/audit_report.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/security/content_scanner.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/security/file_scanner.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/security/gate.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/update_policy.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/console.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/content_hash.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/diagnostics.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/exclude.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/file_ops.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/guards.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/helpers.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/install_tui.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/normalization.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/path_security.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/paths.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/reflink.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/short_sha.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/subprocess_env.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/version_checker.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/utils/yaml_io.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/version.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/workflow/__init__.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/workflow/discovery.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/workflow/parser.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli/workflow/runner.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli.egg-info/dependency_links.txt +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli.egg-info/entry_points.txt +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/src/apm_cli.egg-info/top_level.txt +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/tests/test_apm_package_models.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/tests/test_apm_resolver.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/tests/test_codex_docker_args_fix.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/tests/test_collision_integration.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/tests/test_console.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/tests/test_distributed_compilation.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/tests/test_empty_string_and_defaults.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/tests/test_enhanced_discovery.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/tests/test_github_downloader.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/tests/test_github_downloader_token_precedence.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/tests/test_lockfile.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/tests/test_runnable_prompts.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/tests/test_runtime_manager_token_precedence.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/tests/test_token_manager.py +0 -0
- {apm_cli-0.14.1 → apm_cli-0.14.2}/tests/test_virtual_package_multi_install.py +0 -0
|
@@ -1252,6 +1252,46 @@ SOFTWARE.
|
|
|
1252
1252
|
|
|
1253
1253
|
---
|
|
1254
1254
|
|
|
1255
|
+
## Component. websockets
|
|
1256
|
+
|
|
1257
|
+
- Version requirement: `>=12,<17`
|
|
1258
|
+
- Upstream: https://github.com/python-websockets/websockets
|
|
1259
|
+
- SPDX: `BSD-3-Clause`
|
|
1260
|
+
- Notes: Used by the copilot-app integrator to nudge the Copilot desktop App over its local WebSocket IPC channel after writing workflows to the App DB.
|
|
1261
|
+
|
|
1262
|
+
### Open Source License/Copyright Notice.
|
|
1263
|
+
|
|
1264
|
+
_Copyright (c) Aymeric Augustin and contributors_
|
|
1265
|
+
|
|
1266
|
+
```
|
|
1267
|
+
Copyright (c) Aymeric Augustin and contributors
|
|
1268
|
+
|
|
1269
|
+
Redistribution and use in source and binary forms, with or without
|
|
1270
|
+
modification, are permitted provided that the following conditions are met:
|
|
1271
|
+
|
|
1272
|
+
* Redistributions of source code must retain the above copyright notice,
|
|
1273
|
+
this list of conditions and the following disclaimer.
|
|
1274
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
1275
|
+
this list of conditions and the following disclaimer in the documentation
|
|
1276
|
+
and/or other materials provided with the distribution.
|
|
1277
|
+
* Neither the name of the copyright holder nor the names of its contributors
|
|
1278
|
+
may be used to endorse or promote products derived from this software
|
|
1279
|
+
without specific prior written permission.
|
|
1280
|
+
|
|
1281
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
1282
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
1283
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
1284
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
1285
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
1286
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
1287
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
1288
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
1289
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
1290
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
1291
|
+
```
|
|
1292
|
+
|
|
1293
|
+
---
|
|
1294
|
+
|
|
1255
1295
|
Submitted on behalf of a third-party
|
|
1256
1296
|
|
|
1257
1297
|
The contributions below are identified as submitted on behalf of a
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: apm-cli
|
|
3
|
-
Version: 0.14.
|
|
3
|
+
Version: 0.14.2
|
|
4
4
|
Summary: MCP configuration tool
|
|
5
5
|
Author-email: Daniel Meppiel <user@example.com>
|
|
6
6
|
License: MIT License
|
|
@@ -52,6 +52,7 @@ Requires-Dist: watchdog>=3.0.0
|
|
|
52
52
|
Requires-Dist: GitPython>=3.1.0
|
|
53
53
|
Requires-Dist: ruamel.yaml>=0.18.0
|
|
54
54
|
Requires-Dist: filelock>=3.12
|
|
55
|
+
Requires-Dist: websockets<17,>=12
|
|
55
56
|
Provides-Extra: dev
|
|
56
57
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
57
58
|
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
@@ -219,8 +220,6 @@ Or add an MCP server (wired into Copilot, Claude, Cursor, Codex, OpenCode, Gemin
|
|
|
219
220
|
apm install --mcp io.github.github/github-mcp-server --transport http # connects over HTTPS
|
|
220
221
|
```
|
|
221
222
|
|
|
222
|
-
> *Codex CLI currently does not support remote MCP servers; the install will skip Codex with a notice. Omit `--transport http` to use the local Docker variant on Codex (requires `GITHUB_PERSONAL_ACCESS_TOKEN`).*
|
|
223
|
-
|
|
224
223
|
See the **[Getting Started guide](https://microsoft.github.io/apm/getting-started/quick-start/)** for the full walkthrough.
|
|
225
224
|
|
|
226
225
|
## Works with agentrc
|
|
@@ -152,8 +152,6 @@ Or add an MCP server (wired into Copilot, Claude, Cursor, Codex, OpenCode, Gemin
|
|
|
152
152
|
apm install --mcp io.github.github/github-mcp-server --transport http # connects over HTTPS
|
|
153
153
|
```
|
|
154
154
|
|
|
155
|
-
> *Codex CLI currently does not support remote MCP servers; the install will skip Codex with a notice. Omit `--transport http` to use the local Docker variant on Codex (requires `GITHUB_PERSONAL_ACCESS_TOKEN`).*
|
|
156
|
-
|
|
157
155
|
See the **[Getting Started guide](https://microsoft.github.io/apm/getting-started/quick-start/)** for the full walkthrough.
|
|
158
156
|
|
|
159
157
|
## Works with agentrc
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "apm-cli"
|
|
7
|
-
version = "0.14.
|
|
7
|
+
version = "0.14.2"
|
|
8
8
|
description = "MCP configuration tool"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -37,6 +37,7 @@ dependencies = [
|
|
|
37
37
|
"GitPython>=3.1.0",
|
|
38
38
|
"ruamel.yaml>=0.18.0",
|
|
39
39
|
"filelock>=3.12",
|
|
40
|
+
"websockets>=12,<17",
|
|
40
41
|
]
|
|
41
42
|
|
|
42
43
|
[project.optional-dependencies]
|
|
@@ -137,6 +138,7 @@ parallel = true
|
|
|
137
138
|
[tool.coverage.report]
|
|
138
139
|
show_missing = true
|
|
139
140
|
skip_empty = true
|
|
141
|
+
fail_under = 80
|
|
140
142
|
# Exclude lines that are not meant to be covered
|
|
141
143
|
exclude_lines = [
|
|
142
144
|
"pragma: no cover",
|
|
@@ -4,6 +4,7 @@ import os
|
|
|
4
4
|
import re
|
|
5
5
|
from abc import ABC, abstractmethod
|
|
6
6
|
from pathlib import Path
|
|
7
|
+
from typing import ClassVar
|
|
7
8
|
|
|
8
9
|
from ...utils.console import _rich_error, _rich_warning
|
|
9
10
|
|
|
@@ -16,6 +17,80 @@ _INPUT_VAR_RE = re.compile(r"\$\{input:([^}]+)\}")
|
|
|
16
17
|
# variable handling, so existing _INPUT_VAR_RE call sites are unaffected.
|
|
17
18
|
_ENV_VAR_RE = re.compile(r"\$\{(?:env:)?([A-Za-z_][A-Za-z0-9_]*)\}")
|
|
18
19
|
|
|
20
|
+
# Superset of _ENV_VAR_RE that also matches the legacy ``<VAR>`` syntax
|
|
21
|
+
# (uppercase identifier only). Used as the single-pass translation target so
|
|
22
|
+
# resolved values are NOT re-scanned -- a literal value whose text happens to
|
|
23
|
+
# contain ``${...}`` does not get recursively expanded. ``${input:...}`` is
|
|
24
|
+
# intentionally not matched here so input-variable handling stays disjoint.
|
|
25
|
+
_ENV_PLACEHOLDER_RE = re.compile(r"<([A-Z_][A-Z0-9_]*)>|" + _ENV_VAR_RE.pattern)
|
|
26
|
+
|
|
27
|
+
# Detects the legacy ``<VAR>`` placeholder syntax only. Used to aggregate
|
|
28
|
+
# deprecation warnings across all servers in a single install run.
|
|
29
|
+
_LEGACY_ANGLE_VAR_RE = re.compile(r"<([A-Z_][A-Z0-9_]*)>")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _translate_env_placeholder(value):
|
|
33
|
+
"""Pure-textual translation of env-var placeholders to the canonical
|
|
34
|
+
``${VAR}`` runtime-substitution syntax.
|
|
35
|
+
|
|
36
|
+
Security-critical helper for issue #1152: MUST NOT read ``os.environ``
|
|
37
|
+
and MUST NOT resolve placeholders to literal values. Runtimes that
|
|
38
|
+
support runtime substitution (Copilot CLI) resolve ``${VAR}`` from the
|
|
39
|
+
host environment at server-start, so APM emits placeholders verbatim
|
|
40
|
+
rather than baking secrets to disk.
|
|
41
|
+
|
|
42
|
+
Translations:
|
|
43
|
+
``${env:VAR}`` -> ``${VAR}`` (strip ``env:`` prefix)
|
|
44
|
+
``${VAR}`` -> ``${VAR}`` (no-op)
|
|
45
|
+
``<VAR>`` -> ``${VAR}`` (legacy syntax migration)
|
|
46
|
+
``${VAR:-default}``-> passthrough (regex doesn't match)
|
|
47
|
+
``$VAR`` (bare) -> passthrough (regex doesn't match)
|
|
48
|
+
``${input:foo}`` -> passthrough (regex doesn't match)
|
|
49
|
+
non-string -> passthrough
|
|
50
|
+
|
|
51
|
+
Idempotent: applying twice yields the same result as applying once.
|
|
52
|
+
"""
|
|
53
|
+
if not isinstance(value, str):
|
|
54
|
+
return value
|
|
55
|
+
|
|
56
|
+
def _to_brace(match):
|
|
57
|
+
# group(1) = legacy <VAR>; group(2) = ${VAR} / ${env:VAR}
|
|
58
|
+
var_name = match.group(1) or match.group(2)
|
|
59
|
+
return "${" + var_name + "}"
|
|
60
|
+
|
|
61
|
+
return _ENV_PLACEHOLDER_RE.sub(_to_brace, value)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _extract_legacy_angle_vars(value):
|
|
65
|
+
"""Return the set of legacy ``<VAR>`` names present in *value*.
|
|
66
|
+
|
|
67
|
+
Used to aggregate deprecation warnings across all servers in a single
|
|
68
|
+
install run, so authors see one helpful list instead of one warning per
|
|
69
|
+
occurrence.
|
|
70
|
+
"""
|
|
71
|
+
if not isinstance(value, str):
|
|
72
|
+
return set()
|
|
73
|
+
return set(_LEGACY_ANGLE_VAR_RE.findall(value))
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _has_env_placeholder(value):
|
|
77
|
+
"""True if *value* is a string containing any recognised env-var
|
|
78
|
+
placeholder syntax (``${VAR}``, ``${env:VAR}``, or legacy ``<VAR>``).
|
|
79
|
+
|
|
80
|
+
Used to distinguish placeholder-sourced env values (which translate)
|
|
81
|
+
from hardcoded literal defaults (which stay literal).
|
|
82
|
+
"""
|
|
83
|
+
if not isinstance(value, str):
|
|
84
|
+
return False
|
|
85
|
+
return bool(_ENV_PLACEHOLDER_RE.search(value))
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _stringify_env_literal(value):
|
|
89
|
+
"""Return MCP env literal values in the manifest ``map<string, string>`` shape."""
|
|
90
|
+
if isinstance(value, bool):
|
|
91
|
+
return str(value).lower()
|
|
92
|
+
return str(value)
|
|
93
|
+
|
|
19
94
|
|
|
20
95
|
class MCPClientAdapter(ABC):
|
|
21
96
|
"""Base adapter for MCP clients."""
|
|
@@ -44,6 +119,13 @@ class MCPClientAdapter(ABC):
|
|
|
44
119
|
# so that ``apm install --global`` can install MCP servers to them.
|
|
45
120
|
supports_user_scope: bool = False
|
|
46
121
|
|
|
122
|
+
# Whether the target runtime resolves ``${VAR}`` placeholders from the
|
|
123
|
+
# host environment at server-start time. Adapters that opt in (Copilot
|
|
124
|
+
# CLI) emit placeholders verbatim so secrets never touch disk; legacy
|
|
125
|
+
# adapters resolve to literal values at install time via env_overrides
|
|
126
|
+
# -> os.environ -> optional interactive prompt. See issue #1152.
|
|
127
|
+
_supports_runtime_env_substitution: bool = False
|
|
128
|
+
|
|
47
129
|
def __init__(
|
|
48
130
|
self,
|
|
49
131
|
project_root: Path | str | None = None,
|
|
@@ -60,6 +142,13 @@ class MCPClientAdapter(ABC):
|
|
|
60
142
|
"""
|
|
61
143
|
self._project_root = Path(project_root) if project_root is not None else None
|
|
62
144
|
self.user_scope = user_scope
|
|
145
|
+
# Per-server tracking populated by the env-resolution helpers and
|
|
146
|
+
# consumed by ``configure_mcp_server`` for the post-install summary
|
|
147
|
+
# and the aggregated legacy-syntax deprecation warning. Defined on
|
|
148
|
+
# the base so every adapter has the attributes regardless of which
|
|
149
|
+
# subclass path constructed it.
|
|
150
|
+
self._last_env_placeholder_keys: set[str] = set()
|
|
151
|
+
self._last_legacy_angle_vars: set[str] = set()
|
|
63
152
|
|
|
64
153
|
@property
|
|
65
154
|
def project_root(self) -> Path:
|
|
@@ -159,6 +248,46 @@ class MCPClientAdapter(ABC):
|
|
|
159
248
|
|
|
160
249
|
return ""
|
|
161
250
|
|
|
251
|
+
@classmethod
|
|
252
|
+
def _select_best_package(cls, packages):
|
|
253
|
+
"""Select the best package for installation from available packages.
|
|
254
|
+
|
|
255
|
+
Prioritizes packages in order: npm, docker, pypi, homebrew, others.
|
|
256
|
+
Uses ``_infer_registry_name`` so selection works even when the
|
|
257
|
+
registry API returns empty ``registry_name``.
|
|
258
|
+
|
|
259
|
+
Args:
|
|
260
|
+
packages (list): List of package dictionaries.
|
|
261
|
+
|
|
262
|
+
Returns:
|
|
263
|
+
dict: Best package to use, or None if no suitable package found.
|
|
264
|
+
"""
|
|
265
|
+
priority_order = ["npm", "docker", "pypi", "homebrew"]
|
|
266
|
+
|
|
267
|
+
for target in priority_order:
|
|
268
|
+
for package in packages:
|
|
269
|
+
if cls._infer_registry_name(package) == target:
|
|
270
|
+
return package
|
|
271
|
+
|
|
272
|
+
# If no priority package found, return the first one
|
|
273
|
+
return packages[0] if packages else None
|
|
274
|
+
|
|
275
|
+
@staticmethod
|
|
276
|
+
def _select_remote_with_url(remotes):
|
|
277
|
+
"""Return the first remote entry that has a non-empty URL.
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
remotes (list): Candidate remote entries from the registry.
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
dict or None: The first usable remote, or None if none qualify.
|
|
284
|
+
"""
|
|
285
|
+
for remote in remotes:
|
|
286
|
+
url = (remote.get("url") or "").strip()
|
|
287
|
+
if url:
|
|
288
|
+
return remote
|
|
289
|
+
return None
|
|
290
|
+
|
|
162
291
|
@staticmethod
|
|
163
292
|
def _warn_input_variables(mapping, server_name, runtime_label):
|
|
164
293
|
"""Emit a warning for each ``${input:...}`` reference found in *mapping*.
|
|
@@ -199,6 +328,270 @@ class MCPClientAdapter(ABC):
|
|
|
199
328
|
return "."
|
|
200
329
|
return value
|
|
201
330
|
|
|
331
|
+
# -- Env-var placeholder resolution -------------------------------------
|
|
332
|
+
# GitHub MCP server defaults: not secrets, preserved literal in translate
|
|
333
|
+
# mode and used as fallbacks in legacy mode. The defaults apply regardless
|
|
334
|
+
# of which client CLI runs the server, so they live on the base.
|
|
335
|
+
_DEFAULT_GITHUB_ENV: ClassVar[dict[str, str]] = {
|
|
336
|
+
"GITHUB_TOOLSETS": "context",
|
|
337
|
+
"GITHUB_DYNAMIC_TOOLSETS": "1",
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
@staticmethod
|
|
341
|
+
def _should_skip_env_prompts(env_overrides):
|
|
342
|
+
"""True when the caller has already collected env vars (managed mode),
|
|
343
|
+
when APM_E2E_TESTS is set, or when stdin/stdout is not a TTY.
|
|
344
|
+
|
|
345
|
+
Centralising this policy keeps the resolver paths consistent and
|
|
346
|
+
avoids subtle drift between ``_resolve_environment_variables`` and
|
|
347
|
+
``_resolve_env_variable``.
|
|
348
|
+
"""
|
|
349
|
+
import sys
|
|
350
|
+
|
|
351
|
+
if env_overrides:
|
|
352
|
+
return True
|
|
353
|
+
if os.getenv("APM_E2E_TESTS") == "1":
|
|
354
|
+
return True
|
|
355
|
+
return not (sys.stdin.isatty() and sys.stdout.isatty())
|
|
356
|
+
|
|
357
|
+
def _resolve_environment_variables(self, env_vars, env_overrides=None):
|
|
358
|
+
"""Resolve (or translate) declared environment variables.
|
|
359
|
+
|
|
360
|
+
Behaviour follows ``self._supports_runtime_env_substitution``:
|
|
361
|
+
translate-mode (Copilot CLI) emits ``${VAR}`` placeholders verbatim
|
|
362
|
+
so the runtime resolves them at server-start (see issue #1152);
|
|
363
|
+
legacy-mode resolves placeholders to literal values via env_overrides
|
|
364
|
+
-> os.environ -> optional interactive prompt.
|
|
365
|
+
|
|
366
|
+
Args:
|
|
367
|
+
env_vars: Either a ``dict[name, value-or-placeholder]`` from a
|
|
368
|
+
self-defined stdio dep (``_raw_stdio["env"]``), or a
|
|
369
|
+
``list[{name, description, required}]`` from the registry.
|
|
370
|
+
env_overrides: Pre-collected env-var overrides (ignored in
|
|
371
|
+
translate mode).
|
|
372
|
+
|
|
373
|
+
Returns:
|
|
374
|
+
dict: ``{name: value}`` -- placeholder string in translate
|
|
375
|
+
mode, literal value in legacy mode.
|
|
376
|
+
"""
|
|
377
|
+
# ---- translate mode, dict shape (self-defined stdio in apm.yml) ----
|
|
378
|
+
if isinstance(env_vars, dict) and self._supports_runtime_env_substitution:
|
|
379
|
+
# Value type is intentionally untyped: most entries are translated
|
|
380
|
+
# placeholder strings, but non-string values (e.g. an int/bool
|
|
381
|
+
# YAML scalar) are passed through verbatim and serialised by the
|
|
382
|
+
# adapter's config writer (JSON/TOML).
|
|
383
|
+
translated: dict = {}
|
|
384
|
+
placeholder_keys: list[str] = []
|
|
385
|
+
for name, raw_value in env_vars.items():
|
|
386
|
+
if not name:
|
|
387
|
+
continue
|
|
388
|
+
if not isinstance(raw_value, str):
|
|
389
|
+
translated[name] = raw_value
|
|
390
|
+
continue
|
|
391
|
+
if _has_env_placeholder(raw_value):
|
|
392
|
+
self._last_legacy_angle_vars.update(_extract_legacy_angle_vars(raw_value))
|
|
393
|
+
translated[name] = _translate_env_placeholder(raw_value)
|
|
394
|
+
# Record every ${VAR} in the translated value (handles
|
|
395
|
+
# both ${env:VAR} -> ${VAR} and bare ${VAR} cases).
|
|
396
|
+
placeholder_keys.extend(
|
|
397
|
+
m.group(1) for m in _ENV_VAR_RE.finditer(translated[name])
|
|
398
|
+
)
|
|
399
|
+
elif (
|
|
400
|
+
name in self._DEFAULT_GITHUB_ENV and raw_value == self._DEFAULT_GITHUB_ENV[name]
|
|
401
|
+
):
|
|
402
|
+
translated[name] = raw_value
|
|
403
|
+
else:
|
|
404
|
+
# Literal value present in apm.yml -- replace with a
|
|
405
|
+
# runtime placeholder so the secret never touches disk.
|
|
406
|
+
translated[name] = "${" + name + "}"
|
|
407
|
+
placeholder_keys.append(name)
|
|
408
|
+
self._last_env_placeholder_keys = set(placeholder_keys)
|
|
409
|
+
return translated
|
|
410
|
+
|
|
411
|
+
# ---- translate mode, registry list shape ----
|
|
412
|
+
if self._supports_runtime_env_substitution:
|
|
413
|
+
resolved: dict[str, str] = {}
|
|
414
|
+
placeholder_keys: list[str] = []
|
|
415
|
+
for env_var in env_vars:
|
|
416
|
+
if not isinstance(env_var, dict):
|
|
417
|
+
continue
|
|
418
|
+
name = env_var.get("name", "")
|
|
419
|
+
if not name:
|
|
420
|
+
continue
|
|
421
|
+
if name in self._DEFAULT_GITHUB_ENV:
|
|
422
|
+
resolved[name] = self._DEFAULT_GITHUB_ENV[name]
|
|
423
|
+
else:
|
|
424
|
+
resolved[name] = "${" + name + "}"
|
|
425
|
+
placeholder_keys.append(name)
|
|
426
|
+
self._last_env_placeholder_keys = set(placeholder_keys)
|
|
427
|
+
return resolved
|
|
428
|
+
|
|
429
|
+
# ---- legacy mode, dict shape (self-defined stdio in apm.yml) ----
|
|
430
|
+
# Issue #1266 / #1222: ``_raw_stdio["env"]`` is a plain dict. Each
|
|
431
|
+
# value is resolved via the same single-value pipeline used for
|
|
432
|
+
# header values so all three placeholder syntaxes (``<VAR>``,
|
|
433
|
+
# ``${VAR}``, ``${env:VAR}``) behave consistently across adapters.
|
|
434
|
+
#
|
|
435
|
+
# Note the deliberate semantic divergence from the legacy-list branch
|
|
436
|
+
# below: empty strings authored in apm.yml are preserved as-is and
|
|
437
|
+
# ``_DEFAULT_GITHUB_ENV`` fallbacks are NOT applied, because a value
|
|
438
|
+
# explicitly written by the user expresses intent, whereas an empty
|
|
439
|
+
# value coming from ``env_overrides`` / ``os.environ`` for a
|
|
440
|
+
# registry-declared schema entry means "no value supplied, use the
|
|
441
|
+
# default if one exists".
|
|
442
|
+
if isinstance(env_vars, dict):
|
|
443
|
+
resolved = {}
|
|
444
|
+
for name, value in env_vars.items():
|
|
445
|
+
if not name:
|
|
446
|
+
continue
|
|
447
|
+
if isinstance(value, str):
|
|
448
|
+
resolved[name] = self._resolve_env_variable(
|
|
449
|
+
name, value, env_overrides=env_overrides
|
|
450
|
+
)
|
|
451
|
+
elif value is not None:
|
|
452
|
+
resolved[name] = str(value)
|
|
453
|
+
return resolved
|
|
454
|
+
|
|
455
|
+
# ---- legacy mode, registry list shape ----
|
|
456
|
+
from rich.prompt import Prompt
|
|
457
|
+
|
|
458
|
+
env_overrides = env_overrides or {}
|
|
459
|
+
skip_prompting = self._should_skip_env_prompts(env_overrides)
|
|
460
|
+
|
|
461
|
+
# Variables explicitly provided with empty values mean "use the default".
|
|
462
|
+
empty_value_vars = {k for k, v in env_overrides.items() if not v or not v.strip()}
|
|
463
|
+
|
|
464
|
+
resolved = {}
|
|
465
|
+
for env_var in env_vars:
|
|
466
|
+
if not isinstance(env_var, dict):
|
|
467
|
+
continue
|
|
468
|
+
name = env_var.get("name", "")
|
|
469
|
+
if not name:
|
|
470
|
+
continue
|
|
471
|
+
required = env_var.get("required", True)
|
|
472
|
+
|
|
473
|
+
value = env_overrides.get(name) or os.getenv(name)
|
|
474
|
+
if not value and required and not skip_prompting:
|
|
475
|
+
prompt_text = f"Enter value for {name}"
|
|
476
|
+
if description := env_var.get("description", ""):
|
|
477
|
+
prompt_text += f" ({description})"
|
|
478
|
+
value = Prompt.ask(
|
|
479
|
+
prompt_text,
|
|
480
|
+
password="token" in name.lower() or "key" in name.lower(),
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
if value and value.strip():
|
|
484
|
+
resolved[name] = value
|
|
485
|
+
elif name in self._DEFAULT_GITHUB_ENV and (
|
|
486
|
+
name in empty_value_vars or not required or skip_prompting
|
|
487
|
+
):
|
|
488
|
+
resolved[name] = self._DEFAULT_GITHUB_ENV[name]
|
|
489
|
+
|
|
490
|
+
return resolved
|
|
491
|
+
|
|
492
|
+
def _resolve_env_variable(self, name, value, env_overrides=None):
|
|
493
|
+
"""Resolve (or translate) a single env-var value.
|
|
494
|
+
|
|
495
|
+
Used for header values and for individual entries in dict-shape
|
|
496
|
+
env blocks. The ``name`` parameter is currently unused by the
|
|
497
|
+
method body but kept in the signature because every call site
|
|
498
|
+
(headers, dict iteration) already has the name in hand, and
|
|
499
|
+
passing it preserves call-site symmetry with future hooks that
|
|
500
|
+
may want to dispatch on it.
|
|
501
|
+
|
|
502
|
+
Args:
|
|
503
|
+
name: Env-var name (currently unused, see above).
|
|
504
|
+
value: Env-var value possibly containing placeholders.
|
|
505
|
+
env_overrides: Pre-collected overrides (ignored in translate mode).
|
|
506
|
+
"""
|
|
507
|
+
if self._supports_runtime_env_substitution:
|
|
508
|
+
legacy_keys = _extract_legacy_angle_vars(value)
|
|
509
|
+
self._last_legacy_angle_vars.update(legacy_keys)
|
|
510
|
+
self._last_env_placeholder_keys.update(legacy_keys)
|
|
511
|
+
for match in _ENV_VAR_RE.finditer(value):
|
|
512
|
+
self._last_env_placeholder_keys.add(match.group(1))
|
|
513
|
+
return _translate_env_placeholder(value)
|
|
514
|
+
|
|
515
|
+
from rich.prompt import Prompt
|
|
516
|
+
|
|
517
|
+
env_overrides = env_overrides or {}
|
|
518
|
+
skip_prompting = self._should_skip_env_prompts(env_overrides)
|
|
519
|
+
|
|
520
|
+
# Three accepted placeholder syntaxes resolved against
|
|
521
|
+
# env_overrides -> os.environ -> optional interactive prompt.
|
|
522
|
+
# Single-pass substitution preserves the legacy ``<VAR>`` semantics:
|
|
523
|
+
# resolved values are NOT re-scanned for further expansion.
|
|
524
|
+
def _replace(match):
|
|
525
|
+
env_name = match.group(1) or match.group(2)
|
|
526
|
+
env_value = env_overrides.get(env_name) or os.getenv(env_name)
|
|
527
|
+
if not env_value and not skip_prompting:
|
|
528
|
+
env_value = Prompt.ask(
|
|
529
|
+
f"Enter value for {env_name}",
|
|
530
|
+
password="token" in env_name.lower() or "key" in env_name.lower(),
|
|
531
|
+
)
|
|
532
|
+
return env_value if env_value else match.group(0)
|
|
533
|
+
|
|
534
|
+
return _ENV_PLACEHOLDER_RE.sub(_replace, value)
|
|
535
|
+
|
|
536
|
+
def _resolve_variable_placeholders(self, value, resolved_env, runtime_vars):
|
|
537
|
+
"""Resolve env-var and APM template placeholders in argument strings.
|
|
538
|
+
|
|
539
|
+
Translate mode rewrites all three env-var placeholder syntaxes to
|
|
540
|
+
``${VAR}`` (so the runtime can resolve them at server-start); legacy
|
|
541
|
+
mode resolves only the legacy ``<VAR>`` form against ``resolved_env``
|
|
542
|
+
and leaves the newer ``${VAR}`` / ``${env:VAR}`` syntaxes untouched
|
|
543
|
+
for backward compatibility. APM template variables (``{runtime_var}``)
|
|
544
|
+
are always resolved at install time because they are an APM-internal
|
|
545
|
+
concept the target runtime cannot interpret.
|
|
546
|
+
|
|
547
|
+
Args:
|
|
548
|
+
value: String possibly containing placeholders.
|
|
549
|
+
resolved_env: Resolved env-var literals (legacy mode) or
|
|
550
|
+
placeholder strings (translate mode).
|
|
551
|
+
runtime_vars: Resolved APM template variables.
|
|
552
|
+
|
|
553
|
+
Returns:
|
|
554
|
+
str: ``value`` with placeholders translated or resolved.
|
|
555
|
+
"""
|
|
556
|
+
if not value:
|
|
557
|
+
return value
|
|
558
|
+
|
|
559
|
+
processed = str(value)
|
|
560
|
+
|
|
561
|
+
if self._supports_runtime_env_substitution:
|
|
562
|
+
self._last_legacy_angle_vars.update(_extract_legacy_angle_vars(processed))
|
|
563
|
+
processed = _translate_env_placeholder(processed)
|
|
564
|
+
else:
|
|
565
|
+
# Resolve only the legacy ``<VAR>`` form; newer syntaxes are
|
|
566
|
+
# preserved verbatim for backward compatibility.
|
|
567
|
+
def _replace_legacy_angle(match):
|
|
568
|
+
return resolved_env.get(match.group(1), match.group(0))
|
|
569
|
+
|
|
570
|
+
processed = _LEGACY_ANGLE_VAR_RE.sub(_replace_legacy_angle, processed)
|
|
571
|
+
|
|
572
|
+
# Resolve APM ``{runtime_var}`` template variables. The negative
|
|
573
|
+
# lookbehind on ``$`` ensures we never accidentally match the brace
|
|
574
|
+
# of an already-translated ``${VAR}`` env placeholder.
|
|
575
|
+
if runtime_vars:
|
|
576
|
+
runtime_pattern = re.compile(r"(?<!\$)\{([a-zA-Z_][a-zA-Z0-9_]*)\}")
|
|
577
|
+
|
|
578
|
+
def _replace_runtime(match):
|
|
579
|
+
return runtime_vars.get(match.group(1), match.group(0))
|
|
580
|
+
|
|
581
|
+
processed = runtime_pattern.sub(_replace_runtime, processed)
|
|
582
|
+
|
|
583
|
+
return processed
|
|
584
|
+
|
|
585
|
+
def _resolve_env_placeholders(self, value, resolved_env):
|
|
586
|
+
"""Legacy thin wrapper for backward compatibility.
|
|
587
|
+
|
|
588
|
+
Kept because external callers and the phase-3 test suite invoke
|
|
589
|
+
the pre-#1277 name. Delegates to ``_resolve_variable_placeholders``
|
|
590
|
+
with an empty ``runtime_vars`` map. New code should call
|
|
591
|
+
``_resolve_variable_placeholders`` directly.
|
|
592
|
+
"""
|
|
593
|
+
return self._resolve_variable_placeholders(value, resolved_env, {})
|
|
594
|
+
|
|
202
595
|
# ------------------------------------------------------------------
|
|
203
596
|
# Shared server-info helpers (used by all adapter subclasses)
|
|
204
597
|
# ------------------------------------------------------------------
|
|
@@ -401,10 +794,19 @@ class MCPClientAdapter(ABC):
|
|
|
401
794
|
if not name:
|
|
402
795
|
continue
|
|
403
796
|
|
|
404
|
-
# Priority 1: caller-supplied override
|
|
797
|
+
# Priority 1: caller-supplied override.
|
|
798
|
+
# An explicit empty (or whitespace-only) value is treated as
|
|
799
|
+
# "user cleared this". For names with a GitHub-style default the
|
|
800
|
+
# logic falls through so the literal default wins; for names
|
|
801
|
+
# without a default the entry is dropped from the resolved map.
|
|
405
802
|
if name in env_overrides:
|
|
406
|
-
|
|
407
|
-
|
|
803
|
+
override_value = env_overrides[name]
|
|
804
|
+
if isinstance(override_value, str) and not override_value.strip():
|
|
805
|
+
if name not in default_github_env:
|
|
806
|
+
continue
|
|
807
|
+
else:
|
|
808
|
+
resolved[name] = override_value
|
|
809
|
+
continue
|
|
408
810
|
|
|
409
811
|
# Priority 2: check GitHub-specific defaults (values are literal defaults, not env-var names)
|
|
410
812
|
if name in default_github_env:
|