apm-cli 0.17.0__tar.gz → 0.19.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 (387) hide show
  1. {apm_cli-0.17.0 → apm_cli-0.19.0}/AUTHORS +1 -0
  2. {apm_cli-0.17.0/src/apm_cli.egg-info → apm_cli-0.19.0}/PKG-INFO +1 -1
  3. {apm_cli-0.17.0 → apm_cli-0.19.0}/pyproject.toml +1 -1
  4. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/base.py +28 -12
  5. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/claude.py +1 -6
  6. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/codex.py +1 -13
  7. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/copilot.py +13 -26
  8. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/intellij.py +11 -6
  9. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/bundle/lockfile_enrichment.py +3 -0
  10. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/cli.py +57 -1
  11. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/audit.py +82 -23
  12. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/compile/cli.py +14 -3
  13. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/experimental.py +2 -2
  14. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/install.py +28 -7
  15. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/__init__.py +37 -7
  16. apm_cli-0.19.0/src/apm_cli/commands/marketplace/audit.py +122 -0
  17. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/outdated.py +80 -8
  18. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/publish.py +34 -34
  19. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/compilation/agents_compiler.py +25 -8
  20. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/compilation/context_optimizer.py +28 -9
  21. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/compilation/link_resolver.py +18 -1
  22. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/auth.py +148 -18
  23. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/command_logger.py +5 -0
  24. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/experimental.py +10 -0
  25. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/safe_installer.py +2 -0
  26. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/target_detection.py +31 -1
  27. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/apm_resolver.py +111 -0
  28. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/dependency_graph.py +1 -0
  29. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/download_strategies.py +48 -3
  30. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/git_semver_resolver.py +9 -5
  31. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/lockfile.py +13 -1
  32. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/plugin_parser.py +276 -12
  33. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/context.py +1 -0
  34. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/drift.py +19 -2
  35. apm_cli-0.19.0/src/apm_cli/install/lsp/__init__.py +5 -0
  36. apm_cli-0.19.0/src/apm_cli/install/lsp/integration.py +148 -0
  37. apm_cli-0.19.0/src/apm_cli/install/manifest_reconcile.py +112 -0
  38. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/local_content.py +109 -13
  39. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/lockfile.py +46 -10
  40. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/post_deps_local.py +17 -3
  41. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/resolve.py +33 -2
  42. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/targets.py +248 -268
  43. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/pipeline.py +3 -0
  44. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/services.py +88 -4
  45. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/summary.py +4 -1
  46. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/__init__.py +2 -0
  47. apm_cli-0.19.0/src/apm_cli/integration/_shared.py +71 -0
  48. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/base_integrator.py +15 -2
  49. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/hook_integrator.py +131 -4
  50. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/instruction_integrator.py +83 -21
  51. apm_cli-0.19.0/src/apm_cli/integration/lsp_integrator.py +508 -0
  52. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/mcp_integrator.py +4 -41
  53. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/mcp_integrator_install.py +1 -28
  54. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/skill_integrator.py +74 -10
  55. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/targets.py +103 -3
  56. apm_cli-0.19.0/src/apm_cli/marketplace/audit.py +337 -0
  57. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/client.py +96 -14
  58. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/resolver.py +59 -10
  59. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/tag_pattern.py +80 -3
  60. apm_cli-0.19.0/src/apm_cli/marketplace/version_resolver.py +114 -0
  61. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/models/apm_package.py +33 -0
  62. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/models/dependency/__init__.py +2 -0
  63. apm_cli-0.19.0/src/apm_cli/models/dependency/lsp.py +229 -0
  64. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/models/dependency/mcp.py +29 -1
  65. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/models/dependency/reference.py +135 -3
  66. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/security/external/skillspector.py +18 -5
  67. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/exclude.py +10 -0
  68. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/github_host.py +24 -5
  69. {apm_cli-0.17.0 → apm_cli-0.19.0/src/apm_cli.egg-info}/PKG-INFO +1 -1
  70. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli.egg-info/SOURCES.txt +9 -0
  71. {apm_cli-0.17.0 → apm_cli-0.19.0}/tests/test_apm_package_models.py +156 -0
  72. {apm_cli-0.17.0 → apm_cli-0.19.0}/tests/test_apm_resolver.py +192 -1
  73. {apm_cli-0.17.0 → apm_cli-0.19.0}/tests/test_lockfile.py +55 -0
  74. {apm_cli-0.17.0 → apm_cli-0.19.0}/LICENSE +0 -0
  75. {apm_cli-0.17.0 → apm_cli-0.19.0}/NOTICE +0 -0
  76. {apm_cli-0.17.0 → apm_cli-0.19.0}/README.md +0 -0
  77. {apm_cli-0.17.0 → apm_cli-0.19.0}/setup.cfg +0 -0
  78. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/__init__.py +0 -0
  79. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/adapters/__init__.py +0 -0
  80. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/__init__.py +0 -0
  81. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/_mcp_runtime_args.py +0 -0
  82. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/cursor.py +0 -0
  83. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/gemini.py +0 -0
  84. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/opencode.py +0 -0
  85. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/vscode.py +0 -0
  86. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/windsurf.py +0 -0
  87. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/adapters/package_manager/__init__.py +0 -0
  88. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/adapters/package_manager/base.py +0 -0
  89. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/adapters/package_manager/default_manager.py +0 -0
  90. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/bundle/__init__.py +0 -0
  91. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/bundle/local_bundle.py +0 -0
  92. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/bundle/packer.py +0 -0
  93. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/bundle/plugin_exporter.py +0 -0
  94. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/bundle/unpacker.py +0 -0
  95. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/cache/__init__.py +0 -0
  96. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/cache/git_cache.py +0 -0
  97. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/cache/http_cache.py +0 -0
  98. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/cache/integrity.py +0 -0
  99. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/cache/locking.py +0 -0
  100. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/cache/paths.py +0 -0
  101. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/cache/url_normalize.py +0 -0
  102. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/__init__.py +0 -0
  103. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/_apm_yml_writer.py +0 -0
  104. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/_helpers.py +0 -0
  105. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/cache.py +0 -0
  106. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/compile/__init__.py +0 -0
  107. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/compile/watcher.py +0 -0
  108. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/config.py +0 -0
  109. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/deps/__init__.py +0 -0
  110. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/deps/_utils.py +0 -0
  111. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/deps/cli.py +0 -0
  112. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/deps/why.py +0 -0
  113. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/doctor.py +0 -0
  114. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/find.py +0 -0
  115. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/init.py +0 -0
  116. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/list_cmd.py +0 -0
  117. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/lock.py +0 -0
  118. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/check.py +0 -0
  119. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/doctor.py +0 -0
  120. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/init.py +0 -0
  121. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/migrate.py +0 -0
  122. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/outdated.py +0 -0
  123. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/plugin/__init__.py +0 -0
  124. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/plugin/add.py +0 -0
  125. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/plugin/remove.py +0 -0
  126. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/plugin/set.py +0 -0
  127. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/publish.py +0 -0
  128. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/validate.py +0 -0
  129. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/mcp.py +0 -0
  130. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/pack.py +0 -0
  131. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/plugin/__init__.py +0 -0
  132. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/plugin/init.py +0 -0
  133. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/policy.py +0 -0
  134. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/prune.py +0 -0
  135. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/run.py +0 -0
  136. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/runtime.py +0 -0
  137. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/self_update.py +0 -0
  138. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/targets.py +0 -0
  139. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/uninstall/__init__.py +0 -0
  140. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/uninstall/cli.py +0 -0
  141. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/uninstall/engine.py +0 -0
  142. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/update.py +0 -0
  143. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/commands/view.py +0 -0
  144. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/compilation/__init__.py +0 -0
  145. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/compilation/build_id.py +0 -0
  146. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/compilation/claude_formatter.py +0 -0
  147. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/compilation/constants.py +0 -0
  148. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/compilation/constitution.py +0 -0
  149. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/compilation/constitution_block.py +0 -0
  150. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/compilation/distributed_compiler.py +0 -0
  151. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/compilation/gemini_formatter.py +0 -0
  152. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/compilation/injector.py +0 -0
  153. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/compilation/managed_section.py +0 -0
  154. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/compilation/output_writer.py +0 -0
  155. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/compilation/template_builder.py +0 -0
  156. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/config.py +0 -0
  157. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/constants.py +0 -0
  158. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/__init__.py +0 -0
  159. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/apm_yml.py +0 -0
  160. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/azure_cli.py +0 -0
  161. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/build_orchestrator.py +0 -0
  162. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/conflict_detector.py +0 -0
  163. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/docker_args.py +0 -0
  164. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/errors.py +0 -0
  165. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/install_audit.py +0 -0
  166. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/null_logger.py +0 -0
  167. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/operations.py +0 -0
  168. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/plugin_manifest.py +0 -0
  169. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/scope.py +0 -0
  170. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/script_runner.py +0 -0
  171. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/core/token_manager.py +0 -0
  172. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/__init__.py +0 -0
  173. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/_shared.py +0 -0
  174. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/aggregator.py +0 -0
  175. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/artifactory_entry.py +0 -0
  176. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/artifactory_orchestrator.py +0 -0
  177. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/bare_cache.py +0 -0
  178. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/clone_engine.py +0 -0
  179. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/git_auth_env.py +0 -0
  180. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/git_reference_resolver.py +0 -0
  181. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/git_remote_ops.py +0 -0
  182. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/github_downloader.py +0 -0
  183. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/github_downloader_validation.py +0 -0
  184. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/host_backends.py +0 -0
  185. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/installed_package.py +0 -0
  186. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/outdated_row.py +0 -0
  187. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/package_validator.py +0 -0
  188. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/path_anchoring.py +0 -0
  189. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/__init__.py +0 -0
  190. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/auth.py +0 -0
  191. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/client.py +0 -0
  192. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/config_loader.py +0 -0
  193. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/extractor.py +0 -0
  194. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/feature_gate.py +0 -0
  195. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/outdated.py +0 -0
  196. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/resolver.py +0 -0
  197. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/semver.py +0 -0
  198. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry_proxy.py +0 -0
  199. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/shared_clone_cache.py +0 -0
  200. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/tiered_ref_resolver.py +0 -0
  201. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/transport_selection.py +0 -0
  202. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/verifier.py +0 -0
  203. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/deps/why_walker.py +0 -0
  204. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/drift.py +0 -0
  205. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/factory.py +0 -0
  206. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/__init__.py +0 -0
  207. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/artifactory_resolver.py +0 -0
  208. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/cache_pin.py +0 -0
  209. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/errors.py +0 -0
  210. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/gitlab_resolver.py +0 -0
  211. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/heals/__init__.py +0 -0
  212. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/heals/base.py +0 -0
  213. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/heals/branch_ref_drift.py +0 -0
  214. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/heals/buggy_lockfile_recovery.py +0 -0
  215. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/helpers/__init__.py +0 -0
  216. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/helpers/security_scan.py +0 -0
  217. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/insecure_policy.py +0 -0
  218. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/local_bundle_handler.py +0 -0
  219. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/__init__.py +0 -0
  220. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/args.py +0 -0
  221. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/command.py +0 -0
  222. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/conflicts.py +0 -0
  223. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/entry.py +0 -0
  224. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/registry.py +0 -0
  225. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/warnings.py +0 -0
  226. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/writer.py +0 -0
  227. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/package_resolution.py +0 -0
  228. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/package_selection.py +0 -0
  229. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/__init__.py +0 -0
  230. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/_redownload.py +0 -0
  231. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/_skip_logic.py +0 -0
  232. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/audit.py +0 -0
  233. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/cleanup.py +0 -0
  234. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/download.py +0 -0
  235. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/finalize.py +0 -0
  236. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/heal.py +0 -0
  237. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/integrate.py +0 -0
  238. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/policy_gate.py +0 -0
  239. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/policy_target_check.py +0 -0
  240. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/plan.py +0 -0
  241. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/presentation/__init__.py +0 -0
  242. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/presentation/dry_run.py +0 -0
  243. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/registry_wiring.py +0 -0
  244. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/request.py +0 -0
  245. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/root_redirect.py +0 -0
  246. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/service.py +0 -0
  247. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/skill_path_migration.py +0 -0
  248. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/sources.py +0 -0
  249. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/template.py +0 -0
  250. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/install/validation.py +0 -0
  251. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/agent_integrator.py +0 -0
  252. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/cleanup.py +0 -0
  253. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/command_integrator.py +0 -0
  254. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/copilot_app_db.py +0 -0
  255. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/copilot_app_project.py +0 -0
  256. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/copilot_app_workflow_integrator.py +0 -0
  257. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/copilot_app_ws.py +0 -0
  258. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/copilot_cowork_paths.py +0 -0
  259. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/coverage.py +0 -0
  260. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/dispatch.py +0 -0
  261. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/opencode_frontmatter.py +0 -0
  262. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/prompt_integrator.py +0 -0
  263. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/skill_transformer.py +0 -0
  264. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/integration/utils.py +0 -0
  265. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/__init__.py +0 -0
  266. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/_git_utils.py +0 -0
  267. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/_io.py +0 -0
  268. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/_shared.py +0 -0
  269. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/builder.py +0 -0
  270. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/diagnostics.py +0 -0
  271. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/drift_check.py +0 -0
  272. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/errors.py +0 -0
  273. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/git_stderr.py +0 -0
  274. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/init_template.py +0 -0
  275. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/migration.py +0 -0
  276. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/models.py +0 -0
  277. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/output_mappers.py +0 -0
  278. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/output_profiles.py +0 -0
  279. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/pr_integration.py +0 -0
  280. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/publisher.py +0 -0
  281. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/ref_resolver.py +0 -0
  282. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/registry.py +0 -0
  283. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/semver.py +0 -0
  284. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/shadow_detector.py +0 -0
  285. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/validator.py +0 -0
  286. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/version_check.py +0 -0
  287. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/version_pins.py +0 -0
  288. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/yml_editor.py +0 -0
  289. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/yml_schema.py +0 -0
  290. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/models/__init__.py +0 -0
  291. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/models/dependency/types.py +0 -0
  292. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/models/format_detection.py +0 -0
  293. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/models/plugin.py +0 -0
  294. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/models/results.py +0 -0
  295. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/models/validation.py +0 -0
  296. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/output/__init__.py +0 -0
  297. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/output/formatters.py +0 -0
  298. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/output/models.py +0 -0
  299. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/output/script_formatters.py +0 -0
  300. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/policy/__init__.py +0 -0
  301. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/policy/_constraint_pinning.py +0 -0
  302. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/policy/_help_text.py +0 -0
  303. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/policy/_shared.py +0 -0
  304. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/policy/ci_checks.py +0 -0
  305. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/policy/discovery.py +0 -0
  306. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/policy/inheritance.py +0 -0
  307. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/policy/install_preflight.py +0 -0
  308. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/policy/matcher.py +0 -0
  309. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/policy/models.py +0 -0
  310. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/policy/outcome_routing.py +0 -0
  311. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/policy/parser.py +0 -0
  312. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/policy/policy_checks.py +0 -0
  313. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/policy/project_config.py +0 -0
  314. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/policy/schema.py +0 -0
  315. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/primitives/__init__.py +0 -0
  316. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/primitives/discovery.py +0 -0
  317. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/primitives/models.py +0 -0
  318. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/primitives/parser.py +0 -0
  319. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/registry/__init__.py +0 -0
  320. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/registry/client.py +0 -0
  321. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/registry/integration.py +0 -0
  322. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/registry/operations.py +0 -0
  323. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/runtime/__init__.py +0 -0
  324. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/runtime/base.py +0 -0
  325. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/runtime/codex_runtime.py +0 -0
  326. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/runtime/copilot_runtime.py +0 -0
  327. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/runtime/factory.py +0 -0
  328. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/runtime/llm_runtime.py +0 -0
  329. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/runtime/manager.py +0 -0
  330. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/runtime/utils.py +0 -0
  331. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/security/__init__.py +0 -0
  332. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/security/audit_report.py +0 -0
  333. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/security/content_scanner.py +0 -0
  334. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/security/external/__init__.py +0 -0
  335. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/security/external/base.py +0 -0
  336. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/security/external/gate.py +0 -0
  337. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/security/external/generic_sarif.py +0 -0
  338. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/security/external/options.py +0 -0
  339. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/security/external/registry.py +0 -0
  340. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/security/external/runner.py +0 -0
  341. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/security/external/sarif_ingest.py +0 -0
  342. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/security/file_scanner.py +0 -0
  343. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/security/gate.py +0 -0
  344. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/update_policy.py +0 -0
  345. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/__init__.py +0 -0
  346. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/atomic_io.py +0 -0
  347. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/console.py +0 -0
  348. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/content_hash.py +0 -0
  349. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/diagnostics.py +0 -0
  350. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/file_ops.py +0 -0
  351. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/git_env.py +0 -0
  352. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/git_sparse.py +0 -0
  353. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/guards.py +0 -0
  354. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/helpers.py +0 -0
  355. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/install_tui.py +0 -0
  356. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/normalization.py +0 -0
  357. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/path_security.py +0 -0
  358. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/paths.py +0 -0
  359. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/patterns.py +0 -0
  360. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/perf_stats.py +0 -0
  361. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/reflink.py +0 -0
  362. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/short_sha.py +0 -0
  363. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/subprocess_env.py +0 -0
  364. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/version_checker.py +0 -0
  365. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/utils/yaml_io.py +0 -0
  366. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/version.py +0 -0
  367. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/workflow/__init__.py +0 -0
  368. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/workflow/discovery.py +0 -0
  369. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/workflow/parser.py +0 -0
  370. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli/workflow/runner.py +0 -0
  371. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli.egg-info/dependency_links.txt +0 -0
  372. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli.egg-info/entry_points.txt +0 -0
  373. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli.egg-info/requires.txt +0 -0
  374. {apm_cli-0.17.0 → apm_cli-0.19.0}/src/apm_cli.egg-info/top_level.txt +0 -0
  375. {apm_cli-0.17.0 → apm_cli-0.19.0}/tests/test_codex_docker_args_fix.py +0 -0
  376. {apm_cli-0.17.0 → apm_cli-0.19.0}/tests/test_codex_empty_string_and_defaults.py +0 -0
  377. {apm_cli-0.17.0 → apm_cli-0.19.0}/tests/test_collision_integration.py +0 -0
  378. {apm_cli-0.17.0 → apm_cli-0.19.0}/tests/test_console.py +0 -0
  379. {apm_cli-0.17.0 → apm_cli-0.19.0}/tests/test_distributed_compilation.py +0 -0
  380. {apm_cli-0.17.0 → apm_cli-0.19.0}/tests/test_empty_string_and_defaults.py +0 -0
  381. {apm_cli-0.17.0 → apm_cli-0.19.0}/tests/test_enhanced_discovery.py +0 -0
  382. {apm_cli-0.17.0 → apm_cli-0.19.0}/tests/test_github_downloader.py +0 -0
  383. {apm_cli-0.17.0 → apm_cli-0.19.0}/tests/test_github_downloader_token_precedence.py +0 -0
  384. {apm_cli-0.17.0 → apm_cli-0.19.0}/tests/test_runnable_prompts.py +0 -0
  385. {apm_cli-0.17.0 → apm_cli-0.19.0}/tests/test_runtime_manager_token_precedence.py +0 -0
  386. {apm_cli-0.17.0 → apm_cli-0.19.0}/tests/test_token_manager.py +0 -0
  387. {apm_cli-0.17.0 → apm_cli-0.19.0}/tests/test_virtual_package_multi_install.py +0 -0
