apm-cli 0.27.0__tar.gz → 0.29.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.27.0/src/apm_cli.egg-info → apm_cli-0.29.0}/PKG-INFO +6 -5
- {apm_cli-0.27.0 → apm_cli-0.29.0}/README.md +5 -4
- {apm_cli-0.27.0 → apm_cli-0.29.0}/pyproject.toml +1 -1
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/client/base.py +93 -2
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/client/codex.py +19 -4
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/client/copilot.py +23 -8
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/client/cursor.py +2 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/client/gemini.py +2 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/client/kiro.py +2 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/client/vscode.py +110 -82
- apm_cli-0.29.0/src/apm_cli/agent_plugins/__init__.py +146 -0
- apm_cli-0.29.0/src/apm_cli/agent_plugins/assets.py +368 -0
- apm_cli-0.29.0/src/apm_cli/agent_plugins/constants.py +23 -0
- apm_cli-0.29.0/src/apm_cli/agent_plugins/errors.py +162 -0
- apm_cli-0.29.0/src/apm_cli/agent_plugins/io.py +101 -0
- apm_cli-0.29.0/src/apm_cli/agent_plugins/ir.py +196 -0
- apm_cli-0.29.0/src/apm_cli/agent_plugins/loader.py +966 -0
- apm_cli-0.29.0/src/apm_cli/agent_plugins/projection.py +61 -0
- apm_cli-0.29.0/src/apm_cli/agent_plugins/validation.py +690 -0
- apm_cli-0.29.0/src/apm_cli/bundle/agent_plugin_exporter.py +521 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/bundle/attest.py +1 -1
- apm_cli-0.29.0/src/apm_cli/bundle/claude_plugin_exporter.py +32 -0
- apm_cli-0.29.0/src/apm_cli/bundle/export_common.py +41 -0
- apm_cli-0.29.0/src/apm_cli/bundle/formats.py +147 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/bundle/local_bundle.py +158 -18
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/bundle/lockfile_enrichment.py +28 -17
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/bundle/packer.py +28 -8
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/bundle/plugin_exporter.py +63 -53
- apm_cli-0.29.0/src/apm_cli/bundle/reproducible_archive.py +79 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/_helpers.py +42 -33
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/compile/cli.py +2 -1
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/deps/_utils.py +26 -4
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/deps/cli.py +61 -3
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/init.py +127 -21
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/install.py +101 -115
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/lock.py +21 -5
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/marketplace/__init__.py +21 -15
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/marketplace/audit.py +27 -5
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/marketplace/check.py +30 -15
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/marketplace/plugin/__init__.py +5 -3
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/marketplace/plugin/add.py +11 -3
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/marketplace/validate.py +15 -11
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/mcp.py +8 -5
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/outdated.py +9 -2
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/pack.py +84 -24
- apm_cli-0.29.0/src/apm_cli/commands/plugin/init.py +73 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/prune.py +116 -7
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/uninstall/cli.py +165 -15
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/uninstall/engine.py +209 -94
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/compilation/agents_compiler.py +67 -14
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/compilation/context_optimizer.py +211 -123
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/compilation/distributed_compiler.py +133 -50
- apm_cli-0.29.0/src/apm_cli/compilation/inventory.py +122 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/compilation/user_root_context.py +39 -12
- apm_cli-0.29.0/src/apm_cli/copilot_plugins/__init__.py +54 -0
- apm_cli-0.29.0/src/apm_cli/copilot_plugins/capability.py +142 -0
- apm_cli-0.29.0/src/apm_cli/copilot_plugins/catalog.py +106 -0
- apm_cli-0.29.0/src/apm_cli/copilot_plugins/constants.py +32 -0
- apm_cli-0.29.0/src/apm_cli/copilot_plugins/registrar.py +659 -0
- apm_cli-0.29.0/src/apm_cli/copilot_plugins/settings.py +306 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/apm_yml.py +11 -3
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/auth.py +25 -7
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/build_orchestrator.py +40 -20
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/command_logger.py +11 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/deployment_ledger.py +24 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/experimental.py +6 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/plugin_manifest.py +56 -21
- apm_cli-0.29.0/src/apm_cli/core/project_name.py +19 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/script_executors.py +3 -31
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/script_runner.py +2 -1
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/target_catalog.py +39 -4
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/target_detection.py +34 -24
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/_shared.py +25 -1
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/apm_resolver.py +23 -1
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/artifactory_orchestrator.py +4 -5
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/bare_cache.py +4 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/git_auth_env.py +20 -7
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/github_downloader.py +19 -21
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/lockfile.py +29 -14
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/package_validator.py +12 -6
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/plugin_parser.py +398 -66
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/registry/resolver.py +36 -2
- apm_cli-0.29.0/src/apm_cli/hook_contract.py +266 -0
- apm_cli-0.29.0/src/apm_cli/install/argv.py +34 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/context.py +9 -0
- apm_cli-0.29.0/src/apm_cli/install/deployable_source_plan.py +264 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/drift.py +55 -7
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/exec_gate.py +74 -7
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/helpers/ref_reuse.py +16 -7
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/helpers/security_scan.py +20 -9
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/integrity.py +27 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/local_bundle_handler.py +261 -59
- apm_cli-0.29.0/src/apm_cli/install/local_bundle_paths.py +93 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/lsp/integration.py +73 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/manifest_reconcile.py +127 -40
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/mcp/integration.py +91 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/mcp/ownership.py +4 -4
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/mcp/registry.py +6 -18
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/mcp/warnings.py +29 -17
- apm_cli-0.29.0/src/apm_cli/install/native_plugin_admission.py +207 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/package_resolution.py +96 -6
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/phases/_skip_logic.py +13 -2
- apm_cli-0.29.0/src/apm_cli/install/phases/copilot_plugins.py +198 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/phases/finalize.py +16 -4
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/phases/integrate.py +24 -2
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/phases/targets.py +23 -37
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/pipeline.py +39 -45
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/request.py +1 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/resolution_staging.py +9 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/service.py +77 -4
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/services.py +148 -78
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/sources.py +106 -68
- apm_cli-0.29.0/src/apm_cli/install/target_hints.py +53 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/template.py +202 -20
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/agent_integrator.py +263 -21
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/base_integrator.py +13 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/canvas_integrator.py +15 -1
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/command_integrator.py +7 -3
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/hook_bundle.py +46 -12
- apm_cli-0.29.0/src/apm_cli/integration/hook_command_paths.py +58 -0
- apm_cli-0.29.0/src/apm_cli/integration/hook_command_warnings.py +25 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/hook_integrator.py +233 -219
- apm_cli-0.29.0/src/apm_cli/integration/hook_ir.py +5 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/hook_native_formats.py +6 -73
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/hook_ownership.py +68 -15
- apm_cli-0.29.0/src/apm_cli/integration/hook_reintegration.py +37 -0
- apm_cli-0.29.0/src/apm_cli/integration/hook_source_selection.py +188 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/instruction_integrator.py +26 -22
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/kiro_hook_integrator.py +11 -10
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/mcp_config_view.py +33 -6
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/mcp_integrator.py +10 -1
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/mcp_integrator_install.py +24 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/prompt_integrator.py +9 -3
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/skill_integrator.py +387 -302
- apm_cli-0.29.0/src/apm_cli/integration/skill_package_routing.py +49 -0
- apm_cli-0.29.0/src/apm_cli/integration/skill_support.py +97 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/targets.py +50 -2
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/audit.py +48 -3
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/builder.py +39 -10
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/drift_check.py +12 -18
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/models.py +108 -33
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/output_profiles.py +39 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/resolver.py +32 -10
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/validator.py +15 -7
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/version_check.py +91 -11
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/yml_schema.py +40 -21
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/apm_package.py +73 -42
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/dependency/identity.py +1 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/dependency/mcp.py +26 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/dependency/reference.py +74 -110
- apm_cli-0.29.0/src/apm_cli/models/dependency/registry_entry.py +119 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/format_detection.py +76 -17
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/validation.py +128 -21
- apm_cli-0.29.0/src/apm_cli/policy/_gitlab.py +490 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/policy/_help_text.py +2 -2
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/policy/ci_checks.py +83 -6
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/policy/discovery.py +109 -115
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/primitives/discovery.py +131 -27
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/primitives/parser.py +3 -29
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/registry/operations.py +44 -10
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/runtime/copilot_runtime.py +12 -6
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/security/executables.py +129 -20
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/security/gate.py +69 -2
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/content_hash.py +12 -5
- apm_cli-0.29.0/src/apm_cli/utils/net.py +58 -0
- apm_cli-0.29.0/src/apm_cli/utils/path_security.py +243 -0
- apm_cli-0.29.0/src/apm_cli/utils/patterns.py +285 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/yaml_io.py +105 -23
- {apm_cli-0.27.0 → apm_cli-0.29.0/src/apm_cli.egg-info}/PKG-INFO +6 -5
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli.egg-info/SOURCES.txt +38 -0
- apm_cli-0.27.0/src/apm_cli/commands/plugin/init.py +0 -44
- apm_cli-0.27.0/src/apm_cli/integration/hook_ir.py +0 -54
- apm_cli-0.27.0/src/apm_cli/utils/path_security.py +0 -130
- apm_cli-0.27.0/src/apm_cli/utils/patterns.py +0 -91
- {apm_cli-0.27.0 → apm_cli-0.29.0}/AUTHORS +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/LICENSE +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/NOTICE +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/setup.cfg +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/client/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/client/_mcp_runtime_args.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/client/antigravity.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/client/claude.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/client/hermes.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/client/intellij.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/client/opencode.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/client/windsurf.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/package_manager/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/package_manager/base.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/adapters/package_manager/default_manager.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/bootstrap_mirror.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/bundle/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/bundle/plugin_layout.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/bundle/unpacker.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/cache/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/cache/git_cache.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/cache/http_cache.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/cache/integrity.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/cache/locking.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/cache/paths.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/cache/url_normalize.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/cli.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/_apm_yml_writer.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/approve.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/audit.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/cache.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/compile/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/compile/watcher.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/config.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/deps/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/deps/why.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/doctor.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/experimental.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/find.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/lifecycle.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/list_cmd.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/marketplace/doctor.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/marketplace/init.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/marketplace/migrate.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/marketplace/outdated.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/marketplace/plugin/remove.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/marketplace/plugin/set.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/plugin/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/policy.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/publish.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/run.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/runtime.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/self_update.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/targets.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/uninstall/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/uninstall/lockfile_state.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/update.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/commands/view.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/compilation/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/compilation/build_id.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/compilation/claude_formatter.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/compilation/constants.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/compilation/constitution.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/compilation/constitution_block.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/compilation/gemini_formatter.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/compilation/injector.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/compilation/link_resolver.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/compilation/managed_section.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/compilation/output_writer.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/compilation/template_builder.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/config.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/constants.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/_child_tls/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/_child_tls/_apm_tls.pth +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/_child_tls/_apm_tls_bootstrap.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/azure_cli.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/conflict_detector.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/deployment_state.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/docker_args.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/errors.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/host_providers.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/install_audit.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/lifecycle_scripts.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/null_logger.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/operations.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/output_mode.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/safe_installer.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/scope.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/script_trust.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/tls_trust.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/core/token_manager.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/aggregator.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/artifactory_entry.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/clone_engine.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/dependency_graph.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/download_strategies.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/git_file_transport.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/git_reference_resolver.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/git_remote_ops.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/git_semver_resolver.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/github_downloader_validation.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/github_rate_limit.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/host_backends.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/installed_package.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/outdated_ref_cache.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/outdated_row.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/path_anchoring.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/reachability.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/registry/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/registry/auth.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/registry/client.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/registry/config_loader.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/registry/extractor.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/registry/feature_gate.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/registry/outdated.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/registry/semver.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/registry_proxy.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/revision_pins.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/shared_clone_cache.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/tiered_ref_resolver.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/transport_selection.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/verifier.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/deps/why_walker.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/drift.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/export/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/export/authoring.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/export/declared_license.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/export/formats.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/export/purl.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/export/sbom.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/export/spdx.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/export/spdx_data.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/factory.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/artifactory_resolver.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/audit_replay.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/cache_pin.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/deployed_paths.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/drift_render.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/errors.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/gitlab_resolver.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/heals/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/heals/base.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/heals/branch_ref_drift.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/heals/buggy_lockfile_recovery.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/helpers/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/helpers/no_work.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/helpers/ref_seed.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/insecure_policy.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/lsp/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/mcp/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/mcp/args.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/mcp/command.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/mcp/conflicts.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/mcp/entry.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/mcp/writer.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/outcome.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/package_selection.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/phases/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/phases/_redownload.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/phases/audit.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/phases/cleanup.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/phases/download.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/phases/heal.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/phases/local_content.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/phases/lockfile.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/phases/policy_gate.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/phases/policy_target_check.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/phases/post_deps_local.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/phases/resolve.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/plan.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/presentation/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/presentation/dry_run.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/registry_wiring.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/root_redirect.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/service_integration.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/skill_path_migration.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/summary.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/target_filter.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/target_warnings.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/transaction.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/install/validation.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/_hook_dropped_targets.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/_shared.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/cleanup.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/copilot_app_db.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/copilot_app_project.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/copilot_app_workflow_integrator.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/copilot_app_ws.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/copilot_cowork_paths.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/coverage.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/dispatch.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/hook_file_routing.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/lsp_integrator.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/opencode_frontmatter.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/skill_transformer.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/integration/utils.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/_git_utils.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/_io.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/_shared.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/auth_helpers.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/client.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/diagnostics.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/errors.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/git_stderr.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/init_template.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/migration.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/output_mappers.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/ref_resolver.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/registry.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/semver.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/shadow_detector.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/tag_pattern.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/version_pins.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/version_resolver.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/marketplace/yml_editor.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/dependency/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/dependency/lsp.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/dependency/materialization.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/dependency/object_fields.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/dependency/provider_coordinates.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/dependency/selection.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/dependency/subsets.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/dependency/types.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/manifest_contract.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/plugin.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/models/results.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/output/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/output/formatters.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/output/models.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/output/script_formatters.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/policy/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/policy/_constraint_pinning.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/policy/_shared.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/policy/inheritance.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/policy/install_preflight.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/policy/matcher.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/policy/models.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/policy/outcome_routing.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/policy/parser.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/policy/policy_checks.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/policy/project_config.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/policy/schema.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/primitives/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/primitives/models.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/registry/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/registry/client.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/registry/integration.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/runtime/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/runtime/base.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/runtime/codex_runtime.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/runtime/factory.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/runtime/llm_runtime.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/runtime/manager.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/runtime/registry.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/runtime/utils.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/security/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/security/audit_report.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/security/content_scanner.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/security/external/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/security/external/base.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/security/external/gate.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/security/external/generic_sarif.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/security/external/options.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/security/external/registry.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/security/external/runner.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/security/external/sarif_ingest.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/security/external/skillspector.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/security/file_scanner.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/update_policy.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/archive.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/atomic_io.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/console.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/diagnostics.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/exclude.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/file_ops.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/git_env.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/git_sparse.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/github_host.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/guards.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/helpers.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/install_tui.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/normalization.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/paths.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/perf_stats.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/reflink.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/short_sha.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/subprocess_env.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/utils/version_checker.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/version.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/workflow/__init__.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/workflow/discovery.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/workflow/parser.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli/workflow/runner.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli.egg-info/dependency_links.txt +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli.egg-info/entry_points.txt +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli.egg-info/requires.txt +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/src/apm_cli.egg-info/top_level.txt +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/tests/test_apm_package_models.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/tests/test_apm_resolver.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/tests/test_codex_docker_args_fix.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/tests/test_codex_empty_string_and_defaults.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/tests/test_collision_integration.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/tests/test_console.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/tests/test_distributed_compilation.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/tests/test_empty_string_and_defaults.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/tests/test_enhanced_discovery.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/tests/test_github_downloader.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/tests/test_github_downloader_token_precedence.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/tests/test_gitlab_git_transport.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/tests/test_lockfile.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/tests/test_runnable_prompts.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/tests/test_runtime_manager_token_precedence.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.0}/tests/test_token_manager.py +0 -0
- {apm_cli-0.27.0 → apm_cli-0.29.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.29.0
|
|
4
4
|
Summary: MCP configuration tool
|
|
5
5
|
Author-email: Daniel Meppiel <user@example.com>
|
|
6
6
|
License: MIT License
|
|
@@ -76,9 +76,9 @@ Dynamic: license-file
|
|
|
76
76
|
|
|
77
77
|
Think `package.json`, `requirements.txt`, or `Cargo.toml` — but for AI agent configuration.
|
|
78
78
|
|
|
79
|
-
GitHub Copilot
|
|
79
|
+
GitHub Copilot | Claude Code | Grok Build | Cursor | OpenCode | Codex | Gemini | Windsurf | Kiro
|
|
80
80
|
|
|
81
|
-
**[Documentation](https://microsoft.github.io/apm/)** · **[Quick Start](https://microsoft.github.io/apm/getting-started/quick-start/)** · **[CLI Reference](https://microsoft.github.io/apm/reference/cli-commands/)** · **[Roadmap](https://github.com/
|
|
81
|
+
**[Documentation](https://microsoft.github.io/apm/)** · **[Quick Start](https://microsoft.github.io/apm/getting-started/quick-start/)** · **[CLI Reference](https://microsoft.github.io/apm/reference/cli-commands/)** · **[v0.29 Roadmap](https://github.com/microsoft/apm/milestone/17)**
|
|
82
82
|
|
|
83
83
|
---
|
|
84
84
|
|
|
@@ -139,7 +139,7 @@ One command, no configuration -- VS Code and GitHub Copilot read the file automa
|
|
|
139
139
|
|
|
140
140
|
One `apm.yml` describes every primitive your agents need — instructions, skills, prompts, agents, hooks, plugins, MCP servers — and `apm install` reproduces the exact same setup across every client on every machine. `apm.lock.yaml` pins the resolved tree the way `package-lock.json` does for npm.
|
|
141
141
|
|
|
142
|
-
- **[One manifest for everything](https://microsoft.github.io/apm/reference/primitive-types/)**
|
|
142
|
+
- **[One manifest for everything](https://microsoft.github.io/apm/reference/primitive-types/)** -- declared once, deployed across Copilot, Claude, Grok Build, Cursor, OpenCode, Codex, Gemini, Windsurf, Kiro
|
|
143
143
|
- **[Install from anywhere](https://microsoft.github.io/apm/guides/dependencies/)** — GitHub, GitLab, Bitbucket, Azure DevOps, GitHub Enterprise, Gitea, Gogs, any git host
|
|
144
144
|
- **[Transitive dependencies](https://microsoft.github.io/apm/guides/dependencies/)** — packages can depend on packages; APM resolves the full tree
|
|
145
145
|
- **[Author plugins](https://microsoft.github.io/apm/guides/plugins/)** — build Copilot, Claude, and Cursor plugins with dependency management, then export standard `plugin.json`
|
|
@@ -239,7 +239,8 @@ Use agentrc to author high-quality instructions, then package them with APM to s
|
|
|
239
239
|
|
|
240
240
|
Created by [@danielmeppiel](https://github.com/danielmeppiel). Maintained by [@danielmeppiel](https://github.com/danielmeppiel) and [@sergio-sisternes-epam](https://github.com/sergio-sisternes-epam).
|
|
241
241
|
|
|
242
|
-
- [Roadmap
|
|
242
|
+
- [v0.29 Roadmap](https://github.com/microsoft/apm/milestone/17)
|
|
243
|
+
- [Discussions](https://github.com/microsoft/apm/discussions)
|
|
243
244
|
- [Contributing](CONTRIBUTING.md)
|
|
244
245
|
- [AI Native Development guide](https://danielmeppiel.github.io/awesome-ai-native) — a practical learning path for AI-native development
|
|
245
246
|
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
Think `package.json`, `requirements.txt`, or `Cargo.toml` — but for AI agent configuration.
|
|
6
6
|
|
|
7
|
-
GitHub Copilot
|
|
7
|
+
GitHub Copilot | Claude Code | Grok Build | Cursor | OpenCode | Codex | Gemini | Windsurf | Kiro
|
|
8
8
|
|
|
9
|
-
**[Documentation](https://microsoft.github.io/apm/)** · **[Quick Start](https://microsoft.github.io/apm/getting-started/quick-start/)** · **[CLI Reference](https://microsoft.github.io/apm/reference/cli-commands/)** · **[Roadmap](https://github.com/
|
|
9
|
+
**[Documentation](https://microsoft.github.io/apm/)** · **[Quick Start](https://microsoft.github.io/apm/getting-started/quick-start/)** · **[CLI Reference](https://microsoft.github.io/apm/reference/cli-commands/)** · **[v0.29 Roadmap](https://github.com/microsoft/apm/milestone/17)**
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
@@ -67,7 +67,7 @@ One command, no configuration -- VS Code and GitHub Copilot read the file automa
|
|
|
67
67
|
|
|
68
68
|
One `apm.yml` describes every primitive your agents need — instructions, skills, prompts, agents, hooks, plugins, MCP servers — and `apm install` reproduces the exact same setup across every client on every machine. `apm.lock.yaml` pins the resolved tree the way `package-lock.json` does for npm.
|
|
69
69
|
|
|
70
|
-
- **[One manifest for everything](https://microsoft.github.io/apm/reference/primitive-types/)**
|
|
70
|
+
- **[One manifest for everything](https://microsoft.github.io/apm/reference/primitive-types/)** -- declared once, deployed across Copilot, Claude, Grok Build, Cursor, OpenCode, Codex, Gemini, Windsurf, Kiro
|
|
71
71
|
- **[Install from anywhere](https://microsoft.github.io/apm/guides/dependencies/)** — GitHub, GitLab, Bitbucket, Azure DevOps, GitHub Enterprise, Gitea, Gogs, any git host
|
|
72
72
|
- **[Transitive dependencies](https://microsoft.github.io/apm/guides/dependencies/)** — packages can depend on packages; APM resolves the full tree
|
|
73
73
|
- **[Author plugins](https://microsoft.github.io/apm/guides/plugins/)** — build Copilot, Claude, and Cursor plugins with dependency management, then export standard `plugin.json`
|
|
@@ -167,7 +167,8 @@ Use agentrc to author high-quality instructions, then package them with APM to s
|
|
|
167
167
|
|
|
168
168
|
Created by [@danielmeppiel](https://github.com/danielmeppiel). Maintained by [@danielmeppiel](https://github.com/danielmeppiel) and [@sergio-sisternes-epam](https://github.com/sergio-sisternes-epam).
|
|
169
169
|
|
|
170
|
-
- [Roadmap
|
|
170
|
+
- [v0.29 Roadmap](https://github.com/microsoft/apm/milestone/17)
|
|
171
|
+
- [Discussions](https://github.com/microsoft/apm/discussions)
|
|
171
172
|
- [Contributing](CONTRIBUTING.md)
|
|
172
173
|
- [AI Native Development guide](https://danielmeppiel.github.io/awesome-ai-native) — a practical learning path for AI-native development
|
|
173
174
|
|
|
@@ -7,7 +7,7 @@ from dataclasses import dataclass
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from typing import Any, ClassVar
|
|
9
9
|
|
|
10
|
-
from ...models.dependency.mcp import _RESERVED_EXTRA_KEYS
|
|
10
|
+
from ...models.dependency.mcp import _RESERVED_EXTRA_KEYS, TrustedEnvLiteral
|
|
11
11
|
from ...utils.console import _rich_error, _rich_warning
|
|
12
12
|
|
|
13
13
|
_INPUT_VAR_RE = re.compile(r"\$\{input:([^}]+)\}")
|
|
@@ -29,6 +29,7 @@ _ENV_PLACEHOLDER_RE = re.compile(r"<([A-Z_][A-Z0-9_]*)>|" + _ENV_VAR_RE.pattern)
|
|
|
29
29
|
# Detects the legacy ``<VAR>`` placeholder syntax only. Used to aggregate
|
|
30
30
|
# deprecation warnings across all servers in a single install run.
|
|
31
31
|
_LEGACY_ANGLE_VAR_RE = re.compile(r"<([A-Z_][A-Z0-9_]*)>")
|
|
32
|
+
_RUNTIME_TEMPLATE_VARIABLE_RE = re.compile(r"(?<!\$)\{([a-zA-Z_][a-zA-Z0-9_]*)\}")
|
|
32
33
|
|
|
33
34
|
# MCP Registry v0.1 names the container registry type ``oci``; the adapters
|
|
34
35
|
# below key their launcher dispatch on ``docker`` (the vocabulary the legacy
|
|
@@ -656,6 +657,94 @@ class MCPClientAdapter(ABC):
|
|
|
656
657
|
None,
|
|
657
658
|
)
|
|
658
659
|
|
|
660
|
+
@staticmethod
|
|
661
|
+
def _package_runtime_variable_metadata(
|
|
662
|
+
package: dict[str, Any] | None,
|
|
663
|
+
) -> dict[str, dict] | None:
|
|
664
|
+
"""Return one validated runtime-variable declaration map for a package.
|
|
665
|
+
|
|
666
|
+
Registry metadata may declare a variable on one argument and reference it
|
|
667
|
+
later without repeating the declaration. Keeping this map package-scoped
|
|
668
|
+
makes those references resolve consistently while rejecting malformed
|
|
669
|
+
secret metadata before an adapter can render a collected value.
|
|
670
|
+
"""
|
|
671
|
+
metadata_by_name: dict[str, dict] = {}
|
|
672
|
+
for field_name in ("runtime_arguments", "package_arguments"):
|
|
673
|
+
for argument in (package or {}).get(field_name) or []:
|
|
674
|
+
if not isinstance(argument, dict):
|
|
675
|
+
continue
|
|
676
|
+
variables = argument.get("variables")
|
|
677
|
+
if variables is None:
|
|
678
|
+
continue
|
|
679
|
+
if not isinstance(variables, dict):
|
|
680
|
+
return None
|
|
681
|
+
for name, metadata in variables.items():
|
|
682
|
+
if not isinstance(name, str) or not isinstance(metadata, dict):
|
|
683
|
+
return None
|
|
684
|
+
secret_marker = metadata.get("isSecret", metadata.get("is_secret", False))
|
|
685
|
+
if not isinstance(secret_marker, bool):
|
|
686
|
+
return None
|
|
687
|
+
existing = metadata_by_name.get(name)
|
|
688
|
+
if existing is not None and existing != metadata:
|
|
689
|
+
return None
|
|
690
|
+
metadata_by_name[name] = metadata
|
|
691
|
+
return metadata_by_name
|
|
692
|
+
|
|
693
|
+
@staticmethod
|
|
694
|
+
def _substitute_runtime_variables(
|
|
695
|
+
template: str,
|
|
696
|
+
variables: dict[object, object] | None,
|
|
697
|
+
runtime_vars: dict[str, object] | None,
|
|
698
|
+
runtime_variable_fallbacks: dict[str, str] | None = None,
|
|
699
|
+
secret_variable_fallbacks: dict[str, str] | None = None,
|
|
700
|
+
) -> str | None:
|
|
701
|
+
"""Resolve every APM runtime variable in one registry argument template.
|
|
702
|
+
|
|
703
|
+
Variable metadata may appear on an earlier argument while later
|
|
704
|
+
arguments reference the same value. Collected values therefore apply to
|
|
705
|
+
every template, not only the metadata-bearing entry. Target-specific
|
|
706
|
+
fallbacks are used only for declared variables with no collected value.
|
|
707
|
+
"""
|
|
708
|
+
secret_fallbacks = secret_variable_fallbacks or {}
|
|
709
|
+
values: dict[str, str] = dict(secret_fallbacks)
|
|
710
|
+
for name, value in (runtime_vars or {}).items():
|
|
711
|
+
if (
|
|
712
|
+
isinstance(name, str)
|
|
713
|
+
and name not in secret_fallbacks
|
|
714
|
+
and value is not None
|
|
715
|
+
and str(value) != ""
|
|
716
|
+
):
|
|
717
|
+
values[name] = str(value)
|
|
718
|
+
|
|
719
|
+
fallbacks = runtime_variable_fallbacks or {}
|
|
720
|
+
for name, metadata in (variables or {}).items():
|
|
721
|
+
if not isinstance(name, str) or not isinstance(metadata, dict):
|
|
722
|
+
return None
|
|
723
|
+
placeholder = f"{{{name}}}"
|
|
724
|
+
if placeholder not in template or name in values:
|
|
725
|
+
continue
|
|
726
|
+
secret_marker = metadata.get("isSecret", metadata.get("is_secret", False))
|
|
727
|
+
if not isinstance(secret_marker, bool):
|
|
728
|
+
return None
|
|
729
|
+
if secret_marker is True:
|
|
730
|
+
return None
|
|
731
|
+
fallback = fallbacks.get(name)
|
|
732
|
+
if fallback is not None:
|
|
733
|
+
values[name] = fallback
|
|
734
|
+
continue
|
|
735
|
+
configured = metadata.get("value", metadata.get("default"))
|
|
736
|
+
if isinstance(configured, str) and configured:
|
|
737
|
+
values[name] = configured
|
|
738
|
+
elif configured is not None:
|
|
739
|
+
return None
|
|
740
|
+
|
|
741
|
+
for name, value in values.items():
|
|
742
|
+
template = template.replace(f"{{{name}}}", value)
|
|
743
|
+
|
|
744
|
+
if _RUNTIME_TEMPLATE_VARIABLE_RE.search(template):
|
|
745
|
+
return None
|
|
746
|
+
return template
|
|
747
|
+
|
|
659
748
|
@staticmethod
|
|
660
749
|
def _processed_non_container_argument_groups(
|
|
661
750
|
arguments: list[object],
|
|
@@ -998,7 +1087,9 @@ class MCPClientAdapter(ABC):
|
|
|
998
1087
|
if not isinstance(raw_value, str):
|
|
999
1088
|
translated[name] = raw_value
|
|
1000
1089
|
continue
|
|
1001
|
-
if
|
|
1090
|
+
if isinstance(raw_value, TrustedEnvLiteral):
|
|
1091
|
+
translated[name] = raw_value
|
|
1092
|
+
elif _has_env_placeholder(raw_value):
|
|
1002
1093
|
self._last_legacy_angle_vars.update(_extract_legacy_angle_vars(raw_value))
|
|
1003
1094
|
translated[name] = self._translate_env_placeholder_for_runtime(raw_value)
|
|
1004
1095
|
placeholder_keys.extend(
|
|
@@ -12,6 +12,7 @@ from ...registry.client import SimpleRegistryClient
|
|
|
12
12
|
from ...registry.integration import RegistryIntegration
|
|
13
13
|
from ...utils.atomic_io import atomic_write_text
|
|
14
14
|
from ...utils.console import _rich_success, _rich_warning
|
|
15
|
+
from ...utils.net import is_loopback_host
|
|
15
16
|
from ...utils.path_security import PathTraversalError
|
|
16
17
|
from ._mcp_runtime_args import process_v01_value_hint_arg
|
|
17
18
|
from .base import MCPClientAdapter
|
|
@@ -216,6 +217,8 @@ class CodexClientAdapter(MCPClientAdapter):
|
|
|
216
217
|
raw = server_info.get("_raw_stdio")
|
|
217
218
|
if raw:
|
|
218
219
|
config["command"] = raw["command"]
|
|
220
|
+
if raw.get("cwd") is not None:
|
|
221
|
+
config["cwd"] = raw["cwd"]
|
|
219
222
|
resolved_env_for_args: dict = {}
|
|
220
223
|
if raw.get("env"):
|
|
221
224
|
resolved_env_for_args = self._resolve_environment_variables(
|
|
@@ -239,7 +242,8 @@ class CodexClientAdapter(MCPClientAdapter):
|
|
|
239
242
|
# Precedence on Codex when a server publishes BOTH a remote and a stdio
|
|
240
243
|
# package: prefer the stdio package (falls through to the packages branch
|
|
241
244
|
# below). The remote-only branch here handles the streamable-http path
|
|
242
|
-
# and rejects SSE / non-https / empty-url remotes
|
|
245
|
+
# and rejects SSE / non-https (except loopback http) / empty-url remotes
|
|
246
|
+
# with explicit warnings.
|
|
243
247
|
remotes = server_info.get("remotes", [])
|
|
244
248
|
packages = server_info.get("packages", [])
|
|
245
249
|
if remotes and not packages:
|
|
@@ -263,11 +267,22 @@ class CodexClientAdapter(MCPClientAdapter):
|
|
|
263
267
|
)
|
|
264
268
|
return None
|
|
265
269
|
|
|
266
|
-
|
|
267
|
-
|
|
270
|
+
try:
|
|
271
|
+
parsed_remote = urlparse(remote_url)
|
|
272
|
+
scheme = parsed_remote.scheme.lower()
|
|
273
|
+
insecure_loopback = scheme == "http" and is_loopback_host(parsed_remote.hostname)
|
|
274
|
+
except ValueError:
|
|
275
|
+
scheme = ""
|
|
276
|
+
insecure_loopback = False
|
|
277
|
+
# Codex CLI itself accepts plain-http loopback URLs (its docs use
|
|
278
|
+
# http://localhost examples), and local dev servers rarely carry
|
|
279
|
+
# certs -- so loopback http is allowed. Any other non-https host is
|
|
280
|
+
# still rejected to avoid cleartext bearer tokens in transit.
|
|
281
|
+
if scheme != "https" and not insecure_loopback:
|
|
268
282
|
_rich_warning(
|
|
269
283
|
f"Skipping MCP server '{server_name}' for Codex CLI: remote URL "
|
|
270
|
-
f"must use https:// (got {scheme or 'no scheme'})."
|
|
284
|
+
f"must use https:// (got {scheme or 'no scheme'}). "
|
|
285
|
+
"Plain http is allowed for loopback addresses only.",
|
|
271
286
|
symbol="warning",
|
|
272
287
|
)
|
|
273
288
|
return None
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""GitHub Copilot CLI implementation of MCP client adapter.
|
|
2
2
|
|
|
3
|
-
This adapter implements the Copilot
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
This adapter implements the Copilot-specific handling of MCP server configuration.
|
|
4
|
+
At project scope it targets .github/mcp.json (read by Copilot CLI); at user scope
|
|
5
|
+
it targets the global ~/.copilot/mcp-config.json file.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import json
|
|
@@ -13,6 +13,7 @@ from typing import ClassVar
|
|
|
13
13
|
import click
|
|
14
14
|
|
|
15
15
|
from ...core.token_manager import GitHubTokenManager
|
|
16
|
+
from ...models.dependency.mcp import TrustedEnvLiteral
|
|
16
17
|
from ...registry.client import SimpleRegistryClient
|
|
17
18
|
from ...registry.integration import RegistryIntegration
|
|
18
19
|
from ...utils.console import _rich_warning
|
|
@@ -103,13 +104,23 @@ class CopilotClientAdapter(MCPClientAdapter):
|
|
|
103
104
|
self.registry_integration = RegistryIntegration(registry_url)
|
|
104
105
|
|
|
105
106
|
def get_config_path(self):
|
|
106
|
-
"""Get the path to the Copilot
|
|
107
|
+
"""Get the path to the Copilot MCP configuration file.
|
|
108
|
+
|
|
109
|
+
At user scope returns the global Copilot CLI config so MCP servers are
|
|
110
|
+
available across all projects. At project scope returns the per-repo
|
|
111
|
+
.github/mcp.json path that Copilot CLI reads since deprecating
|
|
112
|
+
.vscode/mcp.json.
|
|
107
113
|
|
|
108
114
|
Returns:
|
|
109
|
-
str: Path to
|
|
115
|
+
str: Path to the MCP configuration file.
|
|
110
116
|
"""
|
|
111
|
-
|
|
112
|
-
|
|
117
|
+
if self.user_scope:
|
|
118
|
+
configured_home = os.environ.get("COPILOT_HOME", "").strip()
|
|
119
|
+
copilot_home = (
|
|
120
|
+
Path(configured_home).expanduser() if configured_home else Path.home() / ".copilot"
|
|
121
|
+
)
|
|
122
|
+
return str(copilot_home / "mcp-config.json")
|
|
123
|
+
return str(self.project_root / ".github" / "mcp.json")
|
|
113
124
|
|
|
114
125
|
def update_config(self, config_updates):
|
|
115
126
|
"""Update the Copilot CLI MCP configuration.
|
|
@@ -423,6 +434,8 @@ class CopilotClientAdapter(MCPClientAdapter):
|
|
|
423
434
|
raw = server_info.get("_raw_stdio")
|
|
424
435
|
if raw:
|
|
425
436
|
config["command"] = raw["command"]
|
|
437
|
+
if raw.get("cwd") is not None:
|
|
438
|
+
config["cwd"] = raw["cwd"]
|
|
426
439
|
resolved_env_for_args = {}
|
|
427
440
|
if raw.get("env"):
|
|
428
441
|
resolved_env_for_args = self._resolve_environment_variables(
|
|
@@ -723,7 +736,9 @@ class CopilotClientAdapter(MCPClientAdapter):
|
|
|
723
736
|
if not isinstance(raw_value, str):
|
|
724
737
|
translated[name] = _stringify_env_literal(raw_value)
|
|
725
738
|
continue
|
|
726
|
-
if
|
|
739
|
+
if isinstance(raw_value, TrustedEnvLiteral):
|
|
740
|
+
translated[name] = raw_value
|
|
741
|
+
elif _has_env_placeholder(raw_value):
|
|
727
742
|
self._last_legacy_angle_vars.update(_extract_legacy_angle_vars(raw_value))
|
|
728
743
|
translated[name] = self._translate_env_placeholder_for_runtime(raw_value)
|
|
729
744
|
for match in _ENV_VAR_RE.finditer(translated[name]):
|
|
@@ -134,6 +134,8 @@ class CursorClientAdapter(CopilotClientAdapter):
|
|
|
134
134
|
if raw:
|
|
135
135
|
config["type"] = "stdio"
|
|
136
136
|
config["command"] = raw["command"]
|
|
137
|
+
if raw.get("cwd") is not None:
|
|
138
|
+
config["cwd"] = raw["cwd"]
|
|
137
139
|
resolved_env_for_args: dict = {}
|
|
138
140
|
if raw.get("env"):
|
|
139
141
|
resolved_env_for_args = self._resolve_environment_variables(
|
|
@@ -148,6 +148,8 @@ class GeminiClientAdapter(CopilotClientAdapter):
|
|
|
148
148
|
raw = server_info.get("_raw_stdio")
|
|
149
149
|
if raw:
|
|
150
150
|
config["command"] = raw["command"]
|
|
151
|
+
if raw.get("cwd") is not None:
|
|
152
|
+
config["cwd"] = raw["cwd"]
|
|
151
153
|
resolved_env_for_args: dict = {}
|
|
152
154
|
if raw.get("env"):
|
|
153
155
|
resolved_env_for_args = self._resolve_environment_variables(
|
|
@@ -116,6 +116,8 @@ class KiroClientAdapter(CopilotClientAdapter):
|
|
|
116
116
|
raw = server_info.get("_raw_stdio")
|
|
117
117
|
if raw:
|
|
118
118
|
config: dict[str, Any] = {"command": raw["command"]}
|
|
119
|
+
if raw.get("cwd") is not None:
|
|
120
|
+
config["cwd"] = raw["cwd"]
|
|
119
121
|
resolved_env_for_args: dict[str, Any] = {}
|
|
120
122
|
if raw.get("env"):
|
|
121
123
|
resolved_env_for_args = self._resolve_environment_variables(
|
|
@@ -5,6 +5,7 @@ following the official documentation at:
|
|
|
5
5
|
https://code.visualstudio.com/docs/copilot/chat/mcp-servers
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
import hashlib
|
|
8
9
|
import json
|
|
9
10
|
import re
|
|
10
11
|
from pathlib import Path
|
|
@@ -13,7 +14,13 @@ from ...core.docker_args import DockerArgsProcessor
|
|
|
13
14
|
from ...registry.client import SimpleRegistryClient
|
|
14
15
|
from ...registry.integration import RegistryIntegration
|
|
15
16
|
from ...utils.console import _rich_warning
|
|
16
|
-
from .base import
|
|
17
|
+
from .base import (
|
|
18
|
+
_ENV_VAR_RE,
|
|
19
|
+
_INPUT_VAR_RE,
|
|
20
|
+
_RUNTIME_TEMPLATE_VARIABLE_RE,
|
|
21
|
+
MCPClientAdapter,
|
|
22
|
+
registry_field_is_required,
|
|
23
|
+
)
|
|
17
24
|
|
|
18
25
|
# Legacy ``<VAR>`` placeholder (Copilot CLI / Codex only). VS Code does not
|
|
19
26
|
# resolve angle-bracket placeholders, so emitting them produces literal
|
|
@@ -270,6 +277,8 @@ class VSCodeClientAdapter(MCPClientAdapter):
|
|
|
270
277
|
"command": raw["command"],
|
|
271
278
|
"args": raw["args"],
|
|
272
279
|
}
|
|
280
|
+
if raw.get("cwd") is not None:
|
|
281
|
+
server_config["cwd"] = raw["cwd"]
|
|
273
282
|
if raw.get("env"):
|
|
274
283
|
# Translate bare ${VAR} -> ${env:VAR} so VS Code's runtime env
|
|
275
284
|
# interpolation resolves them at server-start. ${input:...}
|
|
@@ -298,7 +307,8 @@ class VSCodeClientAdapter(MCPClientAdapter):
|
|
|
298
307
|
existing_server_config=existing_server_config,
|
|
299
308
|
)
|
|
300
309
|
secret_fallbacks, argument_inputs = self._declared_vscode_argument_secret_inputs(
|
|
301
|
-
package
|
|
310
|
+
package,
|
|
311
|
+
server_name=server_info.get("name", ""),
|
|
302
312
|
)
|
|
303
313
|
seen_input_ids = {item.get("id") for item in input_vars}
|
|
304
314
|
for input_definition in (*declared_inputs, *argument_inputs):
|
|
@@ -342,19 +352,29 @@ class VSCodeClientAdapter(MCPClientAdapter):
|
|
|
342
352
|
|
|
343
353
|
# Handle docker packages
|
|
344
354
|
elif is_docker:
|
|
345
|
-
|
|
355
|
+
docker_kwargs = (
|
|
356
|
+
{"secret_variable_fallbacks": secret_fallbacks} if secret_fallbacks else {}
|
|
357
|
+
)
|
|
358
|
+
unresolved_variables: list[str] = []
|
|
359
|
+
args = self._docker_run_args(
|
|
360
|
+
package,
|
|
361
|
+
runtime_vars,
|
|
362
|
+
unresolved_variables=unresolved_variables,
|
|
363
|
+
**docker_kwargs,
|
|
364
|
+
)
|
|
346
365
|
if args is None:
|
|
347
366
|
if package.get("runtime_arguments") or package.get("package_arguments"):
|
|
367
|
+
variable_name = (
|
|
368
|
+
unresolved_variables[0] if unresolved_variables else "unknown"
|
|
369
|
+
)
|
|
348
370
|
_rich_warning(
|
|
349
|
-
"Could not resolve container run
|
|
350
|
-
f"'{package.get('name', '')}';
|
|
351
|
-
"
|
|
352
|
-
"'apm install'."
|
|
371
|
+
"Could not resolve required container run option "
|
|
372
|
+
f"'{variable_name}' for '{package.get('name', '')}'; "
|
|
373
|
+
"target configuration was not changed. Set the required "
|
|
374
|
+
"registry runtime variables and rerun 'apm install'."
|
|
353
375
|
)
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
package.get("name"),
|
|
357
|
-
)
|
|
376
|
+
return {}, []
|
|
377
|
+
args = self._ensure_docker_image_arg(["run", "-i", "--rm"], package.get("name"))
|
|
358
378
|
|
|
359
379
|
server_config = {"type": "stdio", "command": "docker", "args": args}
|
|
360
380
|
|
|
@@ -547,50 +567,50 @@ class VSCodeClientAdapter(MCPClientAdapter):
|
|
|
547
567
|
return env_config, input_vars
|
|
548
568
|
|
|
549
569
|
@staticmethod
|
|
550
|
-
def
|
|
570
|
+
def _vscode_argument_secret_input_id(server_name: str, variable_name: str) -> str:
|
|
571
|
+
"""Return a collision-safe VS Code input ID for one server variable."""
|
|
572
|
+
server_digest = hashlib.sha256(server_name.encode("utf-8")).hexdigest()[:12]
|
|
573
|
+
return f"mcp-{server_digest}-{variable_name.encode('utf-8').hex()}"
|
|
574
|
+
|
|
575
|
+
@classmethod
|
|
576
|
+
def _declared_vscode_argument_secret_inputs(cls, package, *, server_name: str):
|
|
551
577
|
"""Return VS Code input indirections for secret argument variables."""
|
|
552
578
|
if not package:
|
|
553
579
|
return {}, []
|
|
580
|
+
package_variables = cls._package_runtime_variable_metadata(package)
|
|
581
|
+
if package_variables is None:
|
|
582
|
+
raise ValueError("MCP package argument variable metadata must be valid")
|
|
554
583
|
fallbacks = {}
|
|
555
584
|
input_vars = []
|
|
585
|
+
templates = []
|
|
556
586
|
for field_name in ("runtime_arguments", "package_arguments"):
|
|
557
587
|
for argument in package.get(field_name) or []:
|
|
558
588
|
if not isinstance(argument, dict):
|
|
559
589
|
continue
|
|
560
|
-
variables = argument.get("variables")
|
|
561
|
-
if not isinstance(variables, dict):
|
|
562
|
-
continue
|
|
563
590
|
template = argument.get(
|
|
564
591
|
"value",
|
|
565
592
|
argument.get("default", argument.get("value_hint", "")),
|
|
566
593
|
)
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
"description": variable_info.get(
|
|
588
|
-
"description",
|
|
589
|
-
f"{variable_name} for MCP server",
|
|
590
|
-
),
|
|
591
|
-
"password": True,
|
|
592
|
-
}
|
|
593
|
-
)
|
|
594
|
+
if isinstance(template, str):
|
|
595
|
+
templates.append(template)
|
|
596
|
+
for variable_name, variable_info in package_variables.items():
|
|
597
|
+
if not any(f"{{{variable_name}}}" in template for template in templates):
|
|
598
|
+
continue
|
|
599
|
+
if not variable_info.get("isSecret", variable_info.get("is_secret", False)):
|
|
600
|
+
continue
|
|
601
|
+
input_id = cls._vscode_argument_secret_input_id(server_name, variable_name)
|
|
602
|
+
fallbacks[variable_name] = f"${{input:{input_id}}}"
|
|
603
|
+
input_vars.append(
|
|
604
|
+
{
|
|
605
|
+
"type": "promptString",
|
|
606
|
+
"id": input_id,
|
|
607
|
+
"description": variable_info.get(
|
|
608
|
+
"description",
|
|
609
|
+
f"{variable_name} for MCP server",
|
|
610
|
+
),
|
|
611
|
+
"password": True,
|
|
612
|
+
}
|
|
613
|
+
)
|
|
594
614
|
return fallbacks, input_vars
|
|
595
615
|
|
|
596
616
|
@staticmethod
|
|
@@ -776,7 +796,14 @@ class VSCodeClientAdapter(MCPClientAdapter):
|
|
|
776
796
|
return extracted
|
|
777
797
|
|
|
778
798
|
@classmethod
|
|
779
|
-
def _docker_run_args(
|
|
799
|
+
def _docker_run_args(
|
|
800
|
+
cls,
|
|
801
|
+
package: dict,
|
|
802
|
+
runtime_vars: dict | None = None,
|
|
803
|
+
*,
|
|
804
|
+
secret_variable_fallbacks: dict[str, str] | None = None,
|
|
805
|
+
unresolved_variables: list[str] | None = None,
|
|
806
|
+
) -> list[str] | None:
|
|
780
807
|
"""Build ``docker run`` arguments from a container package's metadata.
|
|
781
808
|
|
|
782
809
|
Container packages retain a dedicated assembler because Docker requires
|
|
@@ -813,10 +840,27 @@ class VSCodeClientAdapter(MCPClientAdapter):
|
|
|
813
840
|
"""
|
|
814
841
|
if not package:
|
|
815
842
|
return None
|
|
816
|
-
|
|
843
|
+
package_variables = cls._package_runtime_variable_metadata(package)
|
|
844
|
+
if package_variables is None:
|
|
845
|
+
if unresolved_variables is not None:
|
|
846
|
+
unresolved_variables.append("invalid metadata")
|
|
847
|
+
return None
|
|
848
|
+
run_options = cls._docker_arg_values(
|
|
849
|
+
package.get("runtime_arguments"),
|
|
850
|
+
runtime_vars,
|
|
851
|
+
secret_variable_fallbacks,
|
|
852
|
+
package_variables,
|
|
853
|
+
unresolved_variables,
|
|
854
|
+
)
|
|
817
855
|
if run_options is None:
|
|
818
856
|
return None
|
|
819
|
-
package_args = cls._docker_arg_values(
|
|
857
|
+
package_args = cls._docker_arg_values(
|
|
858
|
+
package.get("package_arguments"),
|
|
859
|
+
runtime_vars,
|
|
860
|
+
secret_variable_fallbacks,
|
|
861
|
+
package_variables,
|
|
862
|
+
unresolved_variables,
|
|
863
|
+
)
|
|
820
864
|
if package_args is None:
|
|
821
865
|
return None
|
|
822
866
|
if not run_options and package_args and package_args[0] == "run":
|
|
@@ -855,7 +899,12 @@ class VSCodeClientAdapter(MCPClientAdapter):
|
|
|
855
899
|
|
|
856
900
|
@classmethod
|
|
857
901
|
def _docker_arg_values(
|
|
858
|
-
cls,
|
|
902
|
+
cls,
|
|
903
|
+
entries: list | None,
|
|
904
|
+
runtime_vars: dict | None,
|
|
905
|
+
secret_variable_fallbacks: dict[str, str] | None,
|
|
906
|
+
package_variables: dict[str, dict],
|
|
907
|
+
unresolved_variables: list[str] | None,
|
|
859
908
|
) -> list[str] | None:
|
|
860
909
|
"""Resolve one registry argument list into CLI argument strings.
|
|
861
910
|
|
|
@@ -903,47 +952,26 @@ class VSCodeClientAdapter(MCPClientAdapter):
|
|
|
903
952
|
continue
|
|
904
953
|
|
|
905
954
|
template = str(raw)
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
955
|
+
substituted = cls._substitute_runtime_variables(
|
|
956
|
+
template,
|
|
957
|
+
package_variables,
|
|
958
|
+
runtime_vars,
|
|
959
|
+
{"workspaceFolder": "${workspaceFolder}"},
|
|
960
|
+
secret_variable_fallbacks,
|
|
961
|
+
)
|
|
962
|
+
if substituted is None:
|
|
963
|
+
if required:
|
|
964
|
+
if unresolved_variables is not None:
|
|
965
|
+
match = _RUNTIME_TEMPLATE_VARIABLE_RE.search(template)
|
|
966
|
+
unresolved_variables.append(match.group(1) if match else "unknown")
|
|
967
|
+
return None
|
|
968
|
+
continue
|
|
969
|
+
template = substituted
|
|
914
970
|
if arg_type == "named" and arg.get("name"):
|
|
915
971
|
args.append(str(arg["name"]))
|
|
916
972
|
args.append(template)
|
|
917
973
|
return args
|
|
918
974
|
|
|
919
|
-
@staticmethod
|
|
920
|
-
def _substitute_runtime_variables(
|
|
921
|
-
template: str, variables: dict, runtime_vars: dict | None
|
|
922
|
-
) -> str | None:
|
|
923
|
-
"""Substitute ``{var}`` placeholders, or return None if unresolvable.
|
|
924
|
-
|
|
925
|
-
``workspaceFolder`` resolves to VS Code's own ``${workspaceFolder}``
|
|
926
|
-
token, which the editor expands at server start. Any other name that
|
|
927
|
-
this install did not collect a value for has no such fallback, so the
|
|
928
|
-
caller is told to decline rather than write a literal ``${name}`` into
|
|
929
|
-
a mount path.
|
|
930
|
-
"""
|
|
931
|
-
for var_name in variables:
|
|
932
|
-
placeholder = f"{{{var_name}}}"
|
|
933
|
-
# A descriptor the template never references cannot make it
|
|
934
|
-
# unresolvable; declining on one would drop a usable argument.
|
|
935
|
-
if placeholder not in template:
|
|
936
|
-
continue
|
|
937
|
-
supplied = (runtime_vars or {}).get(var_name)
|
|
938
|
-
if supplied is not None and str(supplied) != "":
|
|
939
|
-
replacement = str(supplied)
|
|
940
|
-
elif var_name == "workspaceFolder":
|
|
941
|
-
replacement = "${workspaceFolder}"
|
|
942
|
-
else:
|
|
943
|
-
return None
|
|
944
|
-
template = template.replace(placeholder, replacement)
|
|
945
|
-
return template
|
|
946
|
-
|
|
947
975
|
@staticmethod
|
|
948
976
|
def _select_remote_with_url(remotes):
|
|
949
977
|
"""Return the first remote entry that has a non-empty URL.
|