apm-cli 0.17.0__tar.gz → 0.18.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 (386) hide show
  1. {apm_cli-0.17.0/src/apm_cli.egg-info → apm_cli-0.18.0}/PKG-INFO +1 -1
  2. {apm_cli-0.17.0 → apm_cli-0.18.0}/pyproject.toml +1 -1
  3. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/adapters/client/base.py +20 -7
  4. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/adapters/client/copilot.py +12 -13
  5. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/adapters/client/intellij.py +11 -6
  6. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/install.py +28 -7
  7. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/__init__.py +37 -7
  8. apm_cli-0.18.0/src/apm_cli/commands/marketplace/audit.py +122 -0
  9. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/outdated.py +80 -8
  10. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/compilation/context_optimizer.py +28 -9
  11. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/compilation/link_resolver.py +18 -1
  12. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/command_logger.py +5 -0
  13. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/apm_resolver.py +111 -0
  14. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/dependency_graph.py +1 -0
  15. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/git_semver_resolver.py +9 -5
  16. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/lockfile.py +13 -1
  17. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/plugin_parser.py +156 -0
  18. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/context.py +1 -0
  19. apm_cli-0.18.0/src/apm_cli/install/lsp/__init__.py +5 -0
  20. apm_cli-0.18.0/src/apm_cli/install/lsp/integration.py +148 -0
  21. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/phases/resolve.py +33 -2
  22. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/pipeline.py +3 -0
  23. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/summary.py +4 -1
  24. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/__init__.py +2 -0
  25. apm_cli-0.18.0/src/apm_cli/integration/_shared.py +71 -0
  26. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/base_integrator.py +8 -1
  27. apm_cli-0.18.0/src/apm_cli/integration/lsp_integrator.py +508 -0
  28. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/mcp_integrator.py +4 -41
  29. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/mcp_integrator_install.py +1 -28
  30. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/skill_integrator.py +41 -3
  31. apm_cli-0.18.0/src/apm_cli/marketplace/audit.py +337 -0
  32. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/client.py +96 -14
  33. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/resolver.py +59 -10
  34. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/tag_pattern.py +80 -3
  35. apm_cli-0.18.0/src/apm_cli/marketplace/version_resolver.py +114 -0
  36. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/models/apm_package.py +33 -0
  37. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/models/dependency/__init__.py +2 -0
  38. apm_cli-0.18.0/src/apm_cli/models/dependency/lsp.py +229 -0
  39. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/models/dependency/reference.py +129 -3
  40. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/exclude.py +10 -0
  41. {apm_cli-0.17.0 → apm_cli-0.18.0/src/apm_cli.egg-info}/PKG-INFO +1 -1
  42. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli.egg-info/SOURCES.txt +8 -0
  43. {apm_cli-0.17.0 → apm_cli-0.18.0}/tests/test_apm_package_models.py +156 -0
  44. {apm_cli-0.17.0 → apm_cli-0.18.0}/tests/test_apm_resolver.py +192 -1
  45. {apm_cli-0.17.0 → apm_cli-0.18.0}/tests/test_lockfile.py +55 -0
  46. {apm_cli-0.17.0 → apm_cli-0.18.0}/AUTHORS +0 -0
  47. {apm_cli-0.17.0 → apm_cli-0.18.0}/LICENSE +0 -0
  48. {apm_cli-0.17.0 → apm_cli-0.18.0}/NOTICE +0 -0
  49. {apm_cli-0.17.0 → apm_cli-0.18.0}/README.md +0 -0
  50. {apm_cli-0.17.0 → apm_cli-0.18.0}/setup.cfg +0 -0
  51. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/__init__.py +0 -0
  52. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/adapters/__init__.py +0 -0
  53. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/adapters/client/__init__.py +0 -0
  54. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/adapters/client/_mcp_runtime_args.py +0 -0
  55. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/adapters/client/claude.py +0 -0
  56. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/adapters/client/codex.py +0 -0
  57. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/adapters/client/cursor.py +0 -0
  58. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/adapters/client/gemini.py +0 -0
  59. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/adapters/client/opencode.py +0 -0
  60. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/adapters/client/vscode.py +0 -0
  61. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/adapters/client/windsurf.py +0 -0
  62. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/adapters/package_manager/__init__.py +0 -0
  63. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/adapters/package_manager/base.py +0 -0
  64. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/adapters/package_manager/default_manager.py +0 -0
  65. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/bundle/__init__.py +0 -0
  66. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/bundle/local_bundle.py +0 -0
  67. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/bundle/lockfile_enrichment.py +0 -0
  68. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/bundle/packer.py +0 -0
  69. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/bundle/plugin_exporter.py +0 -0
  70. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/bundle/unpacker.py +0 -0
  71. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/cache/__init__.py +0 -0
  72. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/cache/git_cache.py +0 -0
  73. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/cache/http_cache.py +0 -0
  74. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/cache/integrity.py +0 -0
  75. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/cache/locking.py +0 -0
  76. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/cache/paths.py +0 -0
  77. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/cache/url_normalize.py +0 -0
  78. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/cli.py +0 -0
  79. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/__init__.py +0 -0
  80. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/_apm_yml_writer.py +0 -0
  81. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/_helpers.py +0 -0
  82. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/audit.py +0 -0
  83. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/cache.py +0 -0
  84. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/compile/__init__.py +0 -0
  85. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/compile/cli.py +0 -0
  86. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/compile/watcher.py +0 -0
  87. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/config.py +0 -0
  88. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/deps/__init__.py +0 -0
  89. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/deps/_utils.py +0 -0
  90. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/deps/cli.py +0 -0
  91. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/deps/why.py +0 -0
  92. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/doctor.py +0 -0
  93. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/experimental.py +0 -0
  94. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/find.py +0 -0
  95. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/init.py +0 -0
  96. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/list_cmd.py +0 -0
  97. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/lock.py +0 -0
  98. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/check.py +0 -0
  99. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/doctor.py +0 -0
  100. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/init.py +0 -0
  101. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/migrate.py +0 -0
  102. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/outdated.py +0 -0
  103. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/plugin/__init__.py +0 -0
  104. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/plugin/add.py +0 -0
  105. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/plugin/remove.py +0 -0
  106. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/plugin/set.py +0 -0
  107. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/publish.py +0 -0
  108. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/validate.py +0 -0
  109. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/mcp.py +0 -0
  110. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/pack.py +0 -0
  111. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/plugin/__init__.py +0 -0
  112. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/plugin/init.py +0 -0
  113. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/policy.py +0 -0
  114. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/prune.py +0 -0
  115. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/publish.py +0 -0
  116. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/run.py +0 -0
  117. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/runtime.py +0 -0
  118. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/self_update.py +0 -0
  119. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/targets.py +0 -0
  120. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/uninstall/__init__.py +0 -0
  121. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/uninstall/cli.py +0 -0
  122. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/uninstall/engine.py +0 -0
  123. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/update.py +0 -0
  124. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/commands/view.py +0 -0
  125. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/compilation/__init__.py +0 -0
  126. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/compilation/agents_compiler.py +0 -0
  127. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/compilation/build_id.py +0 -0
  128. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/compilation/claude_formatter.py +0 -0
  129. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/compilation/constants.py +0 -0
  130. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/compilation/constitution.py +0 -0
  131. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/compilation/constitution_block.py +0 -0
  132. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/compilation/distributed_compiler.py +0 -0
  133. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/compilation/gemini_formatter.py +0 -0
  134. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/compilation/injector.py +0 -0
  135. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/compilation/managed_section.py +0 -0
  136. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/compilation/output_writer.py +0 -0
  137. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/compilation/template_builder.py +0 -0
  138. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/config.py +0 -0
  139. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/constants.py +0 -0
  140. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/__init__.py +0 -0
  141. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/apm_yml.py +0 -0
  142. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/auth.py +0 -0
  143. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/azure_cli.py +0 -0
  144. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/build_orchestrator.py +0 -0
  145. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/conflict_detector.py +0 -0
  146. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/docker_args.py +0 -0
  147. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/errors.py +0 -0
  148. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/experimental.py +0 -0
  149. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/install_audit.py +0 -0
  150. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/null_logger.py +0 -0
  151. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/operations.py +0 -0
  152. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/plugin_manifest.py +0 -0
  153. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/safe_installer.py +0 -0
  154. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/scope.py +0 -0
  155. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/script_runner.py +0 -0
  156. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/target_detection.py +0 -0
  157. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/core/token_manager.py +0 -0
  158. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/__init__.py +0 -0
  159. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/_shared.py +0 -0
  160. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/aggregator.py +0 -0
  161. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/artifactory_entry.py +0 -0
  162. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/artifactory_orchestrator.py +0 -0
  163. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/bare_cache.py +0 -0
  164. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/clone_engine.py +0 -0
  165. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/download_strategies.py +0 -0
  166. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/git_auth_env.py +0 -0
  167. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/git_reference_resolver.py +0 -0
  168. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/git_remote_ops.py +0 -0
  169. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/github_downloader.py +0 -0
  170. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/github_downloader_validation.py +0 -0
  171. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/host_backends.py +0 -0
  172. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/installed_package.py +0 -0
  173. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/outdated_row.py +0 -0
  174. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/package_validator.py +0 -0
  175. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/path_anchoring.py +0 -0
  176. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/registry/__init__.py +0 -0
  177. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/registry/auth.py +0 -0
  178. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/registry/client.py +0 -0
  179. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/registry/config_loader.py +0 -0
  180. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/registry/extractor.py +0 -0
  181. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/registry/feature_gate.py +0 -0
  182. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/registry/outdated.py +0 -0
  183. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/registry/resolver.py +0 -0
  184. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/registry/semver.py +0 -0
  185. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/registry_proxy.py +0 -0
  186. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/shared_clone_cache.py +0 -0
  187. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/tiered_ref_resolver.py +0 -0
  188. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/transport_selection.py +0 -0
  189. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/verifier.py +0 -0
  190. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/deps/why_walker.py +0 -0
  191. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/drift.py +0 -0
  192. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/factory.py +0 -0
  193. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/__init__.py +0 -0
  194. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/artifactory_resolver.py +0 -0
  195. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/cache_pin.py +0 -0
  196. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/drift.py +0 -0
  197. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/errors.py +0 -0
  198. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/gitlab_resolver.py +0 -0
  199. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/heals/__init__.py +0 -0
  200. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/heals/base.py +0 -0
  201. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/heals/branch_ref_drift.py +0 -0
  202. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/heals/buggy_lockfile_recovery.py +0 -0
  203. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/helpers/__init__.py +0 -0
  204. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/helpers/security_scan.py +0 -0
  205. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/insecure_policy.py +0 -0
  206. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/local_bundle_handler.py +0 -0
  207. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/mcp/__init__.py +0 -0
  208. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/mcp/args.py +0 -0
  209. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/mcp/command.py +0 -0
  210. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/mcp/conflicts.py +0 -0
  211. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/mcp/entry.py +0 -0
  212. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/mcp/registry.py +0 -0
  213. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/mcp/warnings.py +0 -0
  214. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/mcp/writer.py +0 -0
  215. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/package_resolution.py +0 -0
  216. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/package_selection.py +0 -0
  217. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/phases/__init__.py +0 -0
  218. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/phases/_redownload.py +0 -0
  219. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/phases/_skip_logic.py +0 -0
  220. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/phases/audit.py +0 -0
  221. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/phases/cleanup.py +0 -0
  222. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/phases/download.py +0 -0
  223. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/phases/finalize.py +0 -0
  224. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/phases/heal.py +0 -0
  225. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/phases/integrate.py +0 -0
  226. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/phases/local_content.py +0 -0
  227. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/phases/lockfile.py +0 -0
  228. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/phases/policy_gate.py +0 -0
  229. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/phases/policy_target_check.py +0 -0
  230. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/phases/post_deps_local.py +0 -0
  231. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/phases/targets.py +0 -0
  232. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/plan.py +0 -0
  233. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/presentation/__init__.py +0 -0
  234. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/presentation/dry_run.py +0 -0
  235. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/registry_wiring.py +0 -0
  236. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/request.py +0 -0
  237. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/root_redirect.py +0 -0
  238. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/service.py +0 -0
  239. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/services.py +0 -0
  240. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/skill_path_migration.py +0 -0
  241. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/sources.py +0 -0
  242. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/template.py +0 -0
  243. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/install/validation.py +0 -0
  244. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/agent_integrator.py +0 -0
  245. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/cleanup.py +0 -0
  246. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/command_integrator.py +0 -0
  247. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/copilot_app_db.py +0 -0
  248. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/copilot_app_project.py +0 -0
  249. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/copilot_app_workflow_integrator.py +0 -0
  250. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/copilot_app_ws.py +0 -0
  251. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/copilot_cowork_paths.py +0 -0
  252. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/coverage.py +0 -0
  253. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/dispatch.py +0 -0
  254. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/hook_integrator.py +0 -0
  255. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/instruction_integrator.py +0 -0
  256. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/opencode_frontmatter.py +0 -0
  257. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/prompt_integrator.py +0 -0
  258. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/skill_transformer.py +0 -0
  259. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/targets.py +0 -0
  260. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/integration/utils.py +0 -0
  261. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/__init__.py +0 -0
  262. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/_git_utils.py +0 -0
  263. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/_io.py +0 -0
  264. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/_shared.py +0 -0
  265. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/builder.py +0 -0
  266. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/diagnostics.py +0 -0
  267. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/drift_check.py +0 -0
  268. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/errors.py +0 -0
  269. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/git_stderr.py +0 -0
  270. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/init_template.py +0 -0
  271. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/migration.py +0 -0
  272. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/models.py +0 -0
  273. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/output_mappers.py +0 -0
  274. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/output_profiles.py +0 -0
  275. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/pr_integration.py +0 -0
  276. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/publisher.py +0 -0
  277. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/ref_resolver.py +0 -0
  278. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/registry.py +0 -0
  279. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/semver.py +0 -0
  280. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/shadow_detector.py +0 -0
  281. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/validator.py +0 -0
  282. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/version_check.py +0 -0
  283. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/version_pins.py +0 -0
  284. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/yml_editor.py +0 -0
  285. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/marketplace/yml_schema.py +0 -0
  286. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/models/__init__.py +0 -0
  287. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/models/dependency/mcp.py +0 -0
  288. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/models/dependency/types.py +0 -0
  289. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/models/format_detection.py +0 -0
  290. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/models/plugin.py +0 -0
  291. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/models/results.py +0 -0
  292. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/models/validation.py +0 -0
  293. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/output/__init__.py +0 -0
  294. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/output/formatters.py +0 -0
  295. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/output/models.py +0 -0
  296. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/output/script_formatters.py +0 -0
  297. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/policy/__init__.py +0 -0
  298. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/policy/_constraint_pinning.py +0 -0
  299. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/policy/_help_text.py +0 -0
  300. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/policy/_shared.py +0 -0
  301. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/policy/ci_checks.py +0 -0
  302. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/policy/discovery.py +0 -0
  303. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/policy/inheritance.py +0 -0
  304. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/policy/install_preflight.py +0 -0
  305. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/policy/matcher.py +0 -0
  306. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/policy/models.py +0 -0
  307. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/policy/outcome_routing.py +0 -0
  308. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/policy/parser.py +0 -0
  309. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/policy/policy_checks.py +0 -0
  310. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/policy/project_config.py +0 -0
  311. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/policy/schema.py +0 -0
  312. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/primitives/__init__.py +0 -0
  313. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/primitives/discovery.py +0 -0
  314. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/primitives/models.py +0 -0
  315. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/primitives/parser.py +0 -0
  316. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/registry/__init__.py +0 -0
  317. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/registry/client.py +0 -0
  318. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/registry/integration.py +0 -0
  319. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/registry/operations.py +0 -0
  320. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/runtime/__init__.py +0 -0
  321. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/runtime/base.py +0 -0
  322. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/runtime/codex_runtime.py +0 -0
  323. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/runtime/copilot_runtime.py +0 -0
  324. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/runtime/factory.py +0 -0
  325. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/runtime/llm_runtime.py +0 -0
  326. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/runtime/manager.py +0 -0
  327. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/runtime/utils.py +0 -0
  328. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/security/__init__.py +0 -0
  329. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/security/audit_report.py +0 -0
  330. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/security/content_scanner.py +0 -0
  331. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/security/external/__init__.py +0 -0
  332. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/security/external/base.py +0 -0
  333. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/security/external/gate.py +0 -0
  334. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/security/external/generic_sarif.py +0 -0
  335. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/security/external/options.py +0 -0
  336. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/security/external/registry.py +0 -0
  337. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/security/external/runner.py +0 -0
  338. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/security/external/sarif_ingest.py +0 -0
  339. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/security/external/skillspector.py +0 -0
  340. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/security/file_scanner.py +0 -0
  341. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/security/gate.py +0 -0
  342. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/update_policy.py +0 -0
  343. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/__init__.py +0 -0
  344. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/atomic_io.py +0 -0
  345. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/console.py +0 -0
  346. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/content_hash.py +0 -0
  347. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/diagnostics.py +0 -0
  348. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/file_ops.py +0 -0
  349. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/git_env.py +0 -0
  350. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/git_sparse.py +0 -0
  351. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/github_host.py +0 -0
  352. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/guards.py +0 -0
  353. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/helpers.py +0 -0
  354. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/install_tui.py +0 -0
  355. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/normalization.py +0 -0
  356. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/path_security.py +0 -0
  357. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/paths.py +0 -0
  358. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/patterns.py +0 -0
  359. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/perf_stats.py +0 -0
  360. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/reflink.py +0 -0
  361. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/short_sha.py +0 -0
  362. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/subprocess_env.py +0 -0
  363. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/version_checker.py +0 -0
  364. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/utils/yaml_io.py +0 -0
  365. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/version.py +0 -0
  366. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/workflow/__init__.py +0 -0
  367. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/workflow/discovery.py +0 -0
  368. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/workflow/parser.py +0 -0
  369. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli/workflow/runner.py +0 -0
  370. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli.egg-info/dependency_links.txt +0 -0
  371. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli.egg-info/entry_points.txt +0 -0
  372. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli.egg-info/requires.txt +0 -0
  373. {apm_cli-0.17.0 → apm_cli-0.18.0}/src/apm_cli.egg-info/top_level.txt +0 -0
  374. {apm_cli-0.17.0 → apm_cli-0.18.0}/tests/test_codex_docker_args_fix.py +0 -0
  375. {apm_cli-0.17.0 → apm_cli-0.18.0}/tests/test_codex_empty_string_and_defaults.py +0 -0
  376. {apm_cli-0.17.0 → apm_cli-0.18.0}/tests/test_collision_integration.py +0 -0
  377. {apm_cli-0.17.0 → apm_cli-0.18.0}/tests/test_console.py +0 -0
  378. {apm_cli-0.17.0 → apm_cli-0.18.0}/tests/test_distributed_compilation.py +0 -0
  379. {apm_cli-0.17.0 → apm_cli-0.18.0}/tests/test_empty_string_and_defaults.py +0 -0
  380. {apm_cli-0.17.0 → apm_cli-0.18.0}/tests/test_enhanced_discovery.py +0 -0
  381. {apm_cli-0.17.0 → apm_cli-0.18.0}/tests/test_github_downloader.py +0 -0
  382. {apm_cli-0.17.0 → apm_cli-0.18.0}/tests/test_github_downloader_token_precedence.py +0 -0
  383. {apm_cli-0.17.0 → apm_cli-0.18.0}/tests/test_runnable_prompts.py +0 -0
  384. {apm_cli-0.17.0 → apm_cli-0.18.0}/tests/test_runtime_manager_token_precedence.py +0 -0
  385. {apm_cli-0.17.0 → apm_cli-0.18.0}/tests/test_token_manager.py +0 -0
  386. {apm_cli-0.17.0 → apm_cli-0.18.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.17.0
3
+ Version: 0.18.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.17.0"
7
+ version = "0.18.0"
8
8
  description = "MCP configuration tool"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -150,6 +150,21 @@ class MCPClientAdapter(ABC):
150
150
  self._last_env_placeholder_keys: set[str] = set()
151
151
  self._last_legacy_angle_vars: set[str] = set()
152
152
 
153
+ def _format_runtime_env_placeholder(self, name: str) -> str:
154
+ """Return the target runtime's env-var placeholder syntax for *name*."""
155
+ return "${" + name + "}"
156
+
157
+ def _translate_env_placeholder_for_runtime(self, value):
158
+ """Translate env-var placeholders to this adapter's runtime syntax."""
159
+ if not isinstance(value, str):
160
+ return value
161
+
162
+ def _to_runtime(match):
163
+ var_name = match.group(1) or match.group(2)
164
+ return self._format_runtime_env_placeholder(var_name)
165
+
166
+ return _ENV_PLACEHOLDER_RE.sub(_to_runtime, value)
167
+
153
168
  @property
154
169
  def project_root(self) -> Path:
155
170
  """Return the explicit project root or the current working directory."""
@@ -390,9 +405,7 @@ class MCPClientAdapter(ABC):
390
405
  continue
391
406
  if _has_env_placeholder(raw_value):
392
407
  self._last_legacy_angle_vars.update(_extract_legacy_angle_vars(raw_value))
393
- translated[name] = _translate_env_placeholder(raw_value)
394
- # Record every ${VAR} in the translated value (handles
395
- # both ${env:VAR} -> ${VAR} and bare ${VAR} cases).
408
+ translated[name] = self._translate_env_placeholder_for_runtime(raw_value)
396
409
  placeholder_keys.extend(
397
410
  m.group(1) for m in _ENV_VAR_RE.finditer(translated[name])
398
411
  )
@@ -403,7 +416,7 @@ class MCPClientAdapter(ABC):
403
416
  else:
404
417
  # Literal value present in apm.yml -- replace with a
405
418
  # runtime placeholder so the secret never touches disk.
406
- translated[name] = "${" + name + "}"
419
+ translated[name] = self._format_runtime_env_placeholder(name)
407
420
  placeholder_keys.append(name)
408
421
  self._last_env_placeholder_keys = set(placeholder_keys)
409
422
  return translated
@@ -421,7 +434,7 @@ class MCPClientAdapter(ABC):
421
434
  if name in self._DEFAULT_GITHUB_ENV:
422
435
  resolved[name] = self._DEFAULT_GITHUB_ENV[name]
423
436
  else:
424
- resolved[name] = "${" + name + "}"
437
+ resolved[name] = self._format_runtime_env_placeholder(name)
425
438
  placeholder_keys.append(name)
426
439
  self._last_env_placeholder_keys = set(placeholder_keys)
427
440
  return resolved
@@ -510,7 +523,7 @@ class MCPClientAdapter(ABC):
510
523
  self._last_env_placeholder_keys.update(legacy_keys)
511
524
  for match in _ENV_VAR_RE.finditer(value):
512
525
  self._last_env_placeholder_keys.add(match.group(1))
513
- return _translate_env_placeholder(value)
526
+ return self._translate_env_placeholder_for_runtime(value)
514
527
 
515
528
  from rich.prompt import Prompt
516
529
 
@@ -560,7 +573,7 @@ class MCPClientAdapter(ABC):
560
573
 
561
574
  if self._supports_runtime_env_substitution:
562
575
  self._last_legacy_angle_vars.update(_extract_legacy_angle_vars(processed))
563
- processed = _translate_env_placeholder(processed)
576
+ processed = self._translate_env_placeholder_for_runtime(processed)
564
577
  else:
565
578
  # Resolve only the legacy ``<VAR>`` form; newer syntaxes are
566
579
  # preserved verbatim for backward compatibility.
@@ -26,7 +26,9 @@ from .base import (
26
26
  _extract_legacy_angle_vars,
27
27
  _has_env_placeholder,
28
28
  _stringify_env_literal,
29
- _translate_env_placeholder,
29
+ )
30
+ from .base import (
31
+ _translate_env_placeholder as _translate_env_placeholder,
30
32
  )
31
33
 
32
34
 
@@ -678,9 +680,9 @@ class CopilotClientAdapter(MCPClientAdapter):
678
680
  # ({NAME: value-or-placeholder}); registry-sourced deps pass a list
679
681
  # of {name, description, required} dicts. Translate-mode handling
680
682
  # for the dict shape: each value is either already a placeholder
681
- # (translate it to the canonical ${VAR} form) or a literal (record
682
- # the key as a placeholder reference and emit ${NAME} so the
683
- # value never lands on disk). See issue #1152.
683
+ # (translate it to the adapter's runtime form) or a literal
684
+ # (record the key as a placeholder reference and emit a runtime
685
+ # placeholder so the value never lands on disk). See issue #1152.
684
686
  if isinstance(env_vars, dict) and self._supports_runtime_env_substitution:
685
687
  translated = {}
686
688
  placeholder_keys = []
@@ -694,9 +696,7 @@ class CopilotClientAdapter(MCPClientAdapter):
694
696
  continue
695
697
  if _has_env_placeholder(raw_value):
696
698
  self._last_legacy_angle_vars.update(_extract_legacy_angle_vars(raw_value))
697
- translated[name] = _translate_env_placeholder(raw_value)
698
- # Record every ${VAR} in the translated value (handles
699
- # both ${env:VAR} -> ${VAR} and bare ${VAR} cases).
699
+ translated[name] = self._translate_env_placeholder_for_runtime(raw_value)
700
700
  for match in _ENV_VAR_RE.finditer(translated[name]):
701
701
  placeholder_keys.append(match.group(1))
702
702
  elif name in default_github_env and raw_value == default_github_env[name]:
@@ -704,7 +704,7 @@ class CopilotClientAdapter(MCPClientAdapter):
704
704
  else:
705
705
  # Literal value present in apm.yml -- replace with a
706
706
  # runtime placeholder so the secret never touches disk.
707
- translated[name] = "${" + name + "}"
707
+ translated[name] = self._format_runtime_env_placeholder(name)
708
708
  placeholder_keys.append(name)
709
709
  self._last_env_placeholder_keys = set(placeholder_keys)
710
710
  return translated
@@ -722,10 +722,9 @@ class CopilotClientAdapter(MCPClientAdapter):
722
722
  # Non-secret literal default -- preserve as-is.
723
723
  resolved[name] = default_github_env[name]
724
724
  else:
725
- # Emit a runtime-substitution placeholder; Copilot CLI
726
- # resolves ``${NAME}`` from the host environment at
727
- # server-start. APM never reads or stores the value.
728
- resolved[name] = "${" + name + "}"
725
+ # Emit a runtime-substitution placeholder; APM never reads
726
+ # or stores the value.
727
+ resolved[name] = self._format_runtime_env_placeholder(name)
729
728
  placeholder_keys.append(name)
730
729
  # Record for the post-install summary line and the
731
730
  # security-improvement notice.
@@ -783,7 +782,7 @@ class CopilotClientAdapter(MCPClientAdapter):
783
782
  # them (the env-block path tracks via _resolve_environment_variables).
784
783
  for match in _ENV_VAR_RE.finditer(value):
785
784
  self._last_env_placeholder_keys.add(match.group(1))
786
- return _translate_env_placeholder(value)
785
+ return self._translate_env_placeholder_for_runtime(value)
787
786
 
788
787
  import sys
789
788
 
@@ -67,9 +67,10 @@ class IntelliJClientAdapter(CopilotClientAdapter):
67
67
 
68
68
  JetBrains Copilot stores server definitions in a user-scope JSON file
69
69
  with a ``"servers"`` top-level key (not ``"mcpServers"``). This adapter
70
- inherits all registry-resolution, env-var handling, and config read/write
71
- from :class:`CopilotClientAdapter` and overrides only the config path and
72
- ``mcp_servers_key`` so the parent methods operate on the correct key.
70
+ inherits registry-resolution and config read/write from
71
+ :class:`CopilotClientAdapter` and overrides the config path,
72
+ ``mcp_servers_key``, and runtime env-var placeholder syntax so the parent
73
+ methods operate on the correct schema.
73
74
  """
74
75
 
75
76
  supports_user_scope: bool = True
@@ -77,9 +78,13 @@ class IntelliJClientAdapter(CopilotClientAdapter):
77
78
  target_name: str = "intellij"
78
79
  mcp_servers_key: str = "servers"
79
80
 
80
- # JetBrains runtime-substitution support has not yet been audited.
81
- # Pin to install-time resolution for safety; revisit in a follow-up.
82
- _supports_runtime_env_substitution: bool = False
81
+ # JetBrains Copilot resolves ${env:VAR} placeholders in mcp.json at
82
+ # server-start, so APM must not bake matching host secrets to disk.
83
+ _supports_runtime_env_substitution: bool = True
84
+
85
+ def _format_runtime_env_placeholder(self, name: str) -> str:
86
+ """Return JetBrains Copilot's native env-var placeholder syntax."""
87
+ return "${env:" + name + "}"
83
88
 
84
89
  # ------------------------------------------------------------------ #
85
90
  # Config path
@@ -888,7 +888,7 @@ def _handle_mcp_install(
888
888
  @click.option(
889
889
  "--runtime",
890
890
  help=(
891
- "Target specific runtime only (copilot, codex, vscode, cursor, opencode, gemini, claude, windsurf)"
891
+ "Target specific runtime only (copilot, codex, vscode, cursor, opencode, gemini, claude, windsurf, intellij)"
892
892
  ),
893
893
  )
894
894
  @click.option("--exclude", help="Exclude specific runtime from installation")
@@ -961,7 +961,7 @@ def _handle_mcp_install(
961
961
  "global_",
962
962
  is_flag=True,
963
963
  default=False,
964
- help="Install to user scope (~/.apm/) instead of the current project. MCP servers target global-capable runtimes only (Copilot CLI, Codex CLI).",
964
+ help="Install to user scope (~/.apm/) instead of the current project. MCP servers target global-capable runtimes only (Copilot CLI, Codex CLI, JetBrains Copilot).",
965
965
  )
966
966
  @click.option(
967
967
  "--ssh",
@@ -1550,7 +1550,7 @@ def install( # noqa: PLR0913
1550
1550
  skill_subset_from_cli=bool(skill_names),
1551
1551
  )
1552
1552
 
1553
- apm_count, mcp_count, apm_diagnostics = _install_apm_packages(
1553
+ apm_count, mcp_count, lsp_count, apm_diagnostics = _install_apm_packages(
1554
1554
  install_ctx,
1555
1555
  outcome,
1556
1556
  )
@@ -1559,6 +1559,7 @@ def install( # noqa: PLR0913
1559
1559
  logger=logger,
1560
1560
  apm_count=apm_count,
1561
1561
  mcp_count=mcp_count,
1562
+ lsp_count=lsp_count,
1562
1563
  apm_diagnostics=apm_diagnostics,
1563
1564
  force=force,
1564
1565
  elapsed_seconds=time.perf_counter() - install_started_at,
@@ -1639,7 +1640,7 @@ def _install_apm_packages(ctx, outcome):
1639
1640
  ``None`` when no explicit packages were passed).
1640
1641
 
1641
1642
  Returns:
1642
- Tuple of ``(apm_count, mcp_count, apm_diagnostics)``.
1643
+ Tuple of ``(apm_count, mcp_count, lsp_count, apm_diagnostics)``.
1643
1644
  """
1644
1645
  logger = ctx.logger
1645
1646
 
@@ -1677,6 +1678,7 @@ def _install_apm_packages(ctx, outcome):
1677
1678
  # Determine what to install based on install mode
1678
1679
  should_install_apm = ctx.install_mode != InstallMode.MCP
1679
1680
  should_install_mcp = ctx.install_mode != InstallMode.APM
1681
+ should_install_lsp = should_install_mcp
1680
1682
 
1681
1683
  # Show what will be installed if dry run
1682
1684
  if ctx.dry_run:
@@ -1711,7 +1713,7 @@ def _install_apm_packages(ctx, outcome):
1711
1713
  only_packages=ctx.only_packages,
1712
1714
  apm_dir=ctx.apm_dir,
1713
1715
  )
1714
- return 0, 0, None # render_and_exit exits; this line is defensive
1716
+ return 0, 0, 0, None # render_and_exit exits; this line is defensive
1715
1717
 
1716
1718
  # Install APM dependencies first (if requested)
1717
1719
  apm_count = 0
@@ -1945,17 +1947,35 @@ def _install_apm_packages(ctx, outcome):
1945
1947
  # mcp_servers. Restore the previous set so it is not lost.
1946
1948
  MCPIntegrator.update_lockfile(old_mcp_servers, _lock_path, mcp_configs=old_mcp_configs)
1947
1949
 
1950
+ # -------------------------------------------------------------------------
1951
+ # LSP integration (extracted to install/lsp/integration.py)
1952
+ # -------------------------------------------------------------------------
1953
+ from apm_cli.install.lsp import run_lsp_integration
1954
+
1955
+ lsp_count = run_lsp_integration(
1956
+ apm_package=apm_package,
1957
+ apm_modules_path=apm_modules_path,
1958
+ lock_path=_lock_path,
1959
+ existing_lock=_existing_lock,
1960
+ project_root=ctx.project_root,
1961
+ user_scope=(ctx.scope is InstallScope.USER),
1962
+ should_install=should_install_lsp,
1963
+ logger=logger,
1964
+ diagnostics=apm_diagnostics,
1965
+ target_context=(mcp_apm_config, ctx.target, ctx.scope),
1966
+ )
1967
+
1948
1968
  # Local .apm/ content integration is now handled inside the
1949
1969
  # install pipeline (phases/integrate.py + phases/post_deps_local.py,
1950
1970
  # refactor F3). The duplicate target resolution, integrator
1951
1971
  # initialization, and inline stale-cleanup block that lived here
1952
1972
  # have been removed.
1953
1973
 
1954
- return apm_count, mcp_count, apm_diagnostics
1974
+ return apm_count, mcp_count, lsp_count, apm_diagnostics
1955
1975
 
1956
1976
 
1957
1977
  def _post_install_summary(
1958
- *, logger, apm_count, mcp_count, apm_diagnostics, force, elapsed_seconds=None
1978
+ *, logger, apm_count, mcp_count, lsp_count=0, apm_diagnostics, force, elapsed_seconds=None
1959
1979
  ):
1960
1980
  """Thin shim forwarding to :func:`apm_cli.install.summary.render_post_install_summary`.
1961
1981
 
@@ -1969,6 +1989,7 @@ def _post_install_summary(
1969
1989
  logger=logger,
1970
1990
  apm_count=apm_count,
1971
1991
  mcp_count=mcp_count,
1992
+ lsp_count=lsp_count,
1972
1993
  apm_diagnostics=apm_diagnostics,
1973
1994
  force=force,
1974
1995
  elapsed_seconds=elapsed_seconds,
@@ -8,6 +8,7 @@ from __future__ import annotations
8
8
 
9
9
  import builtins
10
10
  import json
11
+ import logging
11
12
  import re
12
13
  import sys
13
14
  import traceback
@@ -49,6 +50,8 @@ from ...marketplace.yml_schema import load_marketplace_yml
49
50
  from ...utils.path_security import PathTraversalError, validate_path_segments
50
51
  from .._helpers import _get_console, _is_interactive
51
52
 
53
+ logger = logging.getLogger(__name__)
54
+
52
55
  # Restore builtins shadowed by subcommand names
53
56
  list = builtins.list
54
57
 
@@ -83,6 +86,8 @@ class MarketplaceGroup(click.Group):
83
86
  "init",
84
87
  "check",
85
88
  "outdated",
89
+ "audit",
90
+ "doctor",
86
91
  "publish",
87
92
  "package",
88
93
  "migrate",
@@ -112,6 +117,8 @@ class MarketplaceGroup(click.Group):
112
117
  cmd = self.get_command(ctx, name)
113
118
  if cmd is None:
114
119
  continue
120
+ if getattr(cmd, "hidden", False):
121
+ continue
115
122
  help_text = cmd.get_short_help_str(limit=150)
116
123
  commands.append((name, help_text))
117
124
  if commands:
@@ -1025,15 +1032,36 @@ def _load_current_versions():
1025
1032
  def _extract_tag_versions(refs, entry, yml, include_prerelease):
1026
1033
  """Extract (SemVer, tag_name) pairs from remote refs for a package entry."""
1027
1034
  from ...marketplace._shared import iter_semver_tags
1028
- from ...marketplace.tag_pattern import build_tag_regex
1035
+ from ...marketplace.tag_pattern import (
1036
+ build_tag_regex,
1037
+ infer_tag_pattern_from_refs,
1038
+ )
1039
+
1040
+ def _collect(pattern: str) -> list:
1041
+ tag_rx = (
1042
+ build_tag_regex(pattern, name=entry.name)
1043
+ if "{name}" in pattern
1044
+ else build_tag_regex(pattern)
1045
+ )
1046
+ collected = []
1047
+ for sv, tag_name, _ in iter_semver_tags(refs, tag_rx):
1048
+ if sv.is_prerelease and not (include_prerelease or entry.include_prerelease):
1049
+ continue
1050
+ collected.append((sv, tag_name))
1051
+ return collected
1029
1052
 
1030
1053
  pattern = entry.tag_pattern or yml.build.tag_pattern
1031
- tag_rx = build_tag_regex(pattern)
1032
- results = []
1033
- for sv, tag_name, _ in iter_semver_tags(refs, tag_rx):
1034
- if sv.is_prerelease and not (include_prerelease or entry.include_prerelease):
1035
- continue
1036
- results.append((sv, tag_name))
1054
+ results = _collect(pattern)
1055
+ if not results:
1056
+ inferred = infer_tag_pattern_from_refs(refs, entry.name)
1057
+ if inferred and inferred != pattern:
1058
+ logger.debug(
1059
+ "Configured tag pattern %r matched no tags for %s; inferred %r",
1060
+ pattern,
1061
+ entry.name,
1062
+ inferred,
1063
+ )
1064
+ results = _collect(inferred)
1037
1065
  return results
1038
1066
 
1039
1067
 
@@ -1506,6 +1534,7 @@ def search(expression, limit, verbose):
1506
1534
  sys.exit(1)
1507
1535
 
1508
1536
 
1537
+ from .audit import audit # noqa: E402
1509
1538
  from .check import check # noqa: E402
1510
1539
  from .doctor import doctor # noqa: E402
1511
1540
  from .init import init # noqa: E402
@@ -1546,6 +1575,7 @@ __all__ = [
1546
1575
  "SemVer",
1547
1576
  "TargetResult",
1548
1577
  "add",
1578
+ "audit",
1549
1579
  "browse",
1550
1580
  "check",
1551
1581
  "detect_config_source",
@@ -0,0 +1,122 @@
1
+ """``apm marketplace audit`` command."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+ import traceback
7
+
8
+ import click
9
+
10
+ from ...core.command_logger import CommandLogger
11
+ from ...marketplace.audit import FetchStatus, run_audit
12
+ from ...marketplace.client import fetch_marketplace
13
+ from ...marketplace.registry import get_marketplace_by_name
14
+ from . import marketplace
15
+
16
+
17
+ @marketplace.command(help="Check that plugin dependencies resolve through the marketplace")
18
+ @click.argument("name", required=True)
19
+ @click.option(
20
+ "--strict",
21
+ is_flag=True,
22
+ help="Exit non-zero when any plugin has bypass dependencies or fetch errors",
23
+ )
24
+ @click.option("--verbose", "-v", is_flag=True, help="Show detailed output")
25
+ def audit(name, strict, verbose):
26
+ """Audit a registered marketplace's supply-chain pinning.
27
+
28
+ For each plugin in ``NAME``'s manifest, fetch the plugin's own
29
+ ``apm.yml`` (at its pinned ref) and warn when ``dependencies.apm``
30
+ entries use direct repo paths, which bypass the marketplace's
31
+ version pinning and make transitive deps track HEAD.
32
+ """
33
+ logger = CommandLogger("marketplace-audit", verbose=verbose)
34
+ try:
35
+ source = get_marketplace_by_name(name)
36
+ logger.start(f"Auditing marketplace '{name}'...", symbol="running")
37
+
38
+ manifest = fetch_marketplace(source, force_refresh=True)
39
+ n = len(manifest.plugins)
40
+ logger.progress(f"Checking {n} plugin{'' if n == 1 else 's'}...", symbol="info")
41
+
42
+ reports = run_audit(manifest, source)
43
+
44
+ ok_count = 0
45
+ bypass_total = 0
46
+ fetch_error_count = 0
47
+ skipped_count = 0
48
+
49
+ # Suppress the per-plugin section header when there is nothing to
50
+ # report and the user did not opt into verbose: in the all-clean
51
+ # default run the header would otherwise hang above an empty body.
52
+ has_findings = any(rep.fetch_status != FetchStatus.OK or rep.issues for rep in reports)
53
+
54
+ click.echo()
55
+ if has_findings or verbose:
56
+ click.echo("Audit Results:")
57
+ for rep in reports:
58
+ if rep.fetch_status == FetchStatus.OK:
59
+ if not rep.issues:
60
+ ok_count += 1
61
+ if verbose:
62
+ logger.success(
63
+ f" {rep.plugin_name}: deps are marketplace-resolved",
64
+ symbol="check",
65
+ )
66
+ continue
67
+ bypass_total += len(rep.issues)
68
+ if len(rep.issues) == 1:
69
+ verb_phrase = "1 dependency bypasses"
70
+ else:
71
+ verb_phrase = f"{len(rep.issues)} dependencies bypass"
72
+ logger.warning(
73
+ f" {rep.plugin_name}: {verb_phrase} the marketplace",
74
+ symbol="warning",
75
+ )
76
+ for issue in rep.issues:
77
+ click.echo(f" - '{issue.dep}'")
78
+ click.echo(f" hint: {issue.suggestion}")
79
+ elif rep.fetch_status in (
80
+ FetchStatus.NO_MANIFEST,
81
+ FetchStatus.UNSUPPORTED_SOURCE,
82
+ ):
83
+ skipped_count += 1
84
+ if verbose:
85
+ logger.verbose_detail(
86
+ f" {rep.plugin_name}: skipped ({rep.fetch_status.value}"
87
+ f"{' - ' + rep.detail if rep.detail else ''})"
88
+ )
89
+ else:
90
+ fetch_error_count += 1
91
+ logger.warning(
92
+ f" {rep.plugin_name}: could not verify "
93
+ f"({rep.fetch_status.value}: {rep.detail})",
94
+ symbol="warning",
95
+ )
96
+
97
+ click.echo()
98
+ warn_noun = "warning" if bypass_total == 1 else "warnings"
99
+ err_noun = "error" if fetch_error_count == 1 else "errors"
100
+ logger.success(
101
+ f"Summary: {ok_count} clean, {bypass_total} bypass {warn_noun}, "
102
+ f"{skipped_count} skipped, "
103
+ f"{fetch_error_count} unverifiable {err_noun}",
104
+ symbol="check",
105
+ )
106
+ if bypass_total:
107
+ click.echo()
108
+ click.echo(
109
+ "Marketplace refs (name@marketplace) pin transitive deps "
110
+ "through the catalogue so consumers get the same versions "
111
+ "you tested. See: "
112
+ "https://microsoft.github.io/apm/reference/cli/marketplace/#apm-marketplace-audit-name"
113
+ )
114
+
115
+ if strict and (bypass_total or fetch_error_count):
116
+ sys.exit(1)
117
+
118
+ except Exception as e:
119
+ logger.error(f"Failed to audit marketplace: {e}")
120
+ logger.info("Run with --verbose for details.")
121
+ logger.verbose_detail(traceback.format_exc())
122
+ sys.exit(1)
@@ -16,12 +16,15 @@ from ..deps.outdated_row import OutdatedRow
16
16
 
17
17
  logger = logging.getLogger(__name__)
18
18
 
19
+ # Fallback heuristic for _resolve_tag_pattern when inference misses plain tags.
19
20
  TAG_RE = re.compile(r"^v?\d+\.\d+\.\d+")
20
21
 
21
22
 
22
- def _is_tag_ref(ref: str) -> bool:
23
- """Return True when *ref* looks like a semver tag (v1.2.3 or 1.2.3)."""
24
- return bool(TAG_RE.match(ref)) if ref else False
23
+ def _is_tag_ref(ref: str, package_name: str | None = None) -> bool:
24
+ """Return True when *ref* names a version tag (plain or patterned)."""
25
+ from ..marketplace.tag_pattern import is_version_tag_ref
26
+
27
+ return is_version_tag_ref(ref, package_name)
25
28
 
26
29
 
27
30
  def _strip_v(ref: str) -> str:
@@ -29,6 +32,57 @@ def _strip_v(ref: str) -> str:
29
32
  return ref[1:] if ref and ref.startswith("v") else (ref or "")
30
33
 
31
34
 
35
+ def _package_basename(dep) -> str:
36
+ """Return the display name used in ``{name}`` tag patterns."""
37
+ if dep.marketplace_plugin_name:
38
+ return dep.marketplace_plugin_name
39
+ repo = dep.repo_url or ""
40
+ if not repo:
41
+ return ""
42
+ return repo.rstrip("/").split("/")[-1]
43
+
44
+
45
+ def _resolve_tag_pattern(current_ref: str, package_name: str) -> str | None:
46
+ """Return the tag pattern for *current_ref*, or ``None`` if not a version tag."""
47
+ from ..marketplace.tag_pattern import infer_tag_pattern
48
+
49
+ inferred = infer_tag_pattern(current_ref, package_name)
50
+ if inferred:
51
+ logger.debug(
52
+ "Resolved tag pattern %r for %s from ref %s",
53
+ inferred,
54
+ package_name,
55
+ current_ref,
56
+ )
57
+ return inferred
58
+ if TAG_RE.match(current_ref or ""):
59
+ return "v{version}" if (current_ref or "").startswith("v") else "{version}"
60
+ return None
61
+
62
+
63
+ def _semver_tag_candidates(tag_refs, pattern: str, package_name: str = ""):
64
+ """Return ``(SemVer, tag_name)`` pairs matching *pattern*, highest first."""
65
+ from ..marketplace.semver import SemVer, parse_semver
66
+ from ..marketplace.tag_pattern import build_tag_regex
67
+
68
+ tag_rx = (
69
+ build_tag_regex(pattern, name=package_name)
70
+ if "{name}" in pattern and package_name
71
+ else build_tag_regex(pattern)
72
+ )
73
+ candidates: list[tuple[SemVer, str]] = []
74
+ for remote_ref in tag_refs:
75
+ match = tag_rx.match(remote_ref.name)
76
+ if not match:
77
+ continue
78
+ version = match.group("version")
79
+ parsed = parse_semver(version)
80
+ if parsed is not None:
81
+ candidates.append((parsed, remote_ref.name))
82
+ candidates.sort(key=lambda pair: pair[0], reverse=True)
83
+ return candidates
84
+
85
+
32
86
  def _find_remote_tip(ref_name, remote_refs):
33
87
  """Find the tip SHA for a branch ref from remote refs.
34
88
 
@@ -189,7 +243,9 @@ def _check_one_dep(dep, downloader, verbose, registry_ctx=None):
189
243
  package=package_name, current=current_ref or "(none)", latest="-", status="unknown"
190
244
  )
191
245
 
192
- is_tag = _is_tag_ref(current_ref)
246
+ package_basename = _package_basename(dep)
247
+ tag_pattern = _resolve_tag_pattern(current_ref, package_basename)
248
+ is_tag = tag_pattern is not None
193
249
 
194
250
  if is_tag:
195
251
  tag_refs = [r for r in remote_refs if r.ref_type == GitReferenceType.TAG]
@@ -202,12 +258,28 @@ def _check_one_dep(dep, downloader, verbose, registry_ctx=None):
202
258
  source="git tags",
203
259
  )
204
260
 
205
- latest_tag = tag_refs[0].name
206
- current_ver = _strip_v(current_ref)
207
- latest_ver = _strip_v(latest_tag)
261
+ from ..marketplace.tag_pattern import parse_tag_version
262
+
263
+ candidates = _semver_tag_candidates(tag_refs, tag_pattern, package_basename)
264
+ if not candidates:
265
+ return OutdatedRow(
266
+ package=package_name,
267
+ current=current_ref,
268
+ latest="-",
269
+ status="unknown",
270
+ source="git tags",
271
+ )
272
+
273
+ _, latest_tag = candidates[0]
274
+ current_ver = parse_tag_version(
275
+ current_ref, tag_pattern, name=package_basename
276
+ ) or _strip_v(current_ref)
277
+ latest_ver = parse_tag_version(latest_tag, tag_pattern, name=package_basename) or _strip_v(
278
+ latest_tag
279
+ )
208
280
 
209
281
  if is_newer_version(current_ver, latest_ver):
210
- extra = [r.name for r in tag_refs[:10]] if verbose else []
282
+ extra = [name for _, name in candidates[:10]] if verbose else []
211
283
  return OutdatedRow(
212
284
  package=package_name,
213
285
  current=current_ref,