@@ -4,6 +4,7 @@
4
4
 
5
5
  * Daniel Meppiel (@danielmeppiel) — Microsoft
6
6
  * Sergio Sisternes (@sergio-sisternes-epam) — EPAM Systems
7
+ * Nadav Yogev (@nadav-y) — JFrog
7
8
 
8
9
  Maintainers' work on APM is supported by their employers. Project
9
10
  decisions are made in the interest of APM and its users, independent
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: apm-cli
3
- Version: 0.17.0
3
+ Version: 0.19.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.19.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.
@@ -620,22 +633,25 @@ class MCPClientAdapter(ABC):
620
633
  return server_info
621
634
 
622
635
  @staticmethod
623
- def _determine_config_key(server_url: str, server_name: str) -> str:
636
+ def _determine_config_key(server_url: str, server_name: str | None) -> str:
624
637
  """Return the configuration key to use for *server_url*/*server_name*.
625
638
 
626
- The caller-supplied *server_name* takes precedence; if empty the last
627
- path segment of *server_url* is used as a fallback, which mirrors the
628
- convention ``owner/repo -> repo``.
639
+ The caller-supplied *server_name* takes precedence. If it is absent,
640
+ preserve npm-style scoped names such as ``@scope/name`` (one slash by
641
+ npm convention) while keeping the historical ``owner/repo -> repo``
642
+ fallback for registry paths.
629
643
 
630
644
  Args:
631
645
  server_url: Registry reference used as fallback source.
632
- server_name: Explicit caller-supplied name (may be empty string).
646
+ server_name: Explicit caller-supplied name, if any.
633
647
 
634
648
  Returns:
635
649
  Non-empty configuration key string.
636
650
  """
