apm-cli 0.26.0__tar.gz → 0.27.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.
Files changed (460) hide show
  1. {apm_cli-0.26.0/src/apm_cli.egg-info → apm_cli-0.27.0}/PKG-INFO +1 -1
  2. {apm_cli-0.26.0 → apm_cli-0.27.0}/pyproject.toml +1 -1
  3. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/client/base.py +574 -6
  4. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/client/codex.py +24 -7
  5. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/client/copilot.py +54 -17
  6. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/client/gemini.py +5 -7
  7. apm_cli-0.27.0/src/apm_cli/adapters/client/intellij.py +281 -0
  8. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/client/vscode.py +411 -124
  9. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/cli.py +1 -1
  10. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/audit.py +45 -11
  11. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/install.py +103 -64
  12. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/lock.py +7 -6
  13. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/marketplace/check.py +7 -0
  14. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/outdated.py +5 -1
  15. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/policy.py +10 -4
  16. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/self_update.py +90 -40
  17. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/uninstall/cli.py +145 -40
  18. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/uninstall/engine.py +392 -66
  19. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/uninstall/lockfile_state.py +16 -2
  20. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/update.py +105 -17
  21. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/compilation/link_resolver.py +8 -11
  22. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/apm_yml.py +19 -16
  23. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/auth.py +448 -64
  24. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/deployment_ledger.py +45 -3
  25. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/host_providers.py +22 -3
  26. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/operations.py +8 -1
  27. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/safe_installer.py +3 -1
  28. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/scope.py +5 -0
  29. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/target_detection.py +178 -0
  30. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/apm_resolver.py +37 -9
  31. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/bare_cache.py +8 -0
  32. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/clone_engine.py +126 -30
  33. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/dependency_graph.py +9 -9
  34. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/download_strategies.py +268 -36
  35. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/git_auth_env.py +14 -8
  36. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/git_reference_resolver.py +142 -37
  37. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/github_downloader.py +134 -10
  38. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/github_downloader_validation.py +166 -30
  39. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/host_backends.py +6 -4
  40. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/lockfile.py +80 -17
  41. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/tiered_ref_resolver.py +101 -9
  42. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/drift.py +9 -0
  43. apm_cli-0.27.0/src/apm_cli/install/audit_replay.py +112 -0
  44. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/context.py +4 -0
  45. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/drift.py +251 -148
  46. apm_cli-0.27.0/src/apm_cli/install/drift_render.py +100 -0
  47. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/errors.py +4 -0
  48. apm_cli-0.27.0/src/apm_cli/install/helpers/no_work.py +34 -0
  49. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/helpers/ref_reuse.py +11 -3
  50. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/helpers/ref_seed.py +4 -1
  51. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/lsp/integration.py +36 -4
  52. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/manifest_reconcile.py +74 -2
  53. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/mcp/command.py +75 -7
  54. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/mcp/integration.py +78 -16
  55. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/mcp/ownership.py +22 -2
  56. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/outcome.py +1 -0
  57. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/phases/cleanup.py +4 -0
  58. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/phases/lockfile.py +37 -5
  59. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/phases/post_deps_local.py +3 -0
  60. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/phases/resolve.py +139 -43
  61. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/phases/targets.py +27 -36
  62. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/pipeline.py +62 -65
  63. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/request.py +4 -1
  64. apm_cli-0.27.0/src/apm_cli/install/resolution_staging.py +126 -0
  65. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/service.py +64 -5
  66. apm_cli-0.27.0/src/apm_cli/install/service_integration.py +126 -0
  67. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/services.py +62 -21
  68. apm_cli-0.27.0/src/apm_cli/install/target_filter.py +131 -0
  69. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/validation.py +55 -17
  70. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/base_integrator.py +8 -4
  71. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/cleanup.py +9 -1
  72. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/hook_bundle.py +23 -1
  73. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/hook_integrator.py +238 -252
  74. apm_cli-0.27.0/src/apm_cli/integration/hook_ownership.py +296 -0
  75. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/lsp_integrator.py +69 -10
  76. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/mcp_config_view.py +88 -7
  77. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/mcp_integrator.py +140 -47
  78. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/mcp_integrator_install.py +365 -89
  79. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/targets.py +25 -2
  80. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/auth_helpers.py +1 -1
  81. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/builder.py +30 -2
  82. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/client.py +45 -12
  83. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/models.py +29 -0
  84. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/output_mappers.py +12 -0
  85. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/ref_resolver.py +51 -23
  86. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/resolver.py +57 -37
  87. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/tag_pattern.py +33 -0
  88. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/version_resolver.py +15 -4
  89. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/yml_schema.py +7 -6
  90. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/models/apm_package.py +12 -15
  91. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/models/dependency/identity.py +29 -9
  92. apm_cli-0.27.0/src/apm_cli/models/dependency/materialization.py +351 -0
  93. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/models/dependency/reference.py +62 -117
  94. apm_cli-0.27.0/src/apm_cli/models/dependency/selection.py +105 -0
  95. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/models/results.py +7 -0
  96. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/policy/ci_checks.py +91 -46
  97. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/policy/discovery.py +181 -40
  98. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/registry/operations.py +46 -19
  99. apm_cli-0.27.0/src/apm_cli/security/file_scanner.py +238 -0
  100. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/security/gate.py +22 -6
  101. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/atomic_io.py +8 -1
  102. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/github_host.py +220 -9
  103. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/paths.py +16 -0
  104. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/version_checker.py +1 -4
  105. {apm_cli-0.26.0 → apm_cli-0.27.0/src/apm_cli.egg-info}/PKG-INFO +1 -1
  106. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli.egg-info/SOURCES.txt +7 -0
  107. {apm_cli-0.26.0 → apm_cli-0.27.0}/tests/test_apm_package_models.py +6 -5
  108. {apm_cli-0.26.0 → apm_cli-0.27.0}/tests/test_codex_docker_args_fix.py +13 -7
  109. {apm_cli-0.26.0 → apm_cli-0.27.0}/tests/test_lockfile.py +5 -0
  110. apm_cli-0.26.0/src/apm_cli/adapters/client/intellij.py +0 -104
  111. apm_cli-0.26.0/src/apm_cli/install/resolution_staging.py +0 -59
  112. apm_cli-0.26.0/src/apm_cli/install/target_filter.py +0 -33
  113. apm_cli-0.26.0/src/apm_cli/security/file_scanner.py +0 -89
  114. {apm_cli-0.26.0 → apm_cli-0.27.0}/AUTHORS +0 -0
  115. {apm_cli-0.26.0 → apm_cli-0.27.0}/LICENSE +0 -0
  116. {apm_cli-0.26.0 → apm_cli-0.27.0}/NOTICE +0 -0
  117. {apm_cli-0.26.0 → apm_cli-0.27.0}/README.md +0 -0
  118. {apm_cli-0.26.0 → apm_cli-0.27.0}/setup.cfg +0 -0
  119. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/__init__.py +0 -0
  120. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/__init__.py +0 -0
  121. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/client/__init__.py +0 -0
  122. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/client/_mcp_runtime_args.py +0 -0
  123. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/client/antigravity.py +0 -0
  124. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/client/claude.py +0 -0
  125. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/client/cursor.py +0 -0
  126. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/client/hermes.py +0 -0
  127. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/client/kiro.py +0 -0
  128. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/client/opencode.py +0 -0
  129. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/client/windsurf.py +0 -0
  130. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/package_manager/__init__.py +0 -0
  131. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/package_manager/base.py +0 -0
  132. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/adapters/package_manager/default_manager.py +0 -0
  133. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/bootstrap_mirror.py +0 -0
  134. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/bundle/__init__.py +0 -0
  135. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/bundle/attest.py +0 -0
  136. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/bundle/local_bundle.py +0 -0
  137. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/bundle/lockfile_enrichment.py +0 -0
  138. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/bundle/packer.py +0 -0
  139. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/bundle/plugin_exporter.py +0 -0
  140. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/bundle/plugin_layout.py +0 -0
  141. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/bundle/unpacker.py +0 -0
  142. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/cache/__init__.py +0 -0
  143. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/cache/git_cache.py +0 -0
  144. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/cache/http_cache.py +0 -0
  145. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/cache/integrity.py +0 -0
  146. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/cache/locking.py +0 -0
  147. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/cache/paths.py +0 -0
  148. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/cache/url_normalize.py +0 -0
  149. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/__init__.py +0 -0
  150. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/_apm_yml_writer.py +0 -0
  151. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/_helpers.py +0 -0
  152. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/approve.py +0 -0
  153. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/cache.py +0 -0
  154. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/compile/__init__.py +0 -0
  155. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/compile/cli.py +0 -0
  156. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/compile/watcher.py +0 -0
  157. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/config.py +0 -0
  158. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/deps/__init__.py +0 -0
  159. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/deps/_utils.py +0 -0
  160. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/deps/cli.py +0 -0
  161. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/deps/why.py +0 -0
  162. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/doctor.py +0 -0
  163. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/experimental.py +0 -0
  164. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/find.py +0 -0
  165. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/init.py +0 -0
  166. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/lifecycle.py +0 -0
  167. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/list_cmd.py +0 -0
  168. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/marketplace/__init__.py +0 -0
  169. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/marketplace/audit.py +0 -0
  170. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/marketplace/doctor.py +0 -0
  171. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/marketplace/init.py +0 -0
  172. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/marketplace/migrate.py +0 -0
  173. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/marketplace/outdated.py +0 -0
  174. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/marketplace/plugin/__init__.py +0 -0
  175. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/marketplace/plugin/add.py +0 -0
  176. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/marketplace/plugin/remove.py +0 -0
  177. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/marketplace/plugin/set.py +0 -0
  178. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/marketplace/validate.py +0 -0
  179. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/mcp.py +0 -0
  180. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/pack.py +0 -0
  181. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/plugin/__init__.py +0 -0
  182. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/plugin/init.py +0 -0
  183. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/prune.py +0 -0
  184. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/publish.py +0 -0
  185. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/run.py +0 -0
  186. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/runtime.py +0 -0
  187. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/targets.py +0 -0
  188. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/uninstall/__init__.py +0 -0
  189. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/commands/view.py +0 -0
  190. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/compilation/__init__.py +0 -0
  191. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/compilation/agents_compiler.py +0 -0
  192. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/compilation/build_id.py +0 -0
  193. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/compilation/claude_formatter.py +0 -0
  194. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/compilation/constants.py +0 -0
  195. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/compilation/constitution.py +0 -0
  196. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/compilation/constitution_block.py +0 -0
  197. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/compilation/context_optimizer.py +0 -0
  198. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/compilation/distributed_compiler.py +0 -0
  199. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/compilation/gemini_formatter.py +0 -0
  200. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/compilation/injector.py +0 -0
  201. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/compilation/managed_section.py +0 -0
  202. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/compilation/output_writer.py +0 -0
  203. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/compilation/template_builder.py +0 -0
  204. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/compilation/user_root_context.py +0 -0
  205. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/config.py +0 -0
  206. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/constants.py +0 -0
  207. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/__init__.py +0 -0
  208. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/_child_tls/__init__.py +0 -0
  209. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/_child_tls/_apm_tls.pth +0 -0
  210. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/_child_tls/_apm_tls_bootstrap.py +0 -0
  211. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/azure_cli.py +0 -0
  212. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/build_orchestrator.py +0 -0
  213. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/command_logger.py +0 -0
  214. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/conflict_detector.py +0 -0
  215. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/deployment_state.py +0 -0
  216. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/docker_args.py +0 -0
  217. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/errors.py +0 -0
  218. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/experimental.py +0 -0
  219. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/install_audit.py +0 -0
  220. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/lifecycle_scripts.py +0 -0
  221. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/null_logger.py +0 -0
  222. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/output_mode.py +0 -0
  223. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/plugin_manifest.py +0 -0
  224. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/script_executors.py +0 -0
  225. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/script_runner.py +0 -0
  226. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/script_trust.py +0 -0
  227. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/target_catalog.py +0 -0
  228. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/tls_trust.py +0 -0
  229. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/core/token_manager.py +0 -0
  230. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/__init__.py +0 -0
  231. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/_shared.py +0 -0
  232. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/aggregator.py +0 -0
  233. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/artifactory_entry.py +0 -0
  234. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/artifactory_orchestrator.py +0 -0
  235. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/git_file_transport.py +0 -0
  236. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/git_remote_ops.py +0 -0
  237. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/git_semver_resolver.py +0 -0
  238. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/github_rate_limit.py +0 -0
  239. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/installed_package.py +0 -0
  240. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/outdated_ref_cache.py +0 -0
  241. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/outdated_row.py +0 -0
  242. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/package_validator.py +0 -0
  243. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/path_anchoring.py +0 -0
  244. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/plugin_parser.py +0 -0
  245. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/reachability.py +0 -0
  246. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/registry/__init__.py +0 -0
  247. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/registry/auth.py +0 -0
  248. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/registry/client.py +0 -0
  249. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/registry/config_loader.py +0 -0
  250. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/registry/extractor.py +0 -0
  251. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/registry/feature_gate.py +0 -0
  252. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/registry/outdated.py +0 -0
  253. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/registry/resolver.py +0 -0
  254. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/registry/semver.py +0 -0
  255. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/registry_proxy.py +0 -0
  256. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/revision_pins.py +0 -0
  257. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/shared_clone_cache.py +0 -0
  258. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/transport_selection.py +0 -0
  259. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/verifier.py +0 -0
  260. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/deps/why_walker.py +0 -0
  261. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/export/__init__.py +0 -0
  262. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/export/authoring.py +0 -0
  263. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/export/declared_license.py +0 -0
  264. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/export/formats.py +0 -0
  265. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/export/purl.py +0 -0
  266. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/export/sbom.py +0 -0
  267. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/export/spdx.py +0 -0
  268. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/export/spdx_data.py +0 -0
  269. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/factory.py +0 -0
  270. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/__init__.py +0 -0
  271. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/artifactory_resolver.py +0 -0
  272. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/cache_pin.py +0 -0
  273. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/deployed_paths.py +0 -0
  274. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/exec_gate.py +0 -0
  275. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/gitlab_resolver.py +0 -0
  276. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/heals/__init__.py +0 -0
  277. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/heals/base.py +0 -0
  278. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/heals/branch_ref_drift.py +0 -0
  279. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/heals/buggy_lockfile_recovery.py +0 -0
  280. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/helpers/__init__.py +0 -0
  281. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/helpers/security_scan.py +0 -0
  282. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/insecure_policy.py +0 -0
  283. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/integrity.py +0 -0
  284. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/local_bundle_handler.py +0 -0
  285. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/lsp/__init__.py +0 -0
  286. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/mcp/__init__.py +0 -0
  287. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/mcp/args.py +0 -0
  288. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/mcp/conflicts.py +0 -0
  289. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/mcp/entry.py +0 -0
  290. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/mcp/registry.py +0 -0
  291. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/mcp/warnings.py +0 -0
  292. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/mcp/writer.py +0 -0
  293. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/package_resolution.py +0 -0
  294. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/package_selection.py +0 -0
  295. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/phases/__init__.py +0 -0
  296. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/phases/_redownload.py +0 -0
  297. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/phases/_skip_logic.py +0 -0
  298. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/phases/audit.py +0 -0
  299. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/phases/download.py +0 -0
  300. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/phases/finalize.py +0 -0
  301. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/phases/heal.py +0 -0
  302. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/phases/integrate.py +0 -0
  303. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/phases/local_content.py +0 -0
  304. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/phases/policy_gate.py +0 -0
  305. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/phases/policy_target_check.py +0 -0
  306. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/plan.py +0 -0
  307. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/presentation/__init__.py +0 -0
  308. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/presentation/dry_run.py +0 -0
  309. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/registry_wiring.py +0 -0
  310. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/root_redirect.py +0 -0
  311. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/skill_path_migration.py +0 -0
  312. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/sources.py +0 -0
  313. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/summary.py +0 -0
  314. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/target_warnings.py +0 -0
  315. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/template.py +0 -0
  316. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/install/transaction.py +0 -0
  317. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/__init__.py +0 -0
  318. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/_hook_dropped_targets.py +0 -0
  319. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/_shared.py +0 -0
  320. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/agent_integrator.py +0 -0
  321. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/canvas_integrator.py +0 -0
  322. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/command_integrator.py +0 -0
  323. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/copilot_app_db.py +0 -0
  324. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/copilot_app_project.py +0 -0
  325. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/copilot_app_workflow_integrator.py +0 -0
  326. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/copilot_app_ws.py +0 -0
  327. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/copilot_cowork_paths.py +0 -0
  328. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/coverage.py +0 -0
  329. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/dispatch.py +0 -0
  330. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/hook_file_routing.py +0 -0
  331. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/hook_ir.py +0 -0
  332. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/hook_native_formats.py +0 -0
  333. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/instruction_integrator.py +0 -0
  334. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/kiro_hook_integrator.py +0 -0
  335. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/opencode_frontmatter.py +0 -0
  336. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/prompt_integrator.py +0 -0
  337. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/skill_integrator.py +0 -0
  338. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/skill_transformer.py +0 -0
  339. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/integration/utils.py +0 -0
  340. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/__init__.py +0 -0
  341. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/_git_utils.py +0 -0
  342. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/_io.py +0 -0
  343. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/_shared.py +0 -0
  344. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/audit.py +0 -0
  345. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/diagnostics.py +0 -0
  346. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/drift_check.py +0 -0
  347. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/errors.py +0 -0
  348. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/git_stderr.py +0 -0
  349. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/init_template.py +0 -0
  350. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/migration.py +0 -0
  351. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/output_profiles.py +0 -0
  352. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/registry.py +0 -0
  353. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/semver.py +0 -0
  354. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/shadow_detector.py +0 -0
  355. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/validator.py +0 -0
  356. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/version_check.py +0 -0
  357. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/version_pins.py +0 -0
  358. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/marketplace/yml_editor.py +0 -0
  359. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/models/__init__.py +0 -0
  360. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/models/dependency/__init__.py +0 -0
  361. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/models/dependency/lsp.py +0 -0
  362. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/models/dependency/mcp.py +0 -0
  363. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/models/dependency/object_fields.py +0 -0
  364. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/models/dependency/provider_coordinates.py +0 -0
  365. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/models/dependency/subsets.py +0 -0
  366. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/models/dependency/types.py +0 -0
  367. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/models/format_detection.py +0 -0
  368. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/models/manifest_contract.py +0 -0
  369. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/models/plugin.py +0 -0
  370. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/models/validation.py +0 -0
  371. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/output/__init__.py +0 -0
  372. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/output/formatters.py +0 -0
  373. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/output/models.py +0 -0
  374. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/output/script_formatters.py +0 -0
  375. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/policy/__init__.py +0 -0
  376. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/policy/_constraint_pinning.py +0 -0
  377. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/policy/_help_text.py +0 -0
  378. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/policy/_shared.py +0 -0
  379. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/policy/inheritance.py +0 -0
  380. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/policy/install_preflight.py +0 -0
  381. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/policy/matcher.py +0 -0
  382. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/policy/models.py +0 -0
  383. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/policy/outcome_routing.py +0 -0
  384. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/policy/parser.py +0 -0
  385. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/policy/policy_checks.py +0 -0
  386. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/policy/project_config.py +0 -0
  387. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/policy/schema.py +0 -0
  388. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/primitives/__init__.py +0 -0
  389. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/primitives/discovery.py +0 -0
  390. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/primitives/models.py +0 -0
  391. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/primitives/parser.py +0 -0
  392. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/registry/__init__.py +0 -0
  393. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/registry/client.py +0 -0
  394. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/registry/integration.py +0 -0
  395. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/runtime/__init__.py +0 -0
  396. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/runtime/base.py +0 -0
  397. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/runtime/codex_runtime.py +0 -0
  398. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/runtime/copilot_runtime.py +0 -0
  399. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/runtime/factory.py +0 -0
  400. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/runtime/llm_runtime.py +0 -0
  401. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/runtime/manager.py +0 -0
  402. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/runtime/registry.py +0 -0
  403. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/runtime/utils.py +0 -0
  404. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/security/__init__.py +0 -0
  405. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/security/audit_report.py +0 -0
  406. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/security/content_scanner.py +0 -0
  407. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/security/executables.py +0 -0
  408. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/security/external/__init__.py +0 -0
  409. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/security/external/base.py +0 -0
  410. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/security/external/gate.py +0 -0
  411. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/security/external/generic_sarif.py +0 -0
  412. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/security/external/options.py +0 -0
  413. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/security/external/registry.py +0 -0
  414. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/security/external/runner.py +0 -0
  415. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/security/external/sarif_ingest.py +0 -0
  416. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/security/external/skillspector.py +0 -0
  417. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/update_policy.py +0 -0
  418. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/__init__.py +0 -0
  419. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/archive.py +0 -0
  420. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/console.py +0 -0
  421. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/content_hash.py +0 -0
  422. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/diagnostics.py +0 -0
  423. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/exclude.py +0 -0
  424. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/file_ops.py +0 -0
  425. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/git_env.py +0 -0
  426. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/git_sparse.py +0 -0
  427. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/guards.py +0 -0
  428. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/helpers.py +0 -0
  429. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/install_tui.py +0 -0
  430. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/normalization.py +0 -0
  431. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/path_security.py +0 -0
  432. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/patterns.py +0 -0
  433. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/perf_stats.py +0 -0
  434. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/reflink.py +0 -0
  435. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/short_sha.py +0 -0
  436. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/subprocess_env.py +0 -0
  437. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/utils/yaml_io.py +0 -0
  438. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/version.py +0 -0
  439. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/workflow/__init__.py +0 -0
  440. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/workflow/discovery.py +0 -0
  441. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/workflow/parser.py +0 -0
  442. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli/workflow/runner.py +0 -0
  443. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli.egg-info/dependency_links.txt +0 -0
  444. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli.egg-info/entry_points.txt +0 -0
  445. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli.egg-info/requires.txt +0 -0
  446. {apm_cli-0.26.0 → apm_cli-0.27.0}/src/apm_cli.egg-info/top_level.txt +0 -0
  447. {apm_cli-0.26.0 → apm_cli-0.27.0}/tests/test_apm_resolver.py +0 -0
  448. {apm_cli-0.26.0 → apm_cli-0.27.0}/tests/test_codex_empty_string_and_defaults.py +0 -0
  449. {apm_cli-0.26.0 → apm_cli-0.27.0}/tests/test_collision_integration.py +0 -0
  450. {apm_cli-0.26.0 → apm_cli-0.27.0}/tests/test_console.py +0 -0
  451. {apm_cli-0.26.0 → apm_cli-0.27.0}/tests/test_distributed_compilation.py +0 -0
  452. {apm_cli-0.26.0 → apm_cli-0.27.0}/tests/test_empty_string_and_defaults.py +0 -0
  453. {apm_cli-0.26.0 → apm_cli-0.27.0}/tests/test_enhanced_discovery.py +0 -0
  454. {apm_cli-0.26.0 → apm_cli-0.27.0}/tests/test_github_downloader.py +0 -0
  455. {apm_cli-0.26.0 → apm_cli-0.27.0}/tests/test_github_downloader_token_precedence.py +0 -0
  456. {apm_cli-0.26.0 → apm_cli-0.27.0}/tests/test_gitlab_git_transport.py +0 -0
  457. {apm_cli-0.26.0 → apm_cli-0.27.0}/tests/test_runnable_prompts.py +0 -0
  458. {apm_cli-0.26.0 → apm_cli-0.27.0}/tests/test_runtime_manager_token_precedence.py +0 -0
  459. {apm_cli-0.26.0 → apm_cli-0.27.0}/tests/test_token_manager.py +0 -0
  460. {apm_cli-0.26.0 → apm_cli-0.27.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.26.0
3
+ Version: 0.27.0
4
4
  Summary: MCP configuration tool
5
5
  Author-email: Daniel Meppiel <user@example.com>
6
6
  License: MIT License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "apm-cli"
7
- version = "0.26.0"
7
+ version = "0.27.0"
8
8
  description = "MCP configuration tool"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -3,6 +3,7 @@
3
3
  import os
4
4
  import re
5
5
  from abc import ABC, abstractmethod
6
+ from dataclasses import dataclass
6
7
  from pathlib import Path
7
8
  from typing import Any, ClassVar
8
9
 
@@ -29,6 +30,153 @@ _ENV_PLACEHOLDER_RE = re.compile(r"<([A-Z_][A-Z0-9_]*)>|" + _ENV_VAR_RE.pattern)
29
30
  # deprecation warnings across all servers in a single install run.
30
31
  _LEGACY_ANGLE_VAR_RE = re.compile(r"<([A-Z_][A-Z0-9_]*)>")
31
32
 
33
+ # MCP Registry v0.1 names the container registry type ``oci``; the adapters
34
+ # below key their launcher dispatch on ``docker`` (the vocabulary the legacy
35
+ # registry shape used, and what ``_infer_registry_name`` derives from a
36
+ # ``docker`` runtime hint or an image-shaped package name). Without this
37
+ # mapping an ``oci`` package matches no launcher branch and falls through to
38
+ # the generic ``npx`` default, which hands the image reference to npm as a
39
+ # package name -- a dependency-confusion exposure, not just a broken config
40
+ # (#2376). Keyed on the lowercased registry type; unlisted values pass through
41
+ # untouched.
42
+ _REGISTRY_TYPE_ALIASES = {"oci": "docker"}
43
+ _DOCKER_RUN_OPTIONS_WITH_VALUES = frozenset(
44
+ {
45
+ "--add-host",
46
+ "--annotation",
47
+ "--attach",
48
+ "--blkio-weight",
49
+ "--blkio-weight-device",
50
+ "--cap-add",
51
+ "--cap-drop",
52
+ "--cgroup-parent",
53
+ "--cgroupns",
54
+ "--cidfile",
55
+ "--cpu-count",
56
+ "--cpu-percent",
57
+ "--cpu-period",
58
+ "--cpu-quota",
59
+ "--cpu-rt-period",
60
+ "--cpu-rt-runtime",
61
+ "--cpu-shares",
62
+ "--cpus",
63
+ "--cpuset-cpus",
64
+ "--cpuset-mems",
65
+ "--detach-keys",
66
+ "--device",
67
+ "--device-cgroup-rule",
68
+ "--device-read-bps",
69
+ "--device-read-iops",
70
+ "--device-write-bps",
71
+ "--device-write-iops",
72
+ "--dns",
73
+ "--dns-opt",
74
+ "--dns-option",
75
+ "--dns-search",
76
+ "--domainname",
77
+ "--entrypoint",
78
+ "--env",
79
+ "--env-file",
80
+ "--expose",
81
+ "--gpus",
82
+ "--group-add",
83
+ "--health-cmd",
84
+ "--health-interval",
85
+ "--health-retries",
86
+ "--health-start-interval",
87
+ "--health-start-period",
88
+ "--health-timeout",
89
+ "--hostname",
90
+ "--io-maxbandwidth",
91
+ "--io-maxiops",
92
+ "--ip",
93
+ "--ip6",
94
+ "--ipc",
95
+ "--isolation",
96
+ "--kernel-memory",
97
+ "--label",
98
+ "--label-file",
99
+ "--link",
100
+ "--link-local-ip",
101
+ "--log-driver",
102
+ "--log-opt",
103
+ "--mac-address",
104
+ "--memory",
105
+ "--memory-reservation",
106
+ "--memory-swap",
107
+ "--memory-swappiness",
108
+ "--mount",
109
+ "--name",
110
+ "--net",
111
+ "--net-alias",
112
+ "--network",
113
+ "--network-alias",
114
+ "--oom-score-adj",
115
+ "--pid",
116
+ "--pids-limit",
117
+ "--platform",
118
+ "--publish",
119
+ "--pull",
120
+ "--restart",
121
+ "--runtime",
122
+ "--security-opt",
123
+ "--shm-size",
124
+ "--stop-signal",
125
+ "--stop-timeout",
126
+ "--storage-opt",
127
+ "--sysctl",
128
+ "--tmpfs",
129
+ "--ulimit",
130
+ "--user",
131
+ "--userns",
132
+ "--uts",
133
+ "--volume",
134
+ "--volume-driver",
135
+ "--volumes-from",
136
+ "--workdir",
137
+ "-a",
138
+ "-c",
139
+ "-e",
140
+ "-h",
141
+ "-l",
142
+ "-m",
143
+ "-p",
144
+ "-u",
145
+ "-v",
146
+ "-w",
147
+ }
148
+ )
149
+
150
+
151
+ def _docker_image_repository(reference: str) -> str:
152
+ """Return the repository component of a container image reference.
153
+
154
+ Drops an ``@sha256:...`` digest and a trailing ``:tag`` so that two
155
+ references to the same repository compare equal regardless of how each
156
+ side is pinned. A ``host:port/`` prefix is preserved, since a tag can
157
+ only appear in the final path segment.
158
+
159
+ Docker Hub is also folded to its short form: a registry commonly
160
+ publishes a fully qualified ``identifier`` while the run arguments it
161
+ ships use the implicit spelling, and treating those as different
162
+ repositories would append a second image operand.
163
+ """
164
+ repository = reference.split("@", 1)[0]
165
+ last_segment = repository.rsplit("/", 1)[-1]
166
+ tag_at = last_segment.find(":")
167
+ if tag_at != -1:
168
+ repository = repository[: len(repository) - len(last_segment) + tag_at]
169
+ for default_registry in ("docker.io/", "index.docker.io/"):
170
+ if repository.startswith(default_registry):
171
+ repository = repository[len(default_registry) :]
172
+ break
173
+ # Only meaningful once the implicit registry is stripped: ``library/`` is
174
+ # where Docker Hub keeps official images, so ``library/redis`` is ``redis``.
175
+ if repository.startswith("library/"):
176
+ repository = repository[len("library/") :]
177
+ return repository
178
+
179
+
32
180
  # Config keys that ``_extra`` passthrough must NEVER set on a rendered harness
33
181
  # config. Covers the modeled MCP fields (imported single-source from the model)
34
182
  # plus harness-specific aliases that mirror a modeled field under a different
@@ -39,6 +187,14 @@ _LEGACY_ANGLE_VAR_RE = re.compile(r"<([A-Z_][A-Z0-9_]*)>")
39
187
  _EXTRA_DENYLIST = _RESERVED_EXTRA_KEYS | frozenset({"http_headers"})
40
188
 
41
189
 
190
+ @dataclass(frozen=True)
191
+ class _MCPLauncherArgumentGroup:
192
+ """One atomic registry argument and its rendered argv values."""
193
+
194
+ kind: str
195
+ values: tuple[str, ...]
196
+
197
+
42
198
  def registry_field_is_required(field: dict[str, Any]) -> bool:
43
199
  """Return True unless registry metadata explicitly marks a field optional."""
44
200
  return field.get("required", field.get("is_required", True)) is not False
@@ -280,13 +436,25 @@ class MCPClientAdapter(ABC):
280
436
 
281
437
  Returns:
282
438
  str: Inferred registry name (e.g. "npm", "pypi", "docker") or "".
439
+ Spec spellings that name the same registry as an APM launcher
440
+ branch are canonicalized via ``_REGISTRY_TYPE_ALIASES`` (v0.1
441
+ ``oci`` -> ``docker``). Malformed explicit values fail closed
442
+ before any package-manager launcher is selected.
283
443
  """
284
444
  if not package:
285
445
  return ""
286
446
 
287
447
  explicit = package.get("registry_name", "")
448
+ if not isinstance(explicit, str):
449
+ # Registry payloads are untrusted. A malformed explicit value must
450
+ # fail closed rather than miss every launcher branch and reach the
451
+ # generic npx fallback with an untrusted package name.
452
+ raise ValueError("MCP package registry_name must be a string")
453
+ if explicit and not explicit.strip():
454
+ raise ValueError("MCP package registry_name must not be whitespace")
288
455
  if explicit:
289
- return explicit
456
+ canonical = explicit.strip().lower()
457
+ return _REGISTRY_TYPE_ALIASES.get(canonical, canonical)
290
458
 
291
459
  name = package.get("name", "")
292
460
  runtime_hint = package.get("runtime_hint", "")
@@ -314,6 +482,382 @@ class MCPClientAdapter(ABC):
314
482
 
315
483
  return ""
316
484
 
485
+ def _parse_non_container_argument_groups(
486
+ self,
487
+ arguments: object,
488
+ *,
489
+ resolved_env: dict[str, str] | None = None,
490
+ runtime_vars: dict[str, object] | None = None,
491
+ runtime_variable_fallbacks: dict[str, str] | None = None,
492
+ secret_variable_fallbacks: dict[str, str] | None = None,
493
+ package_name: str = "",
494
+ ) -> list[_MCPLauncherArgumentGroup]:
495
+ """Parse registry arguments without losing named-group boundaries.
496
+
497
+ Typed v0.1 entries read ``value`` while untyped legacy entries read
498
+ ``value_hint``. Named arguments remain one atomic group so package
499
+ identity matching cannot confuse a flag value with the package operand.
500
+ Optional groups with unresolved variables are omitted as a whole;
501
+ malformed or unresolved required entries fail closed.
502
+
503
+ Args:
504
+ arguments: Raw ``runtime_arguments`` or ``package_arguments`` value.
505
+ resolved_env: Target-native environment placeholder mapping.
506
+ runtime_vars: Values collected for registry argument variables.
507
+ runtime_variable_fallbacks: Target-native fallbacks for variables
508
+ such as VS Code's ``workspaceFolder``.
509
+ secret_variable_fallbacks: Target-native indirections for secret
510
+ values that must not be written literally.
511
+ package_name: Package identity included in actionable diagnostics.
512
+
513
+ Returns:
514
+ Ordered atomic launcher argument groups.
515
+
516
+ Raises:
517
+ ValueError: If registry argument metadata is malformed or a required
518
+ variable cannot be resolved.
519
+ """
520
+ if arguments is None:
521
+ return []
522
+ if not isinstance(arguments, list):
523
+ raise ValueError("MCP package arguments must be a list")
524
+
525
+ groups: list[_MCPLauncherArgumentGroup] = []
526
+ for entry in arguments:
527
+ if not isinstance(entry, dict):
528
+ raise ValueError("MCP package argument entries must be objects")
529
+
530
+ raw_type = entry.get("type", "")
531
+ if not isinstance(raw_type, str):
532
+ raise ValueError("MCP package argument type must be a string")
533
+ arg_type = raw_type.strip().lower()
534
+ if arg_type not in ("", "positional", "named"):
535
+ raise ValueError("MCP package argument type must be 'positional' or 'named'")
536
+
537
+ required_marker = entry.get(
538
+ "is_required",
539
+ entry.get("isRequired", entry.get("required")),
540
+ )
541
+ if required_marker is not None and not isinstance(required_marker, bool):
542
+ raise ValueError("MCP package argument required marker must be a boolean")
543
+ required = True if required_marker is None else required_marker
544
+
545
+ variables = entry.get("variables")
546
+ if variables is not None and not isinstance(variables, dict):
547
+ raise ValueError("MCP package argument variables must be an object")
548
+ if not required and "variables" not in entry:
549
+ continue
550
+
551
+ if arg_type:
552
+ raw_value = entry.get("value", entry.get("default"))
553
+ else:
554
+ raw_value = entry.get(
555
+ "value_hint",
556
+ entry.get("value", entry.get("default")),
557
+ )
558
+
559
+ name = entry.get("name")
560
+ if arg_type == "named" and not isinstance(name, str):
561
+ raise ValueError("MCP package argument name must be a string")
562
+ if arg_type == "named" and not name:
563
+ raise ValueError("MCP package argument name must not be empty")
564
+
565
+ if raw_value is None or raw_value == "":
566
+ if arg_type == "named" and name:
567
+ if required:
568
+ groups.append(_MCPLauncherArgumentGroup("named", (name,)))
569
+ elif required:
570
+ raise ValueError(
571
+ f"MCP package argument for '{package_name or 'unknown'}' "
572
+ "is missing a required positional value"
573
+ )
574
+ continue
575
+ if not isinstance(raw_value, str):
576
+ raise ValueError("MCP package argument value must be a string")
577
+
578
+ rendered, unresolved_variable = self._resolve_non_container_argument_value(
579
+ raw_value,
580
+ variables=variables or {},
581
+ resolved_env=resolved_env or {},
582
+ runtime_vars=runtime_vars or {},
583
+ runtime_variable_fallbacks=runtime_variable_fallbacks or {},
584
+ secret_variable_fallbacks=secret_variable_fallbacks or {},
585
+ )
586
+ if rendered is None:
587
+ if required:
588
+ raise ValueError(
589
+ "Could not resolve required MCP package argument variable "
590
+ f"'{unresolved_variable or 'unknown'}' for "
591
+ f"'{package_name or 'unknown'}'"
592
+ )
593
+ continue
594
+
595
+ if arg_type == "named" and name:
596
+ groups.append(_MCPLauncherArgumentGroup("named", (name, rendered)))
597
+ else:
598
+ kind = "positional" if arg_type == "positional" else "legacy"
599
+ groups.append(_MCPLauncherArgumentGroup(kind, (rendered,)))
600
+ return groups
601
+
602
+ def _resolve_non_container_argument_value(
603
+ self,
604
+ template: str,
605
+ *,
606
+ variables: dict[object, object],
607
+ resolved_env: dict[str, str],
608
+ runtime_vars: dict[str, object],
609
+ runtime_variable_fallbacks: dict[str, str],
610
+ secret_variable_fallbacks: dict[str, str],
611
+ ) -> tuple[str | None, str | None]:
612
+ """Resolve one argument value and identify any absent variable."""
613
+ for variable_name, variable_info in variables.items():
614
+ if not isinstance(variable_name, str):
615
+ raise ValueError("MCP package argument variable names must be strings")
616
+ if not isinstance(variable_info, dict):
617
+ raise ValueError("MCP package argument variable metadata must be an object")
618
+ placeholder = f"{{{variable_name}}}"
619
+ if placeholder not in template:
620
+ continue
621
+ secret_marker = variable_info.get(
622
+ "isSecret",
623
+ variable_info.get("is_secret", False),
624
+ )
625
+ if not isinstance(secret_marker, bool):
626
+ raise ValueError("MCP package argument variable isSecret marker must be a boolean")
627
+ if secret_marker:
628
+ replacement = secret_variable_fallbacks.get(variable_name)
629
+ if replacement is None and self._supports_runtime_env_substitution:
630
+ replacement = self._format_runtime_env_placeholder(variable_name)
631
+ else:
632
+ supplied = runtime_vars.get(variable_name)
633
+ if supplied is not None and str(supplied) != "":
634
+ replacement = str(supplied)
635
+ else:
636
+ configured = variable_info.get(
637
+ "value",
638
+ variable_info.get("default"),
639
+ )
640
+ if configured is not None and not isinstance(configured, str):
641
+ raise ValueError("MCP package argument variable value must be a string")
642
+ replacement = configured or runtime_variable_fallbacks.get(variable_name)
643
+ if replacement is None:
644
+ return None, variable_name
645
+ template = template.replace(placeholder, replacement)
646
+
647
+ string_runtime_vars = {
648
+ key: str(value) for key, value in runtime_vars.items() if value is not None
649
+ }
650
+ return (
651
+ self._resolve_variable_placeholders(
652
+ template,
653
+ resolved_env,
654
+ string_runtime_vars,
655
+ ),
656
+ None,
657
+ )
658
+
659
+ @staticmethod
660
+ def _processed_non_container_argument_groups(
661
+ arguments: list[object],
662
+ ) -> list[_MCPLauncherArgumentGroup]:
663
+ """Wrap already-processed compatibility inputs as positional groups."""
664
+ return [_MCPLauncherArgumentGroup("legacy", (str(argument),)) for argument in arguments]
665
+
666
+ @staticmethod
667
+ def _flatten_non_container_argument_groups(
668
+ groups: list[_MCPLauncherArgumentGroup],
669
+ ) -> list[str]:
670
+ """Flatten ordered atomic groups without changing their contents."""
671
+ return [value for group in groups for value in group.values]
672
+
673
+ @staticmethod
674
+ def _build_non_container_launcher_argv(
675
+ package_name: str,
676
+ runtime_groups: list[_MCPLauncherArgumentGroup],
677
+ package_groups: list[_MCPLauncherArgumentGroup],
678
+ *,
679
+ launcher_prefix: tuple[str, ...] = (),
680
+ ) -> list[str]:
681
+ """Merge one package identity into a typed non-container launcher argv.
682
+
683
+ Package detection is semantic and type-aware. The first non-option
684
+ typed positional group can satisfy package identity; named groups are
685
+ atomic and their values never count. Untyped legacy runtime argv are
686
+ searched for the identifier because their historical shape carries no
687
+ stronger type signal. Package groups never satisfy launcher identity;
688
+ they are arguments to the package binary. This preserves a legitimate
689
+ flag value equal to the package name while avoiding duplicate package
690
+ operands.
691
+
692
+ Args:
693
+ package_name: Registry package identifier.
694
+ runtime_groups: Ordered runtime argument groups.
695
+ package_groups: Ordered package argument groups appended last.
696
+ launcher_prefix: Default launcher operands preceding the package,
697
+ such as npm's ``-y``.
698
+
699
+ Returns:
700
+ Complete ordered launcher argv.
701
+
702
+ Raises:
703
+ ValueError: If the package identifier is missing or malformed.
704
+ """
705
+ if not isinstance(package_name, str) or not package_name:
706
+ raise ValueError("MCP package name must be a non-empty string")
707
+
708
+ identity_present = any(
709
+ group.kind == "legacy"
710
+ and len(group.values) == 1
711
+ and MCPClientAdapter._package_identity_matches(
712
+ group.values[0],
713
+ package_name,
714
+ )
715
+ for group in runtime_groups
716
+ )
717
+ for group in runtime_groups:
718
+ if identity_present:
719
+ break
720
+ if group.kind != "positional" or len(group.values) != 1:
721
+ continue
722
+ candidate = group.values[0]
723
+ if candidate in launcher_prefix or candidate.startswith("-"):
724
+ continue
725
+ if MCPClientAdapter._package_identity_matches(candidate, package_name):
726
+ identity_present = True
727
+ break
728
+
729
+ leading_prefix_groups = 0
730
+ for expected, group in zip(launcher_prefix, runtime_groups, strict=False):
731
+ if group.kind == "named" or group.values != (expected,):
732
+ break
733
+ leading_prefix_groups += 1
734
+ has_leading_prefix = leading_prefix_groups == len(launcher_prefix)
735
+
736
+ runtime_values = MCPClientAdapter._flatten_non_container_argument_groups(runtime_groups)
737
+ package_values = MCPClientAdapter._flatten_non_container_argument_groups(package_groups)
738
+ if identity_present:
739
+ if launcher_prefix and not has_leading_prefix:
740
+ runtime_values = [*launcher_prefix, *runtime_values]
741
+ elif launcher_prefix and has_leading_prefix:
742
+ insertion = len(launcher_prefix)
743
+ runtime_values = [
744
+ *runtime_values[:insertion],
745
+ package_name,
746
+ *runtime_values[insertion:],
747
+ ]
748
+ else:
749
+ runtime_values = [
750
+ *launcher_prefix,
751
+ package_name,
752
+ *runtime_values,
753
+ ]
754
+ return [*runtime_values, *package_values]
755
+
756
+ @staticmethod
757
+ def _package_identity_matches(candidate: str, package_name: str) -> bool:
758
+ """Return whether a positional operand identifies the package."""
759
+ if candidate == package_name:
760
+ return True
761
+ version_prefix = f"{package_name}@"
762
+ return candidate.startswith(version_prefix) and len(candidate) > len(version_prefix)
763
+
764
+ @staticmethod
765
+ def _docker_image_references_match(left: Any, right: Any) -> bool:
766
+ """Return whether two strings name the same image repository."""
767
+ return (
768
+ isinstance(left, str)
769
+ and isinstance(right, str)
770
+ and _docker_image_repository(left) == _docker_image_repository(right)
771
+ )
772
+
773
+ @staticmethod
774
+ def _docker_option_requires_value(argument: Any) -> bool:
775
+ """Return whether a Docker run option needs a separate value."""
776
+ if not isinstance(argument, str) or "=" in argument:
777
+ return False
778
+ if argument.startswith("--"):
779
+ return argument in _DOCKER_RUN_OPTIONS_WITH_VALUES
780
+ if not argument.startswith("-") or argument == "-":
781
+ return False
782
+ short_options = argument[1:]
783
+ for index, short_name in enumerate(short_options):
784
+ if f"-{short_name}" in _DOCKER_RUN_OPTIONS_WITH_VALUES:
785
+ return index == len(short_options) - 1
786
+ return False
787
+
788
+ @classmethod
789
+ def _docker_image_arg_index(
790
+ cls,
791
+ runtime_args: list[Any],
792
+ image: str | None,
793
+ ) -> int | None:
794
+ """Return the matching Docker image operand index, or None."""
795
+ if not image or not runtime_args or runtime_args[0] != "run":
796
+ return None
797
+ index = 1
798
+ while index < len(runtime_args):
799
+ argument = runtime_args[index]
800
+ if argument == "--":
801
+ index += 1
802
+ break
803
+ if isinstance(argument, str) and argument.startswith("--"):
804
+ option = argument.split("=", 1)[0]
805
+ consumes_next = "=" not in argument and option in _DOCKER_RUN_OPTIONS_WITH_VALUES
806
+ if consumes_next and index + 1 >= len(runtime_args):
807
+ raise ValueError(f"Docker run option '{option}' requires a value")
808
+ index += 2 if consumes_next else 1
809
+ continue
810
+ if isinstance(argument, str) and argument.startswith("-") and argument != "-":
811
+ consumes_next = cls._docker_option_requires_value(argument)
812
+ if consumes_next and index + 1 >= len(runtime_args):
813
+ raise ValueError(f"Docker run option '{argument}' requires a value")
814
+ index += 2 if consumes_next else 1
815
+ continue
816
+ break
817
+ if index >= len(runtime_args):
818
+ return None
819
+ candidate = runtime_args[index]
820
+ if cls._docker_image_references_match(candidate, image):
821
+ return index
822
+ return None
823
+
824
+ @classmethod
825
+ def _ensure_docker_image_arg(
826
+ cls,
827
+ runtime_args: list[Any],
828
+ image: str | None,
829
+ ) -> list[Any]:
830
+ """Return *runtime_args* with the container image operand present.
831
+
832
+ ``docker run [OPTIONS] IMAGE`` needs the image after the run options.
833
+ Registries that list it as the last ``runtime_arguments`` entry already
834
+ satisfy that; registries that expose it only as the package
835
+ ``identifier`` leave the resolved args ending at the last option, which
836
+ would render an image-less ``docker run`` that fails on invocation
837
+ (#2376).
838
+
839
+ The image is appended only when no argument already references the same
840
+ repository. Comparison is on the repository component, so a digest- or
841
+ tag-pinned identifier still matches a differently-pinned argument
842
+ instead of being appended a second time -- a duplicate operand would be
843
+ parsed by Docker as the container command and break a launcher that
844
+ previously worked.
845
+
846
+ Args:
847
+ runtime_args (list): Resolved registry runtime arguments.
848
+ image (str): Container image reference from the package entry.
849
+
850
+ Returns:
851
+ list: A new list of ``docker run`` arguments.
852
+ """
853
+ runtime_args = list(runtime_args)
854
+ if not image:
855
+ return runtime_args
856
+ if cls._docker_image_arg_index(runtime_args, image) is not None:
857
+ return runtime_args
858
+ runtime_args.append(image)
859
+ return runtime_args
860
+
317
861
  @classmethod
318
862
  def _select_best_package(cls, packages):
319
863
  """Select the best package for installation from available packages.
@@ -707,8 +1251,9 @@ class MCPClientAdapter(ABC):
707
1251
  return server_url.split("/")[-1]
708
1252
  return server_url
709
1253
 
710
- @staticmethod
1254
+ @classmethod
711
1255
  def _apply_pypi_homebrew_generic_config(
1256
+ cls,
712
1257
  config: dict,
713
1258
  registry_name: str,
714
1259
  package_name: str,
@@ -716,6 +1261,8 @@ class MCPClientAdapter(ABC):
716
1261
  processed_runtime_args: list,
717
1262
  processed_package_args: list,
718
1263
  resolved_env: dict,
1264
+ runtime_argument_groups: list[_MCPLauncherArgumentGroup] | None = None,
1265
+ package_argument_groups: list[_MCPLauncherArgumentGroup] | None = None,
719
1266
  ) -> None:
720
1267
  """Apply pypi / homebrew / generic (uvx / brew / npx) run config to *config*.
721
1268
 
@@ -734,19 +1281,40 @@ class MCPClientAdapter(ABC):
734
1281
  after the package name.
735
1282
  resolved_env: Pre-resolved environment variables dict; an empty
736
1283
  dict is omitted.
1284
+ runtime_argument_groups: Optional typed runtime groups. Compatibility
1285
+ callers may omit them and supply processed strings only.
1286
+ package_argument_groups: Optional typed package groups appended
1287
+ after runtime groups.
737
1288
  """
1289
+ runtime_groups = runtime_argument_groups
1290
+ if runtime_groups is None:
1291
+ runtime_groups = cls._processed_non_container_argument_groups(processed_runtime_args)
1292
+ package_groups = package_argument_groups
1293
+ if package_groups is None:
1294
+ package_groups = cls._processed_non_container_argument_groups(processed_package_args)
1295
+
738
1296
  if registry_name == "pypi":
739
1297
  launcher = runtime_hint or "uvx"
740
1298
  config["command"] = launcher
741
- config["args"] = [package_name] + processed_runtime_args + processed_package_args # noqa: RUF005
1299
+ config["args"] = cls._build_non_container_launcher_argv(
1300
+ package_name,
1301
+ runtime_groups,
1302
+ package_groups,
1303
+ )
742
1304
  elif registry_name == "homebrew":
743
1305
  formula_name = package_name.split("/")[-1] if "/" in package_name else package_name
744
1306
  config["command"] = formula_name
745
1307
  config["args"] = processed_runtime_args + processed_package_args
746
1308
  else:
747
- # Generic / npm-compatible fallback
748
- config["command"] = "npx"
749
- config["args"] = processed_runtime_args + ["-y", package_name] + processed_package_args # noqa: RUF005
1309
+ launcher = runtime_hint or "npx"
1310
+ config["command"] = launcher
1311
+ prefix = ("-y",) if launcher in ("npx", "bunx") else ()
1312
+ config["args"] = cls._build_non_container_launcher_argv(
1313
+ package_name,
1314
+ runtime_groups,
1315
+ package_groups,
1316
+ launcher_prefix=prefix,
1317
+ )
750
1318
  if resolved_env:
751
1319
  config["env"] = resolved_env
752
1320