apm-cli 0.13.0__tar.gz → 0.14.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.13.0/src/apm_cli.egg-info → apm_cli-0.14.0}/PKG-INFO +2 -1
- {apm_cli-0.13.0 → apm_cli-0.14.0}/pyproject.toml +2 -1
- apm_cli-0.14.0/src/apm_cli/adapters/client/base.py +451 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/adapters/client/codex.py +14 -102
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/adapters/client/copilot.py +149 -178
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/adapters/client/cursor.py +22 -108
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/adapters/client/gemini.py +42 -19
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/adapters/client/opencode.py +3 -13
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/bundle/plugin_exporter.py +35 -8
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/cli.py +2 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/_helpers.py +1 -24
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/audit.py +15 -7
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/compile/cli.py +83 -2
- apm_cli-0.14.0/src/apm_cli/commands/compile/watcher.py +249 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/init.py +64 -5
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/install.py +60 -5
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/marketplace/__init__.py +14 -15
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/marketplace/doctor.py +59 -1
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/marketplace/init.py +2 -1
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/outdated.py +33 -0
- apm_cli-0.14.0/src/apm_cli/commands/pack.py +765 -0
- apm_cli-0.14.0/src/apm_cli/commands/plugin/__init__.py +21 -0
- apm_cli-0.14.0/src/apm_cli/commands/plugin/init.py +44 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/policy.py +3 -3
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/uninstall/cli.py +14 -6
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/uninstall/engine.py +222 -12
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/update.py +34 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/compilation/claude_formatter.py +4 -15
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/compilation/distributed_compiler.py +4 -13
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/compilation/template_builder.py +40 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/core/build_orchestrator.py +59 -18
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/core/script_runner.py +11 -11
- apm_cli-0.14.0/src/apm_cli/deps/_shared.py +40 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/artifactory_orchestrator.py +3 -13
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/github_downloader.py +18 -19
- apm_cli-0.14.0/src/apm_cli/deps/tiered_ref_resolver.py +491 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/context.py +1 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/local_bundle_handler.py +7 -7
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/phases/resolve.py +26 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/services.py +38 -5
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/validation.py +43 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/integration/agent_integrator.py +82 -21
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/integration/base_integrator.py +172 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/integration/command_integrator.py +17 -10
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/integration/hook_integrator.py +190 -11
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/integration/instruction_integrator.py +12 -10
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/integration/mcp_integrator.py +166 -545
- apm_cli-0.14.0/src/apm_cli/integration/mcp_integrator_install.py +601 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/integration/prompt_integrator.py +24 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/integration/targets.py +20 -2
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/__init__.py +2 -0
- apm_cli-0.14.0/src/apm_cli/marketplace/_shared.py +48 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/builder.py +271 -308
- apm_cli-0.14.0/src/apm_cli/marketplace/diagnostics.py +13 -0
- apm_cli-0.14.0/src/apm_cli/marketplace/drift_check.py +258 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/init_template.py +22 -1
- apm_cli-0.14.0/src/apm_cli/marketplace/output_mappers.py +342 -0
- apm_cli-0.14.0/src/apm_cli/marketplace/output_profiles.py +100 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/resolver.py +155 -2
- apm_cli-0.14.0/src/apm_cli/marketplace/version_check.py +248 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/yml_schema.py +356 -4
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/models/apm_package.py +25 -1
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/models/dependency/reference.py +22 -3
- apm_cli-0.14.0/src/apm_cli/policy/_shared.py +40 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/policy/ci_checks.py +40 -22
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/policy/discovery.py +5 -5
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/policy/inheritance.py +61 -10
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/policy/matcher.py +1 -1
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/policy/models.py +1 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/policy/parser.py +28 -10
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/policy/policy_checks.py +9 -21
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/policy/schema.py +29 -7
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/registry/client.py +206 -64
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/runtime/base.py +40 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/runtime/codex_runtime.py +4 -3
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/runtime/copilot_runtime.py +4 -24
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/runtime/llm_runtime.py +2 -20
- apm_cli-0.14.0/src/apm_cli/runtime/utils.py +66 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/console.py +19 -4
- {apm_cli-0.13.0 → apm_cli-0.14.0/src/apm_cli.egg-info}/PKG-INFO +2 -1
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli.egg-info/SOURCES.txt +13 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli.egg-info/requires.txt +1 -0
- apm_cli-0.13.0/src/apm_cli/adapters/client/base.py +0 -198
- apm_cli-0.13.0/src/apm_cli/commands/compile/watcher.py +0 -170
- apm_cli-0.13.0/src/apm_cli/commands/pack.py +0 -417
- {apm_cli-0.13.0 → apm_cli-0.14.0}/AUTHORS +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/LICENSE +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/NOTICE +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/README.md +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/setup.cfg +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/adapters/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/adapters/client/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/adapters/client/claude.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/adapters/client/vscode.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/adapters/client/windsurf.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/adapters/package_manager/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/adapters/package_manager/base.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/adapters/package_manager/default_manager.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/bundle/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/bundle/local_bundle.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/bundle/lockfile_enrichment.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/bundle/packer.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/bundle/unpacker.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/cache/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/cache/git_cache.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/cache/http_cache.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/cache/integrity.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/cache/locking.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/cache/paths.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/cache/url_normalize.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/_apm_yml_writer.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/cache.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/compile/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/config.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/deps/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/deps/_utils.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/deps/cli.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/experimental.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/list_cmd.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/marketplace/check.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/marketplace/migrate.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/marketplace/outdated.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/marketplace/plugin/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/marketplace/plugin/add.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/marketplace/plugin/remove.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/marketplace/plugin/set.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/marketplace/publish.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/marketplace/validate.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/mcp.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/prune.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/run.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/runtime.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/self_update.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/targets.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/uninstall/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/commands/view.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/compilation/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/compilation/agents_compiler.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/compilation/build_id.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/compilation/constants.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/compilation/constitution.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/compilation/constitution_block.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/compilation/context_optimizer.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/compilation/gemini_formatter.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/compilation/injector.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/compilation/link_resolver.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/compilation/output_writer.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/config.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/constants.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/core/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/core/apm_yml.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/core/auth.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/core/azure_cli.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/core/command_logger.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/core/conflict_detector.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/core/docker_args.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/core/errors.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/core/experimental.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/core/null_logger.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/core/operations.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/core/safe_installer.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/core/scope.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/core/target_detection.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/core/token_manager.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/aggregator.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/apm_resolver.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/artifactory_entry.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/bare_cache.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/clone_engine.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/dependency_graph.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/download_strategies.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/git_auth_env.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/git_reference_resolver.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/git_remote_ops.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/github_downloader_validation.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/host_backends.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/installed_package.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/lockfile.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/package_validator.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/plugin_parser.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/registry_proxy.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/shared_clone_cache.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/transport_selection.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/deps/verifier.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/drift.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/factory.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/cache_pin.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/drift.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/errors.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/gitlab_resolver.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/heals/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/heals/base.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/heals/branch_ref_drift.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/heals/buggy_lockfile_recovery.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/helpers/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/helpers/security_scan.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/insecure_policy.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/mcp/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/mcp/args.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/mcp/command.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/mcp/conflicts.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/mcp/entry.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/mcp/registry.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/mcp/warnings.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/mcp/writer.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/package_resolution.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/phases/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/phases/cleanup.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/phases/download.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/phases/finalize.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/phases/heal.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/phases/integrate.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/phases/local_content.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/phases/lockfile.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/phases/policy_gate.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/phases/policy_target_check.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/phases/post_deps_local.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/phases/targets.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/pipeline.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/plan.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/presentation/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/presentation/dry_run.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/request.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/service.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/skill_path_migration.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/sources.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/summary.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/install/template.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/integration/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/integration/cleanup.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/integration/copilot_cowork_paths.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/integration/coverage.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/integration/dispatch.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/integration/skill_integrator.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/integration/skill_transformer.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/integration/utils.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/_git_utils.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/_io.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/client.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/errors.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/git_stderr.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/migration.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/models.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/pr_integration.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/publisher.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/ref_resolver.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/registry.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/semver.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/shadow_detector.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/tag_pattern.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/validator.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/version_pins.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/marketplace/yml_editor.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/models/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/models/dependency/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/models/dependency/mcp.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/models/dependency/types.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/models/plugin.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/models/results.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/models/validation.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/output/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/output/formatters.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/output/models.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/output/script_formatters.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/policy/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/policy/_help_text.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/policy/install_preflight.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/policy/outcome_routing.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/policy/project_config.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/primitives/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/primitives/discovery.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/primitives/models.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/primitives/parser.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/registry/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/registry/integration.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/registry/operations.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/runtime/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/runtime/factory.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/runtime/manager.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/security/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/security/audit_report.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/security/content_scanner.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/security/file_scanner.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/security/gate.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/update_policy.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/atomic_io.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/content_hash.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/diagnostics.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/exclude.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/file_ops.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/git_env.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/github_host.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/guards.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/helpers.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/install_tui.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/normalization.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/path_security.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/paths.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/reflink.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/short_sha.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/subprocess_env.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/version_checker.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/utils/yaml_io.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/version.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/workflow/__init__.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/workflow/discovery.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/workflow/parser.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli/workflow/runner.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli.egg-info/dependency_links.txt +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli.egg-info/entry_points.txt +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/src/apm_cli.egg-info/top_level.txt +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/tests/test_apm_package_models.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/tests/test_apm_resolver.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/tests/test_codex_docker_args_fix.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/tests/test_codex_empty_string_and_defaults.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/tests/test_collision_integration.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/tests/test_console.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/tests/test_distributed_compilation.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/tests/test_empty_string_and_defaults.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/tests/test_enhanced_discovery.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/tests/test_github_downloader.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/tests/test_github_downloader_token_precedence.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/tests/test_lockfile.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/tests/test_runnable_prompts.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/tests/test_runtime_manager_token_precedence.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/tests/test_token_manager.py +0 -0
- {apm_cli-0.13.0 → apm_cli-0.14.0}/tests/test_virtual_package_multi_install.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: apm-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.14.0
|
|
4
4
|
Summary: MCP configuration tool
|
|
5
5
|
Author-email: Daniel Meppiel <user@example.com>
|
|
6
6
|
License: MIT License
|
|
@@ -60,6 +60,7 @@ Requires-Dist: pytest-split>=0.9.0; extra == "dev"
|
|
|
60
60
|
Requires-Dist: ruff>=0.11.0; extra == "dev"
|
|
61
61
|
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
62
62
|
Requires-Dist: jsonschema>=4.0.0; extra == "dev"
|
|
63
|
+
Requires-Dist: pylint>=3.0.0; extra == "dev"
|
|
63
64
|
Provides-Extra: build
|
|
64
65
|
Requires-Dist: pyinstaller>=6.0.0; extra == "build"
|
|
65
66
|
Dynamic: license-file
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "apm-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.14.0"
|
|
8
8
|
description = "MCP configuration tool"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -48,6 +48,7 @@ dev = [
|
|
|
48
48
|
"ruff>=0.11.0",
|
|
49
49
|
"mypy>=1.0.0",
|
|
50
50
|
"jsonschema>=4.0.0",
|
|
51
|
+
"pylint>=3.0.0",
|
|
51
52
|
]
|
|
52
53
|
build = [
|
|
53
54
|
"pyinstaller>=6.0.0",
|
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
"""Base adapter interface for MCP clients."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from ...utils.console import _rich_error, _rich_warning
|
|
9
|
+
|
|
10
|
+
_INPUT_VAR_RE = re.compile(r"\$\{input:([^}]+)\}")
|
|
11
|
+
|
|
12
|
+
# Matches ${VAR} and ${env:VAR}, capturing VAR. Intentionally does NOT match
|
|
13
|
+
# ${input:VAR} (the optional ``env:`` group cannot also satisfy ``input:``),
|
|
14
|
+
# nor GitHub Actions ``${{ ... }}`` templates (the second ``{`` fails the
|
|
15
|
+
# identifier class). This keeps env-var handling fully disjoint from input
|
|
16
|
+
# variable handling, so existing _INPUT_VAR_RE call sites are unaffected.
|
|
17
|
+
_ENV_VAR_RE = re.compile(r"\$\{(?:env:)?([A-Za-z_][A-Za-z0-9_]*)\}")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class MCPClientAdapter(ABC):
|
|
21
|
+
"""Base adapter for MCP clients."""
|
|
22
|
+
|
|
23
|
+
# Identifier matching the corresponding ``KNOWN_TARGETS`` entry name.
|
|
24
|
+
# Subclasses MUST override this so target-aware code can look up
|
|
25
|
+
# per-target metadata via ``KNOWN_TARGETS[adapter.target_name]``
|
|
26
|
+
# instead of sniffing class names. The ``vscode`` adapter is the
|
|
27
|
+
# only MCP-only pseudo-target (no entry in ``KNOWN_TARGETS``), so
|
|
28
|
+
# downstream code that joins on this field must tolerate misses.
|
|
29
|
+
target_name: str = ""
|
|
30
|
+
|
|
31
|
+
# Top-level config key under which this adapter's MCP server entries
|
|
32
|
+
# live (``"mcpServers"``, ``"mcp_servers"``, ``"servers"``, ...).
|
|
33
|
+
# Subclasses MUST override this; ``MCPConflictDetector`` reads it to
|
|
34
|
+
# extract existing server configs without classname dispatch.
|
|
35
|
+
# The adapter is the canonical owner of its config schema, so this
|
|
36
|
+
# field lives here rather than on ``TargetProfile`` (which is
|
|
37
|
+
# primitive-focused) and applies uniformly to MCP-only adapters
|
|
38
|
+
# (e.g. ``VSCodeClientAdapter``) that have no ``KNOWN_TARGETS`` entry.
|
|
39
|
+
mcp_servers_key: str = ""
|
|
40
|
+
|
|
41
|
+
# Whether this adapter's config path is user/global-scoped (e.g.
|
|
42
|
+
# ``~/.copilot/``) rather than workspace-scoped (e.g. ``.vscode/``).
|
|
43
|
+
# Adapters that target a global path should override this to ``True``
|
|
44
|
+
# so that ``apm install --global`` can install MCP servers to them.
|
|
45
|
+
supports_user_scope: bool = False
|
|
46
|
+
|
|
47
|
+
def __init__(
|
|
48
|
+
self,
|
|
49
|
+
project_root: Path | str | None = None,
|
|
50
|
+
user_scope: bool = False,
|
|
51
|
+
):
|
|
52
|
+
"""Initialize the adapter with optional scope-aware path context.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
project_root: Project root used to resolve project-local config paths.
|
|
56
|
+
When not provided, adapters fall back to the current working
|
|
57
|
+
directory for project-scoped paths.
|
|
58
|
+
user_scope: Whether the adapter should resolve user-scope config
|
|
59
|
+
paths instead of project-local paths when supported.
|
|
60
|
+
"""
|
|
61
|
+
self._project_root = Path(project_root) if project_root is not None else None
|
|
62
|
+
self.user_scope = user_scope
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def project_root(self) -> Path:
|
|
66
|
+
"""Return the explicit project root or the current working directory."""
|
|
67
|
+
if self._project_root is not None:
|
|
68
|
+
return self._project_root
|
|
69
|
+
return Path(os.getcwd())
|
|
70
|
+
|
|
71
|
+
@abstractmethod
|
|
72
|
+
def get_config_path(self):
|
|
73
|
+
"""Get the path to the MCP configuration file."""
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
@abstractmethod
|
|
77
|
+
def update_config(self, config_updates) -> bool | None:
|
|
78
|
+
"""Update the MCP configuration.
|
|
79
|
+
|
|
80
|
+
Returns ``False`` or ``None`` when the config write was skipped
|
|
81
|
+
(for example because the existing file could not be parsed safely).
|
|
82
|
+
"""
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
@abstractmethod
|
|
86
|
+
def get_current_config(self):
|
|
87
|
+
"""Get the current MCP configuration."""
|
|
88
|
+
pass
|
|
89
|
+
|
|
90
|
+
@abstractmethod
|
|
91
|
+
def configure_mcp_server(
|
|
92
|
+
self,
|
|
93
|
+
server_url,
|
|
94
|
+
server_name=None,
|
|
95
|
+
enabled=True,
|
|
96
|
+
env_overrides=None,
|
|
97
|
+
server_info_cache=None,
|
|
98
|
+
runtime_vars=None,
|
|
99
|
+
):
|
|
100
|
+
"""Configure an MCP server in the client configuration.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
server_url (str): URL of the MCP server.
|
|
104
|
+
server_name (str, optional): Name of the server. Defaults to None.
|
|
105
|
+
enabled (bool, optional): Whether to enable the server. Defaults to True.
|
|
106
|
+
env_overrides (dict, optional): Environment variable overrides. Defaults to None.
|
|
107
|
+
server_info_cache (dict, optional): Pre-fetched server info to avoid duplicate registry calls.
|
|
108
|
+
runtime_vars (dict, optional): Runtime variable values. Defaults to None.
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
bool: True if successful, False otherwise.
|
|
112
|
+
"""
|
|
113
|
+
pass
|
|
114
|
+
|
|
115
|
+
@staticmethod
|
|
116
|
+
def _infer_registry_name(package):
|
|
117
|
+
"""Infer the registry type from package metadata.
|
|
118
|
+
|
|
119
|
+
The MCP registry API often returns empty ``registry_name``. This
|
|
120
|
+
method derives the registry from explicit fields first, then falls
|
|
121
|
+
back to heuristics on the package name.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
package (dict): A single package entry from the registry.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
str: Inferred registry name (e.g. "npm", "pypi", "docker") or "".
|
|
128
|
+
"""
|
|
129
|
+
if not package:
|
|
130
|
+
return ""
|
|
131
|
+
|
|
132
|
+
explicit = package.get("registry_name", "")
|
|
133
|
+
if explicit:
|
|
134
|
+
return explicit
|
|
135
|
+
|
|
136
|
+
name = package.get("name", "")
|
|
137
|
+
runtime_hint = package.get("runtime_hint", "")
|
|
138
|
+
|
|
139
|
+
# Infer from runtime_hint
|
|
140
|
+
if runtime_hint in ("npx", "npm"):
|
|
141
|
+
return "npm"
|
|
142
|
+
if runtime_hint in ("uvx", "pip", "pipx"):
|
|
143
|
+
return "pypi"
|
|
144
|
+
if runtime_hint == "docker":
|
|
145
|
+
return "docker"
|
|
146
|
+
if runtime_hint in ("dotnet", "dnx"):
|
|
147
|
+
return "nuget"
|
|
148
|
+
|
|
149
|
+
# Infer from package name patterns
|
|
150
|
+
if name.startswith("@") and "/" in name:
|
|
151
|
+
return "npm" # scoped npm package, e.g. @azure/mcp
|
|
152
|
+
if name.startswith(("ghcr.io/", "mcr.microsoft.com/", "docker.io/")):
|
|
153
|
+
return "docker"
|
|
154
|
+
if name.startswith("https://") and name.endswith(".mcpb"):
|
|
155
|
+
return "mcpb"
|
|
156
|
+
# PascalCase with dots usually means nuget (e.g. Azure.Mcp)
|
|
157
|
+
if "." in name and not name.startswith("http") and name[0].isupper():
|
|
158
|
+
return "nuget"
|
|
159
|
+
|
|
160
|
+
return ""
|
|
161
|
+
|
|
162
|
+
@staticmethod
|
|
163
|
+
def _warn_input_variables(mapping, server_name, runtime_label):
|
|
164
|
+
"""Emit a warning for each ``${input:...}`` reference found in *mapping*.
|
|
165
|
+
|
|
166
|
+
Runtimes that do not support VS Code-style input prompts (Copilot CLI,
|
|
167
|
+
Codex CLI, etc.) should call this so users know their placeholders
|
|
168
|
+
will not be resolved at runtime.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
mapping (dict): Header or env dict to scan.
|
|
172
|
+
server_name (str): Server name for the warning message.
|
|
173
|
+
runtime_label (str): Human-readable runtime name (e.g. "Copilot CLI").
|
|
174
|
+
"""
|
|
175
|
+
if not mapping:
|
|
176
|
+
return
|
|
177
|
+
seen: set = set()
|
|
178
|
+
for value in mapping.values():
|
|
179
|
+
if not isinstance(value, str):
|
|
180
|
+
continue
|
|
181
|
+
for match in _INPUT_VAR_RE.finditer(value):
|
|
182
|
+
var_id = match.group(1)
|
|
183
|
+
if var_id in seen:
|
|
184
|
+
continue
|
|
185
|
+
seen.add(var_id)
|
|
186
|
+
_rich_warning(
|
|
187
|
+
f"${{input:{var_id}}} in server "
|
|
188
|
+
f"'{server_name}' will not be resolved -- "
|
|
189
|
+
f"{runtime_label} does not support input variable prompts"
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
def normalize_project_arg(self, value):
|
|
193
|
+
"""Normalize workspace placeholders for project-local runtimes."""
|
|
194
|
+
if (
|
|
195
|
+
not self.user_scope
|
|
196
|
+
and isinstance(value, str)
|
|
197
|
+
and value in {"${workspaceFolder}", "${projectRoot}", "${workspaceRoot}"}
|
|
198
|
+
):
|
|
199
|
+
return "."
|
|
200
|
+
return value
|
|
201
|
+
|
|
202
|
+
# ------------------------------------------------------------------
|
|
203
|
+
# Shared server-info helpers (used by all adapter subclasses)
|
|
204
|
+
# ------------------------------------------------------------------
|
|
205
|
+
|
|
206
|
+
def _fetch_server_info(self, server_url: str, server_info_cache: dict | None) -> dict | None:
|
|
207
|
+
"""Look up *server_url* in *server_info_cache* or fetch from registry.
|
|
208
|
+
|
|
209
|
+
Prints a user-visible error and returns ``None`` when the server is
|
|
210
|
+
not found, so callers can do a simple ``if server_info is None: return False``
|
|
211
|
+
guard and the error message stays consistent across adapters.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
server_url: Registry reference (``owner/repo`` or full URL).
|
|
215
|
+
server_info_cache: Optional pre-fetched cache; ``None`` skips
|
|
216
|
+
the cache lookup.
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
Server-info dict on success; ``None`` when not found.
|
|
220
|
+
"""
|
|
221
|
+
if server_info_cache and server_url in server_info_cache:
|
|
222
|
+
return server_info_cache[server_url]
|
|
223
|
+
server_info = self.registry_client.find_server_by_reference(server_url)
|
|
224
|
+
if not server_info:
|
|
225
|
+
_rich_error(f"Error: MCP server '{server_url}' not found in registry")
|
|
226
|
+
return None
|
|
227
|
+
return server_info
|
|
228
|
+
|
|
229
|
+
@staticmethod
|
|
230
|
+
def _determine_config_key(server_url: str, server_name: str) -> str:
|
|
231
|
+
"""Return the configuration key to use for *server_url*/*server_name*.
|
|
232
|
+
|
|
233
|
+
The caller-supplied *server_name* takes precedence; if empty the last
|
|
234
|
+
path segment of *server_url* is used as a fallback, which mirrors the
|
|
235
|
+
convention ``owner/repo -> repo``.
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
server_url: Registry reference used as fallback source.
|
|
239
|
+
server_name: Explicit caller-supplied name (may be empty string).
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
Non-empty configuration key string.
|
|
243
|
+
"""
|
|
244
|
+
if server_name:
|
|
245
|
+
return server_name
|
|
246
|
+
if "/" in server_url:
|
|
247
|
+
return server_url.split("/")[-1]
|
|
248
|
+
return server_url
|
|
249
|
+
|
|
250
|
+
@staticmethod
|
|
251
|
+
def _apply_pypi_homebrew_generic_config(
|
|
252
|
+
config: dict,
|
|
253
|
+
registry_name: str,
|
|
254
|
+
package_name: str,
|
|
255
|
+
runtime_hint: str,
|
|
256
|
+
processed_runtime_args: list,
|
|
257
|
+
processed_package_args: list,
|
|
258
|
+
resolved_env: dict,
|
|
259
|
+
) -> None:
|
|
260
|
+
"""Apply pypi / homebrew / generic (uvx / brew / npx) run config to *config*.
|
|
261
|
+
|
|
262
|
+
Mutates *config* in-place with ``command``, ``args``, and optionally
|
|
263
|
+
``env`` keys appropriate for the detected registry type.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
config: Mutable server-config dict to populate.
|
|
267
|
+
registry_name: Registry identifier (``"pypi"``, ``"homebrew"``,
|
|
268
|
+
``"npm"``, or any other string treated as generic).
|
|
269
|
+
package_name: Base package / formula / module name.
|
|
270
|
+
runtime_hint: Caller-specified runtime hint (e.g. ``"uvx"``).
|
|
271
|
+
processed_runtime_args: Fully resolved positional args for the
|
|
272
|
+
runtime launcher.
|
|
273
|
+
processed_package_args: Fully resolved positional args appended
|
|
274
|
+
after the package name.
|
|
275
|
+
resolved_env: Pre-resolved environment variables dict; an empty
|
|
276
|
+
dict is omitted.
|
|
277
|
+
"""
|
|
278
|
+
if registry_name == "pypi":
|
|
279
|
+
launcher = runtime_hint or "uvx"
|
|
280
|
+
config["command"] = launcher
|
|
281
|
+
config["args"] = [package_name] + processed_runtime_args + processed_package_args # noqa: RUF005
|
|
282
|
+
elif registry_name == "homebrew":
|
|
283
|
+
formula_name = package_name.split("/")[-1] if "/" in package_name else package_name
|
|
284
|
+
config["command"] = formula_name
|
|
285
|
+
config["args"] = processed_runtime_args + processed_package_args
|
|
286
|
+
else:
|
|
287
|
+
# Generic / npm-compatible fallback
|
|
288
|
+
config["command"] = "npx"
|
|
289
|
+
config["args"] = processed_runtime_args + ["-y", package_name] + processed_package_args # noqa: RUF005
|
|
290
|
+
if resolved_env:
|
|
291
|
+
config["env"] = resolved_env
|
|
292
|
+
|
|
293
|
+
def _apply_auth_and_headers_impl(
|
|
294
|
+
self,
|
|
295
|
+
config: dict,
|
|
296
|
+
remote: dict,
|
|
297
|
+
server_info: dict,
|
|
298
|
+
env_overrides: dict,
|
|
299
|
+
runtime_label: str,
|
|
300
|
+
token_manager_class,
|
|
301
|
+
) -> None:
|
|
302
|
+
"""Core implementation of GitHub-token injection and header merging.
|
|
303
|
+
|
|
304
|
+
Factored out so that each concrete adapter subclass can supply its own
|
|
305
|
+
*token_manager_class* (looked up from the subclass module's namespace),
|
|
306
|
+
allowing :func:`unittest.mock.patch` to intercept the class at the
|
|
307
|
+
right module scope in tests.
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
config: Mutable config dict updated in place.
|
|
311
|
+
remote: Registry remote entry (may contain a ``"headers"`` list).
|
|
312
|
+
server_info: Registry server metadata used for name / URL lookup.
|
|
313
|
+
env_overrides: Caller-supplied env-var override mapping.
|
|
314
|
+
runtime_label: Label for diagnostic messages.
|
|
315
|
+
token_manager_class: The ``GitHubTokenManager`` class (or mock) to
|
|
316
|
+
instantiate. Passed by the caller so tests can patch the right
|
|
317
|
+
module-level name.
|
|
318
|
+
"""
|
|
319
|
+
server_name = server_info.get("name", "")
|
|
320
|
+
is_github_server = self._is_github_server(server_name, remote.get("url", ""))
|
|
321
|
+
local_token_injected = False
|
|
322
|
+
if is_github_server:
|
|
323
|
+
_tm = token_manager_class()
|
|
324
|
+
github_token = _tm.get_token_for_purpose("copilot") or os.getenv(
|
|
325
|
+
"GITHUB_PERSONAL_ACCESS_TOKEN"
|
|
326
|
+
)
|
|
327
|
+
if github_token:
|
|
328
|
+
config["headers"] = {"Authorization": f"Bearer {github_token}"}
|
|
329
|
+
local_token_injected = True
|
|
330
|
+
headers = remote.get("headers", [])
|
|
331
|
+
if headers:
|
|
332
|
+
if "headers" not in config:
|
|
333
|
+
config["headers"] = {}
|
|
334
|
+
for header in headers:
|
|
335
|
+
header_name = header.get("name", "")
|
|
336
|
+
header_value = header.get("value", "")
|
|
337
|
+
if header_name and header_value:
|
|
338
|
+
if header_name == "Authorization" and local_token_injected:
|
|
339
|
+
continue
|
|
340
|
+
resolved_value = self._resolve_env_variable(
|
|
341
|
+
header_name, header_value, env_overrides
|
|
342
|
+
)
|
|
343
|
+
config["headers"][header_name] = resolved_value
|
|
344
|
+
if config.get("headers"):
|
|
345
|
+
self._warn_input_variables(
|
|
346
|
+
config["headers"], server_info.get("name", ""), runtime_label
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
@staticmethod
|
|
350
|
+
def _resolve_env_vars_with_prompting(
|
|
351
|
+
env_vars: list,
|
|
352
|
+
env_overrides: dict,
|
|
353
|
+
default_github_env: dict,
|
|
354
|
+
) -> dict:
|
|
355
|
+
"""Resolve *env_vars* from overrides, environment, or interactive prompts.
|
|
356
|
+
|
|
357
|
+
Identical logic shared between
|
|
358
|
+
:meth:`CopilotClientAdapter._process_environment_variables` and
|
|
359
|
+
:meth:`CodexClientAdapter._process_environment_variables`.
|
|
360
|
+
|
|
361
|
+
All imports are deferred so that ``rich.prompt`` (an optional
|
|
362
|
+
dependency) is never imported at module load time.
|
|
363
|
+
|
|
364
|
+
Args:
|
|
365
|
+
env_vars: List of env-var descriptor dicts from the registry.
|
|
366
|
+
env_overrides: Pre-collected ``{name: value}`` overrides (empty
|
|
367
|
+
dict when none).
|
|
368
|
+
default_github_env: Mapping of well-known GitHub variable names
|
|
369
|
+
to their preferred environment-variable lookup names.
|
|
370
|
+
|
|
371
|
+
Returns:
|
|
372
|
+
``resolved`` dict mapping each env-var name to its resolved value
|
|
373
|
+
(empty string when unresolvable).
|
|
374
|
+
"""
|
|
375
|
+
import sys
|
|
376
|
+
|
|
377
|
+
env_overrides = env_overrides or {}
|
|
378
|
+
resolved: dict = {}
|
|
379
|
+
|
|
380
|
+
# Determine whether interactive prompting is available.
|
|
381
|
+
# If env_overrides is provided the CLI has already collected variables -- never prompt again.
|
|
382
|
+
skip_prompting = (
|
|
383
|
+
bool(env_overrides)
|
|
384
|
+
or bool(os.getenv("CI"))
|
|
385
|
+
or bool(os.getenv("APM_E2E_TESTS"))
|
|
386
|
+
or not sys.stdout.isatty()
|
|
387
|
+
or not sys.stdin.isatty()
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
# First pass: identify variables with empty values to warn the user.
|
|
391
|
+
empty_value_vars = [ev for ev in env_vars if ev.get("required") and not ev.get("value")]
|
|
392
|
+
if empty_value_vars and skip_prompting:
|
|
393
|
+
var_names = [ev.get("name") for ev in empty_value_vars]
|
|
394
|
+
_rich_warning(
|
|
395
|
+
f"Warning: The following required environment variables have no default "
|
|
396
|
+
f"value and cannot be prompted in non-interactive mode: {var_names}"
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
for env_var in env_vars:
|
|
400
|
+
name = env_var.get("name", "")
|
|
401
|
+
if not name:
|
|
402
|
+
continue
|
|
403
|
+
|
|
404
|
+
# Priority 1: caller-supplied override
|
|
405
|
+
if name in env_overrides:
|
|
406
|
+
resolved[name] = env_overrides[name]
|
|
407
|
+
continue
|
|
408
|
+
|
|
409
|
+
# Priority 2: check GitHub-specific defaults (values are literal defaults, not env-var names)
|
|
410
|
+
if name in default_github_env:
|
|
411
|
+
resolved[name] = os.getenv(name) or default_github_env[name]
|
|
412
|
+
continue
|
|
413
|
+
|
|
414
|
+
# Priority 3: environment variable with the same name
|
|
415
|
+
env_val = os.getenv(name, "")
|
|
416
|
+
if env_val:
|
|
417
|
+
resolved[name] = env_val
|
|
418
|
+
continue
|
|
419
|
+
|
|
420
|
+
# Priority 4: interactive prompt
|
|
421
|
+
default_value = env_var.get("value", "")
|
|
422
|
+
required = env_var.get("required", False)
|
|
423
|
+
|
|
424
|
+
if not skip_prompting:
|
|
425
|
+
from rich.prompt import Prompt
|
|
426
|
+
|
|
427
|
+
description = env_var.get("description", "")
|
|
428
|
+
prompt_text = f"Enter value for {name}"
|
|
429
|
+
if description:
|
|
430
|
+
prompt_text += f" ({description})"
|
|
431
|
+
is_secret = "token" in name.lower() or "key" in name.lower()
|
|
432
|
+
user_input = Prompt.ask(
|
|
433
|
+
prompt_text,
|
|
434
|
+
default=default_value,
|
|
435
|
+
password=True # noqa: SIM210
|
|
436
|
+
if is_secret
|
|
437
|
+
else False,
|
|
438
|
+
)
|
|
439
|
+
resolved[name] = user_input
|
|
440
|
+
elif default_value:
|
|
441
|
+
resolved[name] = default_value
|
|
442
|
+
elif required:
|
|
443
|
+
_rich_warning(
|
|
444
|
+
f"Warning: Required environment variable '{name}' could not be resolved. "
|
|
445
|
+
f"The MCP server may not function correctly."
|
|
446
|
+
)
|
|
447
|
+
resolved[name] = ""
|
|
448
|
+
else:
|
|
449
|
+
resolved[name] = default_value
|
|
450
|
+
|
|
451
|
+
return resolved
|
|
@@ -143,16 +143,8 @@ class CodexClientAdapter(MCPClientAdapter):
|
|
|
143
143
|
return False
|
|
144
144
|
|
|
145
145
|
try:
|
|
146
|
-
|
|
147
|
-
if
|
|
148
|
-
server_info = server_info_cache[server_url]
|
|
149
|
-
else:
|
|
150
|
-
# Fallback to registry lookup if not cached
|
|
151
|
-
server_info = self.registry_client.find_server_by_reference(server_url)
|
|
152
|
-
|
|
153
|
-
# Fail if server is not found in registry - security requirement
|
|
154
|
-
if not server_info:
|
|
155
|
-
print(f"Error: MCP server '{server_url}' not found in registry")
|
|
146
|
+
server_info = self._fetch_server_info(server_url, server_info_cache)
|
|
147
|
+
if server_info is None:
|
|
156
148
|
return False
|
|
157
149
|
|
|
158
150
|
# Check for remote servers early - Codex doesn't support remote/SSE servers
|
|
@@ -299,33 +291,21 @@ class CodexClientAdapter(MCPClientAdapter):
|
|
|
299
291
|
if resolved_env:
|
|
300
292
|
config["env"] = resolved_env
|
|
301
293
|
elif registry_name == "pypi":
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
# For homebrew packages, assume the binary name is the command
|
|
311
|
-
config["command"] = (
|
|
312
|
-
package_name.split("/")[-1] if "/" in package_name else package_name
|
|
294
|
+
self._apply_pypi_homebrew_generic_config(
|
|
295
|
+
config,
|
|
296
|
+
registry_name,
|
|
297
|
+
package_name,
|
|
298
|
+
runtime_hint,
|
|
299
|
+
processed_runtime_args,
|
|
300
|
+
processed_package_args,
|
|
301
|
+
resolved_env,
|
|
313
302
|
)
|
|
314
|
-
config["args"] = processed_runtime_args + processed_package_args
|
|
315
|
-
# For Homebrew packages, use env block for environment variables
|
|
316
|
-
if resolved_env:
|
|
317
|
-
config["env"] = resolved_env
|
|
318
|
-
else:
|
|
319
|
-
# Generic package handling
|
|
320
|
-
config["command"] = runtime_hint or package_name
|
|
321
|
-
config["args"] = processed_runtime_args + processed_package_args
|
|
322
|
-
# For generic packages, use env block for environment variables
|
|
323
|
-
if resolved_env:
|
|
324
|
-
config["env"] = resolved_env
|
|
325
303
|
|
|
326
304
|
return config
|
|
327
305
|
|
|
328
|
-
def _process_arguments(
|
|
306
|
+
def _process_arguments( # pylint: disable=duplicate-code # structural similarity with copilot adapter is intentional
|
|
307
|
+
self, arguments, resolved_env=None, runtime_vars=None
|
|
308
|
+
):
|
|
329
309
|
"""Process argument objects to extract simple string values with environment resolution.
|
|
330
310
|
|
|
331
311
|
Args:
|
|
@@ -390,76 +370,8 @@ class CodexClientAdapter(MCPClientAdapter):
|
|
|
390
370
|
Returns:
|
|
391
371
|
dict: Dictionary of resolved environment variable values.
|
|
392
372
|
"""
|
|
393
|
-
import os
|
|
394
|
-
import sys
|
|
395
|
-
|
|
396
|
-
from rich.prompt import Prompt
|
|
397
|
-
|
|
398
|
-
resolved = {}
|
|
399
|
-
env_overrides = env_overrides or {}
|
|
400
|
-
|
|
401
|
-
# If env_overrides is provided, it means the CLI has already handled environment variable collection
|
|
402
|
-
# In this case, we should NEVER prompt for additional variables
|
|
403
|
-
skip_prompting = bool(env_overrides)
|
|
404
|
-
|
|
405
|
-
# Check for CI/automated environment via APM_E2E_TESTS flag (more reliable than TTY detection)
|
|
406
|
-
if os.getenv("APM_E2E_TESTS") == "1":
|
|
407
|
-
skip_prompting = True
|
|
408
|
-
print(f" APM_E2E_TESTS detected, will skip environment variable prompts") # noqa: F541
|
|
409
|
-
|
|
410
|
-
# Also skip prompting if we're in a non-interactive environment (fallback)
|
|
411
|
-
is_interactive = sys.stdin.isatty() and sys.stdout.isatty()
|
|
412
|
-
if not is_interactive:
|
|
413
|
-
skip_prompting = True
|
|
414
|
-
|
|
415
|
-
# Add default GitHub MCP server environment variables for essential functionality first
|
|
416
|
-
# This ensures variables have defaults when user provides empty values or they're optional
|
|
417
373
|
default_github_env = {"GITHUB_TOOLSETS": "context", "GITHUB_DYNAMIC_TOOLSETS": "1"}
|
|
418
|
-
|
|
419
|
-
# Track which variables were explicitly provided with empty values (user wants defaults)
|
|
420
|
-
empty_value_vars = set()
|
|
421
|
-
if env_overrides:
|
|
422
|
-
for key, value in env_overrides.items():
|
|
423
|
-
if key in env_overrides and (not value or not value.strip()):
|
|
424
|
-
empty_value_vars.add(key)
|
|
425
|
-
|
|
426
|
-
for env_var in env_vars:
|
|
427
|
-
if isinstance(env_var, dict):
|
|
428
|
-
name = env_var.get("name", "")
|
|
429
|
-
description = env_var.get("description", "")
|
|
430
|
-
required = env_var.get("required", True)
|
|
431
|
-
|
|
432
|
-
if name:
|
|
433
|
-
# First check overrides, then environment
|
|
434
|
-
value = env_overrides.get(name) or os.getenv(name)
|
|
435
|
-
|
|
436
|
-
# Only prompt if not provided in overrides or environment AND it's required AND we're not in managed override mode
|
|
437
|
-
if not value and required and not skip_prompting:
|
|
438
|
-
# Only prompt if not provided in overrides
|
|
439
|
-
prompt_text = f"Enter value for {name}"
|
|
440
|
-
if description:
|
|
441
|
-
prompt_text += f" ({description})"
|
|
442
|
-
value = Prompt.ask(
|
|
443
|
-
prompt_text,
|
|
444
|
-
password=True # noqa: SIM210
|
|
445
|
-
if "token" in name.lower() or "key" in name.lower()
|
|
446
|
-
else False,
|
|
447
|
-
)
|
|
448
|
-
|
|
449
|
-
# Add variable if it has a value OR if user explicitly provided empty and we have a default
|
|
450
|
-
if value and value.strip():
|
|
451
|
-
resolved[name] = value
|
|
452
|
-
elif name in empty_value_vars and name in default_github_env:
|
|
453
|
-
# User provided empty value and we have a default - use default
|
|
454
|
-
resolved[name] = default_github_env[name]
|
|
455
|
-
elif not required and name in default_github_env:
|
|
456
|
-
# Variable is optional and we have a default - use default
|
|
457
|
-
resolved[name] = default_github_env[name]
|
|
458
|
-
elif skip_prompting and name in default_github_env:
|
|
459
|
-
# Non-interactive environment and we have a default - use default
|
|
460
|
-
resolved[name] = default_github_env[name]
|
|
461
|
-
|
|
462
|
-
return resolved
|
|
374
|
+
return self._resolve_env_vars_with_prompting(env_vars, env_overrides, default_github_env)
|
|
463
375
|
|
|
464
376
|
def _resolve_variable_placeholders(self, value, resolved_env, runtime_vars):
|
|
465
377
|
"""Resolve both environment and runtime variable placeholders in values.
|