637
651
  if server_name:
638
652
  return server_name
653
+ if server_url.startswith("@") and server_url.count("/") == 1:
654
+ return server_url
639
655
  if "/" in server_url:
640
656
  return server_url.split("/")[-1]
641
657
  return server_url
@@ -239,12 +239,7 @@ class ClaudeClientAdapter(CopilotClientAdapter):
239
239
  _rich_error(f"MCP server '{server_url}' not found in registry")
240
240
  return False
241
241
 
242
- if server_name:
243
- config_key = server_name
244
- elif "/" in server_url:
245
- config_key = server_url.split("/")[-1]
246
- else:
247
- config_key = server_url
242
+ config_key = self._determine_config_key(server_url, server_name)
248
243
 
249
244
  server_config = self._format_server_config(server_info, env_overrides, runtime_vars)
250
245
  ok = self.update_config({config_key: server_config})
@@ -150,19 +150,7 @@ class CodexClientAdapter(MCPClientAdapter):
150
150
  if server_info is None:
151
151
  return False
152
152
 
153
- # Determine the server name for configuration key
154
- if server_name:
155
- # Use explicitly provided server name
156
- config_key = server_name
157
- else: # noqa: PLR5501
158
- # Extract name from server_url (part after last slash)
159
- # For URLs like "microsoft/azure-devops-mcp" -> "azure-devops-mcp"
160
- # For URLs like "github/github-mcp-server" -> "github-mcp-server"
161
- if "/" in server_url: # noqa: SIM108
162
- config_key = server_url.split("/")[-1]
163
- else:
164
- # Fallback to full server_url if no slash
165
- config_key = server_url
153
+ config_key = self._determine_config_key(server_url, server_name)
166
154
 
167
155
  # Generate server configuration with environment variable resolution
168
156
  server_config = self._format_server_config(server_info, env_overrides, runtime_vars)
@@ -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
 
@@ -204,19 +206,7 @@ class CopilotClientAdapter(MCPClientAdapter):
204
206
  # Generate server configuration with environment and runtime variable resolution
205
207
  server_config = self._format_server_config(server_info, env_overrides, runtime_vars)
206
208
 
207
- # Determine the server name for configuration key
208
- if server_name:
209
- # Use explicitly provided server name
210
- config_key = server_name
211
- else: # noqa: PLR5501
212
- # Extract name from server_url (part after last slash)
213
- # For URLs like "microsoft/azure-devops-mcp" -> "azure-devops-mcp"
214
- # For URLs like "github/github-mcp-server" -> "github-mcp-server"
215
- if "/" in server_url: # noqa: SIM108
216
- config_key = server_url.split("/")[-1]
217
- else:
218
- # Fallback to full server_url if no slash
219
- config_key = server_url
209
+ config_key = self._determine_config_key(server_url, server_name)
220
210
 
221
211
  # Update configuration using the chosen key
222
212
  self.update_config({config_key: server_config})
@@ -678,9 +668,9 @@ class CopilotClientAdapter(MCPClientAdapter):
678
668
  # ({NAME: value-or-placeholder}); registry-sourced deps pass a list
679
669
  # of {name, description, required} dicts. Translate-mode handling
680
670
  # 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.
671
+ # (translate it to the adapter's runtime form) or a literal
672
+ # (record the key as a placeholder reference and emit a runtime
673
+ # placeholder so the value never lands on disk). See issue #1152.
684
674
  if isinstance(env_vars, dict) and self._supports_runtime_env_substitution:
685
675
  translated = {}
686
676
  placeholder_keys = []
@@ -694,9 +684,7 @@ class CopilotClientAdapter(MCPClientAdapter):
694
684
  continue
695
685
  if _has_env_placeholder(raw_value):
696
686
  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).
687
+ translated[name] = self._translate_env_placeholder_for_runtime(raw_value)
700
688
  for match in _ENV_VAR_RE.finditer(translated[name]):
701
689
  placeholder_keys.append(match.group(1))
702
690
  elif name in default_github_env and raw_value == default_github_env[name]:
@@ -704,7 +692,7 @@ class CopilotClientAdapter(MCPClientAdapter):
704
692
  else:
705
693
  # Literal value present in apm.yml -- replace with a
706
694
  # runtime placeholder so the secret never touches disk.
707
- translated[name] = "${" + name + "}"
695
+ translated[name] = self._format_runtime_env_placeholder(name)
708
696
  placeholder_keys.append(name)
709
697
  self._last_env_placeholder_keys = set(placeholder_keys)
710
698
  return translated
@@ -722,10 +710,9 @@ class CopilotClientAdapter(MCPClientAdapter):
722
710
  # Non-secret literal default -- preserve as-is.
723
711
  resolved[name] = default_github_env[name]
724
712
  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 + "}"
713
+ # Emit a runtime-substitution placeholder; APM never reads
714
+ # or stores the value.
715
+ resolved[name] = self._format_runtime_env_placeholder(name)
729
716
  placeholder_keys.append(name)
730
717
  # Record for the post-install summary line and the
731
718
  # security-improvement notice.
@@ -783,7 +770,7 @@ class CopilotClientAdapter(MCPClientAdapter):
783
770
  # them (the env-block path tracks via _resolve_environment_variables).
784
771
  for match in _ENV_VAR_RE.finditer(value):
785
772
  self._last_env_placeholder_keys.add(match.group(1))
786
- return _translate_env_placeholder(value)
773
+ return self._translate_env_placeholder_for_runtime(value)
787
774
 
788
775
  import sys
789
776
 
@@ -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
@@ -51,6 +51,9 @@ _CROSS_TARGET_MAPS: dict[str, dict[str, str]] = {
51
51
  "agent-skills": {
52
52
  ".github/skills/": ".agents/skills/",
53
53
  },
54
+ "openclaw": {
55
+ ".github/skills/": ".agents/skills/",
56
+ },
54
57
  }
55
58
 
56
59
 
@@ -4,6 +4,7 @@ Thin wiring layer -- all command logic lives in ``apm_cli.commands.*`` modules.
4
4
  """
5
5
 
6
6
  import ctypes
7
+ import logging
7
8
  import os
8
9
  import sys
9
10
  import warnings
@@ -61,6 +62,48 @@ _CLI_EPILOG = (
61
62
  )
62
63
 
63
64
 
65
+ def _configure_logging(verbose: bool = False) -> None:
66
+ """Configure stdlib logging for the ``apm_cli`` package.
67
+
68
+ Two mechanisms activate debug-level output (either is sufficient):
69
+
70
+ * ``--verbose`` / ``-v`` flag on the ``apm`` command.
71
+ * ``APM_LOG_LEVEL=DEBUG`` environment variable (accepts any stdlib
72
+ level name: DEBUG, INFO, WARNING, ERROR, CRITICAL).
73
+
74
+ When neither is set the ``apm_cli`` logger defaults to WARNING so
75
+ routine runs stay silent. A :class:`~apm_cli.core.auth.SecretRedactionFilter`
76
+ is always installed on the ``apm_cli`` logger to strip token-bearing
77
+ exception strings from debug records regardless of which mechanism
78
+ activated debug mode.
79
+ """
80
+ env_level_str = os.environ.get("APM_LOG_LEVEL", "").strip().upper()
81
+ env_level: int | None = (
82
+ getattr(logging, env_level_str, None) if env_level_str.isalpha() else None
83
+ )
84
+
85
+ if verbose:
86
+ level = logging.DEBUG
87
+ elif env_level is not None:
88
+ level = env_level
89
+ else:
90
+ level = logging.WARNING
91
+
92
+ logging.basicConfig(
93
+ level=level,
94
+ format="%(levelname)s %(name)s %(message)s",
95
+ stream=sys.stderr,
96
+ )
97
+ apm_logger = logging.getLogger("apm_cli")
98
+ apm_logger.setLevel(level)
99
+
100
+ # Install secret-redaction filter (idempotent: skip if already present).
101
+ from apm_cli.core.auth import SecretRedactionFilter
102
+
103
+ if not any(isinstance(f, SecretRedactionFilter) for f in apm_logger.filters):
104
+ apm_logger.addFilter(SecretRedactionFilter())
105
+
106
+
64
107
  @click.group(
65
108
  help="Agent Package Manager (APM): The package manager for AI-Native Development",
66
109
  epilog=_CLI_EPILOG,
@@ -73,10 +116,22 @@ _CLI_EPILOG = (
73
116
  is_eager=True,
74
117
  help="Show version and exit.",
75
118
  )
119
+ @click.option(
120
+ "--verbose",
121
+ "-v",
122
+ is_flag=True,
123
+ default=False,
124
+ help="Enable debug-level logging (equivalent to APM_LOG_LEVEL=DEBUG).",
125
+ )
76
126
  @click.pass_context
77
- def cli(ctx):
127
+ def cli(ctx, verbose: bool) -> None:
78
128
  """Main entry point for the APM CLI."""
79
129
  ctx.ensure_object(dict)
130
+ ctx.obj["verbose"] = verbose
131
+
132
+ if verbose:
133
+ # Upgrade to DEBUG when the flag is set; env-var path runs in main().
134
+ _configure_logging(verbose=True)
80
135
 
81
136
  # Suppress only the agents-target deprecation warning so CLI users see
82
137
  # the formatted logger.warning() in the install phase, not a double print.
@@ -267,6 +322,7 @@ def _configure_encoding() -> None:
267
322
 
268
323
  def main():
269
324
  """Main entry point for the CLI."""
325
+ _configure_logging() # honours APM_LOG_LEVEL env var; --verbose upgrades in cli()
270
326
  _configure_encoding()
271
327
  try:
272
328
  cli(obj={})
@@ -103,6 +103,39 @@ def _has_actionable_findings(
103
103
  )
104
104
 
105
105
 
106
+ def _finding_source(finding: ScanFinding) -> str:
107
+ """Derive the scanner source from a finding's category prefix."""
108
+ if "/" in finding.category:
109
+ prefix = finding.category.split("/", 1)[0]
110
+ if prefix != "apm":
111
+ return prefix
112
+ return "apm"
113
+
114
+
115
+ def _has_external_findings(rows: list[ScanFinding]) -> bool:
116
+ """Return True if any finding originates from an external scanner."""
117
+ return any(_finding_source(f) != "apm" for f in rows)
118
+
119
+
120
+ def _source_counts(rows: list[ScanFinding]) -> dict[str, int]:
121
+ """Count findings by source for the table title."""
122
+ counts: dict[str, int] = {}
123
+ for f in rows:
124
+ src = _finding_source(f)
125
+ counts[src] = counts.get(src, 0) + 1
126
+ return counts
127
+
128
+
129
+ def _findings_title(rows: list[ScanFinding], has_external: bool) -> str:
130
+ """Build the findings table title, with per-source counts when mixed."""
131
+ base = f"{STATUS_SYMBOLS['search']} Audit Findings"
132
+ if not has_external:
133
+ return f"{STATUS_SYMBOLS['search']} Content Scan Findings"
134
+ counts = _source_counts(rows)
135
+ parts = [f"{src}: {n}" for src, n in sorted(counts.items())]
136
+ return f"{base} ({', '.join(parts)})"
137
+
138
+
106
139
  def _render_findings_table(
107
140
  findings_by_file: dict[str, list[ScanFinding]],
108
141
  verbose: bool = False,
@@ -124,6 +157,9 @@ def _render_findings_table(
124
157
  if not rows:
125
158
  return
126
159
 
160
+ has_external = _has_external_findings(rows)
161
+ title = _findings_title(rows, has_external)
162
+
127
163
  if console:
128
164
  try:
129
165
  from rich.table import Table
@@ -131,14 +167,19 @@ def _render_findings_table(
131
167
  from ..security.audit_report import relative_path_for_report
132
168
 
133
169
  table = Table(
134
- title=f"{STATUS_SYMBOLS['search']} Content Scan Findings",
170
+ title=title,
135
171
  show_header=True,
136
172
  header_style="bold cyan",
137
173
  )
138
174
  table.add_column("Severity", style="bold", width=10)
175
+ if has_external:
176
+ table.add_column("Source", style="cyan", width=14)
139
177
  table.add_column("File", style="white")
140
178
  table.add_column("Location", style="dim", width=10)
141
- table.add_column("Codepoint", style="bold white", width=10)
179
+ if has_external:
180
+ table.add_column("Category", style="bold white")
181
+ else:
182
+ table.add_column("Codepoint", style="bold white", width=10)
142
183
  table.add_column("Description", style="white")
143
184
 
144
185
  sev_styles = {
@@ -147,12 +188,26 @@ def _render_findings_table(
147
188
  "info": "dim",
148
189
  }
149
190
  for f in rows:
191
+ category_or_codepoint = (
192
+ f.category.split("/", 1)[1]
193
+ if has_external and "/" in f.category
194
+ else f.category
195
+ if has_external
196
+ else f.codepoint
197
+ )
198
+ row_cells = [f.severity.upper()]
199
+ if has_external:
200
+ row_cells.append(_finding_source(f))
201
+ row_cells.extend(
202
+ [
203
+ relative_path_for_report(f.file),
204
+ f"{f.line}:{f.column}",
205
+ category_or_codepoint,
206
+ f.description,
207
+ ]
208
+ )
150
209
  table.add_row(
151
- f.severity.upper(),
152
- relative_path_for_report(f.file),
153
- f"{f.line}:{f.column}",
154
- f.codepoint,
155
- f.description,
210
+ *row_cells,
156
211
  style=sev_styles.get(f.severity, "white"),
157
212
  )
158
213
  console.print()
@@ -163,18 +218,17 @@ def _render_findings_table(
163
218
 
164
219
  # Fallback: plain text
165
220
  _rich_echo("")
166
- _rich_echo(
167
- f"{STATUS_SYMBOLS['search']} Content Scan Findings",
168
- color="cyan",
169
- bold=True,
170
- )
221
+ _rich_echo(title, color="cyan", bold=True)
171
222
  for f in rows:
172
223
  sev_label = f.severity.upper()
173
224
  color = (
174
225
  "red" if f.severity == "critical" else ("yellow" if f.severity == "warning" else "dim")
175
226
  )
227
+ source_part = f" [{_finding_source(f)}]" if has_external else ""
228
+ detail = f.category if has_external else f.codepoint
176
229
  _rich_echo(
177
- f" {sev_label:<10} {f.file} {f.line}:{f.column} {f.codepoint} {f.description}",
230
+ f" {sev_label:<10}{source_part} {f.file} {f.line}:{f.column} {detail} "
231
+ f"{f.description}",
178
232
  color=color,
179
233
  )
180
234
 
@@ -669,7 +723,7 @@ def _run_external_scanners(
669
723
  require_external_scanners_enabled("Ingesting external scanners with --external")
670
724
  except ExternalScannersFeatureDisabledError as exc:
671
725
  logger.error(str(exc))
672
- sys.exit(2)
726
+ sys.exit(3)
673
727
 
674
728
  try:
675
729
  return run_external_scanners(
@@ -681,7 +735,7 @@ def _run_external_scanners(
681
735
  )
682
736
  except ExternalScanError as exc:
683
737
  logger.error(str(exc))
684
- sys.exit(2)
738
+ sys.exit(3)
685
739
 
686
740
 
687
741
  def _audit_content_scan(
@@ -713,8 +767,9 @@ def _audit_content_scan(
713
767
 
714
768
  # --format json/sarif/markdown is incompatible with --strip / --dry-run
715
769
  if effective_format != "text" and (strip or dry_run):
716
- logger.error(f"--format {effective_format} cannot be combined with --strip or --dry-run")
717
- sys.exit(1)
770
+ raise click.UsageError(
771
+ f"--format {effective_format} cannot be combined with --strip or --dry-run"
772
+ )
718
773
 
719
774
  if file_path:
720
775
  # -- File mode: scan a single arbitrary file --
@@ -997,6 +1052,7 @@ def _audit_content_scan(
997
1052
  help=(
998
1053
  "Ingest findings from an external SARIF-native scanner "
999
1054
  "(repeatable). Names: skillspector, sarif. "
1055
+ "Not supported with --ci. "
1000
1056
  "Requires 'apm experimental enable external-scanners'. [experimental]"
1001
1057
  ),
1002
1058
  )
@@ -1070,6 +1126,8 @@ def audit( # noqa: PLR0913 -- Click handler
1070
1126
  (including drift in --ci mode)
1071
1127
  2 Warning-only findings (suspicious but not critical), or
1072
1128
  usage error (mutually exclusive flags)
1129
+ 3 Configuration or infrastructure error (experimental feature
1130
+ disabled, external scanner not installed or unavailable)
1073
1131
 
1074
1132
  \b
1075
1133
  Examples:
@@ -1084,6 +1142,8 @@ def audit( # noqa: PLR0913 -- Click handler
1084
1142
  apm audit --ci -f json # JSON CI report
1085
1143
  apm audit --ci -f sarif # SARIF for GitHub Code Scanning
1086
1144
  apm audit -o report.sarif # Write SARIF to file
1145
+ apm audit --external skillspector # SkillSpector
1146
+ apm audit --external sarif --external-sarif r.sarif # Any SARIF
1087
1147
  """
1088
1148
  project_root = Path.cwd()
1089
1149
  logger = CommandLogger("audit", verbose=verbose)
@@ -1110,17 +1170,17 @@ def audit( # noqa: PLR0913 -- Click handler
1110
1170
  if verbose:
1111
1171
  logger.warning("--verbose has no effect in --ci mode (output is structured)")
1112
1172
  if strip or dry_run or file_path or package:
1113
- logger.error("--ci cannot be combined with --strip, --dry-run, --file, or PACKAGE")
1114
- sys.exit(1)
1173
+ raise click.UsageError(
1174
+ "--ci cannot be combined with --strip, --dry-run, --file, or PACKAGE"
1175
+ )
1115
1176
  if output_format == "markdown":
1116
1177
  logger.error("--ci does not support --format markdown. Use json or sarif.")
1117
1178
  sys.exit(1)
1118
1179
  if external:
1119
- logger.error(
1180
+ raise click.UsageError(
1120
1181
  "--ci does not support --external scanners yet. "
1121
1182
  "Run external scanners in bare 'apm audit' mode."
1122
1183
  )
1123
- sys.exit(1)
1124
1184
 
1125
1185
  _audit_ci_gate(cfg, policy_source, no_cache, no_policy, no_fail_fast, no_drift)
1126
1186
  return # _audit_ci_gate calls sys.exit; return guards against fall-through
@@ -1129,8 +1189,7 @@ def audit( # noqa: PLR0913 -- Click handler
1129
1189
  # They cannot be combined with --strip/--dry-run (APM only knows how to
1130
1190
  # strip the Unicode characters its own scanner detects).
1131
1191
  if external and (strip or dry_run):
1132
- logger.error("--external cannot be combined with --strip or --dry-run")
1133
- sys.exit(1)
1192
+ raise click.UsageError("--external cannot be combined with --strip or --dry-run")
1134
1193
  if external_sarif and not external:
1135
1194
  raise click.UsageError("--external-sarif requires '--external sarif'")
1136
1195
  # Orphan-flag guards: scanner-config flags are meaningless without a
@@ -234,10 +234,21 @@ def _resolve_compile_target(target):
234
234
  families.add("agents")
235
235
 
236
236
  if len(families) >= 2:
237
- # Single-target copilot collapses {"vscode","agents"} to bare
238
- # "vscode" for routing parity with single-string -t copilot.
237
+ # Collapse {"vscode","agents"} to bare "vscode" ONLY when the
238
+ # original target list contains no non-Copilot agents-family
239
+ # targets (e.g. codex, opencode, windsurf). When mixed targets
240
+ # like [copilot, codex] are requested, keep the frozenset so
241
+ # downstream dedup logic knows non-Copilot targets also consume
242
+ # AGENTS.md (issue #1678).
239
243
  if families == {"vscode", "agents"}:
240
- return "vscode"
244
+ _vscode_names = {"copilot", "vscode", "agents"}
245
+ has_non_vscode_agents = any(
246
+ name in target_set
247
+ for name, profile in KNOWN_TARGETS.items()
248
+ if profile.compile_family == "agents" and name not in _vscode_names
249
+ )
250
+ if not has_non_vscode_agents:
251
+ return "vscode"
241
252
  return frozenset(families)
242
253
  if "claude" in families:
243
254
  return "claude"
@@ -244,7 +244,7 @@ def enable_flag(ctx, name: str, verbose: bool):
244
244
  from ..core.experimental import is_enabled
245
245
 
246
246
  if is_enabled(normalised):
247
- logger.warning(f"{display_name(normalised)} is already enabled.")
247
+ logger.progress(f"{display_name(normalised)} is already enabled.")
248
248
  return
249
249
 
250
250
  flag = _enable_flag(normalised)
@@ -274,7 +274,7 @@ def disable_flag(ctx, name: str, verbose: bool):
274
274
  from ..core.experimental import is_enabled
275
275
 
276
276
  if not is_enabled(normalised):
277
- logger.warning(f"{display_name(normalised)} is already disabled.")
277
+ logger.progress(f"{display_name(normalised)} is already disabled.")
278
278
  return
279
279
 
280
280
  _disable_flag(normalised)