apm-cli 0.20.0__tar.gz → 0.22.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 (417) hide show
  1. {apm_cli-0.20.0/src/apm_cli.egg-info → apm_cli-0.22.0}/PKG-INFO +4 -1
  2. {apm_cli-0.20.0 → apm_cli-0.22.0}/README.md +3 -0
  3. {apm_cli-0.20.0 → apm_cli-0.22.0}/pyproject.toml +4 -1
  4. apm_cli-0.22.0/src/apm_cli/adapters/client/antigravity.py +54 -0
  5. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/client/base.py +33 -0
  6. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/client/codex.py +16 -3
  7. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/client/copilot.py +3 -0
  8. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/client/cursor.py +3 -0
  9. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/client/gemini.py +36 -19
  10. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/client/kiro.py +3 -0
  11. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/client/vscode.py +2 -0
  12. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/bundle/lockfile_enrichment.py +7 -9
  13. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/bundle/plugin_exporter.py +7 -1
  14. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/bundle/unpacker.py +24 -0
  15. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/cli.py +3 -0
  16. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/_apm_yml_writer.py +41 -10
  17. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/_helpers.py +2 -2
  18. apm_cli-0.22.0/src/apm_cli/commands/approve.py +505 -0
  19. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/audit.py +79 -4
  20. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/compile/cli.py +153 -4
  21. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/config.py +139 -0
  22. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/deps/cli.py +7 -3
  23. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/doctor.py +3 -5
  24. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/install.py +71 -58
  25. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/lock.py +140 -2
  26. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/marketplace/__init__.py +1 -240
  27. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/marketplace/check.py +83 -4
  28. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/marketplace/doctor.py +87 -66
  29. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/outdated.py +19 -6
  30. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/pack.py +16 -0
  31. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/policy.py +21 -0
  32. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/publish.py +15 -9
  33. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/self_update.py +65 -5
  34. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/update.py +3 -3
  35. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/view.py +140 -13
  36. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/compilation/__init__.py +4 -0
  37. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/compilation/agents_compiler.py +11 -2
  38. apm_cli-0.22.0/src/apm_cli/compilation/user_root_context.py +305 -0
  39. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/config.py +125 -1
  40. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/errors.py +1 -1
  41. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/experimental.py +12 -0
  42. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/target_detection.py +44 -5
  43. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/dependency_graph.py +13 -2
  44. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/installed_package.py +4 -0
  45. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/lockfile.py +82 -13
  46. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/registry/extractor.py +1 -1
  47. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/registry/outdated.py +22 -2
  48. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/registry/resolver.py +38 -15
  49. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/drift.py +9 -4
  50. apm_cli-0.22.0/src/apm_cli/export/__init__.py +13 -0
  51. apm_cli-0.22.0/src/apm_cli/export/authoring.py +55 -0
  52. apm_cli-0.22.0/src/apm_cli/export/declared_license.py +79 -0
  53. apm_cli-0.22.0/src/apm_cli/export/formats.py +15 -0
  54. apm_cli-0.22.0/src/apm_cli/export/purl.py +153 -0
  55. apm_cli-0.22.0/src/apm_cli/export/sbom.py +178 -0
  56. apm_cli-0.22.0/src/apm_cli/export/spdx.py +168 -0
  57. apm_cli-0.22.0/src/apm_cli/export/spdx_data.py +841 -0
  58. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/factory.py +2 -0
  59. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/artifactory_resolver.py +7 -1
  60. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/cache_pin.py +2 -2
  61. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/context.py +24 -2
  62. apm_cli-0.22.0/src/apm_cli/install/deployed_paths.py +70 -0
  63. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/drift.py +40 -2
  64. apm_cli-0.22.0/src/apm_cli/install/exec_gate.py +167 -0
  65. apm_cli-0.22.0/src/apm_cli/install/integrity.py +59 -0
  66. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/local_bundle_handler.py +2 -0
  67. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/package_resolution.py +51 -0
  68. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/phases/cleanup.py +24 -3
  69. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/phases/finalize.py +69 -0
  70. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/phases/integrate.py +100 -0
  71. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/phases/local_content.py +1 -0
  72. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/phases/lockfile.py +32 -0
  73. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/phases/resolve.py +17 -7
  74. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/phases/targets.py +18 -1
  75. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/pipeline.py +47 -1
  76. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/plan.py +5 -1
  77. apm_cli-0.22.0/src/apm_cli/install/registry_wiring.py +145 -0
  78. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/services.py +270 -145
  79. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/skill_path_migration.py +6 -1
  80. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/sources.py +61 -2
  81. apm_cli-0.22.0/src/apm_cli/install/target_filter.py +33 -0
  82. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/template.py +61 -0
  83. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/agent_integrator.py +15 -5
  84. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/base_integrator.py +95 -14
  85. apm_cli-0.22.0/src/apm_cli/integration/canvas_integrator.py +509 -0
  86. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/cleanup.py +236 -23
  87. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/command_integrator.py +5 -1
  88. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/dispatch.py +7 -0
  89. apm_cli-0.22.0/src/apm_cli/integration/hook_file_routing.py +120 -0
  90. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/hook_integrator.py +230 -99
  91. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/instruction_integrator.py +32 -9
  92. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/kiro_hook_integrator.py +10 -2
  93. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/lsp_integrator.py +3 -2
  94. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/mcp_integrator.py +25 -4
  95. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/prompt_integrator.py +5 -2
  96. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/skill_integrator.py +84 -33
  97. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/skill_transformer.py +2 -1
  98. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/targets.py +62 -6
  99. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/__init__.py +0 -16
  100. apm_cli-0.22.0/src/apm_cli/marketplace/auth_helpers.py +53 -0
  101. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/builder.py +45 -32
  102. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/client.py +170 -10
  103. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/git_stderr.py +1 -3
  104. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/models.py +6 -2
  105. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/resolver.py +62 -4
  106. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/validator.py +1 -1
  107. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/version_check.py +1 -1
  108. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/yml_schema.py +1 -1
  109. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/models/apm_package.py +40 -6
  110. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/models/dependency/mcp.py +46 -2
  111. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/models/dependency/reference.py +14 -21
  112. apm_cli-0.22.0/src/apm_cli/models/dependency/subsets.py +94 -0
  113. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/models/validation.py +31 -0
  114. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/policy/_help_text.py +3 -1
  115. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/policy/discovery.py +227 -11
  116. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/policy/inheritance.py +75 -3
  117. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/policy/matcher.py +19 -6
  118. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/policy/models.py +1 -0
  119. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/policy/parser.py +84 -1
  120. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/policy/policy_checks.py +233 -27
  121. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/policy/schema.py +63 -0
  122. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/security/__init__.py +8 -0
  123. apm_cli-0.22.0/src/apm_cli/security/executables.py +1157 -0
  124. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/atomic_io.py +25 -2
  125. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/github_host.py +72 -3
  126. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/version_checker.py +42 -12
  127. {apm_cli-0.20.0 → apm_cli-0.22.0/src/apm_cli.egg-info}/PKG-INFO +4 -1
  128. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli.egg-info/SOURCES.txt +20 -3
  129. {apm_cli-0.20.0 → apm_cli-0.22.0}/tests/test_lockfile.py +242 -0
  130. apm_cli-0.20.0/src/apm_cli/commands/marketplace/publish.py +0 -239
  131. apm_cli-0.20.0/src/apm_cli/install/registry_wiring.py +0 -63
  132. apm_cli-0.20.0/src/apm_cli/marketplace/pr_integration.py +0 -498
  133. apm_cli-0.20.0/src/apm_cli/marketplace/publisher.py +0 -922
  134. {apm_cli-0.20.0 → apm_cli-0.22.0}/AUTHORS +0 -0
  135. {apm_cli-0.20.0 → apm_cli-0.22.0}/LICENSE +0 -0
  136. {apm_cli-0.20.0 → apm_cli-0.22.0}/NOTICE +0 -0
  137. {apm_cli-0.20.0 → apm_cli-0.22.0}/setup.cfg +0 -0
  138. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/__init__.py +0 -0
  139. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/__init__.py +0 -0
  140. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/client/__init__.py +0 -0
  141. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/client/_mcp_runtime_args.py +0 -0
  142. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/client/claude.py +0 -0
  143. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/client/hermes.py +0 -0
  144. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/client/intellij.py +0 -0
  145. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/client/opencode.py +0 -0
  146. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/client/windsurf.py +0 -0
  147. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/package_manager/__init__.py +0 -0
  148. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/package_manager/base.py +0 -0
  149. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/adapters/package_manager/default_manager.py +0 -0
  150. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/bootstrap_mirror.py +0 -0
  151. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/bundle/__init__.py +0 -0
  152. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/bundle/local_bundle.py +0 -0
  153. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/bundle/packer.py +0 -0
  154. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/cache/__init__.py +0 -0
  155. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/cache/git_cache.py +0 -0
  156. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/cache/http_cache.py +0 -0
  157. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/cache/integrity.py +0 -0
  158. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/cache/locking.py +0 -0
  159. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/cache/paths.py +0 -0
  160. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/cache/url_normalize.py +0 -0
  161. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/__init__.py +0 -0
  162. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/cache.py +0 -0
  163. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/compile/__init__.py +0 -0
  164. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/compile/watcher.py +0 -0
  165. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/deps/__init__.py +0 -0
  166. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/deps/_utils.py +0 -0
  167. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/deps/why.py +0 -0
  168. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/experimental.py +0 -0
  169. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/find.py +0 -0
  170. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/init.py +0 -0
  171. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/list_cmd.py +0 -0
  172. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/marketplace/audit.py +0 -0
  173. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/marketplace/init.py +0 -0
  174. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/marketplace/migrate.py +0 -0
  175. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/marketplace/outdated.py +0 -0
  176. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/marketplace/plugin/__init__.py +0 -0
  177. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/marketplace/plugin/add.py +0 -0
  178. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/marketplace/plugin/remove.py +0 -0
  179. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/marketplace/plugin/set.py +0 -0
  180. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/marketplace/validate.py +0 -0
  181. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/mcp.py +0 -0
  182. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/plugin/__init__.py +0 -0
  183. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/plugin/init.py +0 -0
  184. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/prune.py +0 -0
  185. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/run.py +0 -0
  186. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/runtime.py +0 -0
  187. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/targets.py +0 -0
  188. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/uninstall/__init__.py +0 -0
  189. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/uninstall/cli.py +0 -0
  190. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/commands/uninstall/engine.py +0 -0
  191. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/compilation/build_id.py +0 -0
  192. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/compilation/claude_formatter.py +0 -0
  193. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/compilation/constants.py +0 -0
  194. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/compilation/constitution.py +0 -0
  195. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/compilation/constitution_block.py +0 -0
  196. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/compilation/context_optimizer.py +0 -0
  197. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/compilation/distributed_compiler.py +0 -0
  198. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/compilation/gemini_formatter.py +0 -0
  199. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/compilation/injector.py +0 -0
  200. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/compilation/link_resolver.py +0 -0
  201. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/compilation/managed_section.py +0 -0
  202. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/compilation/output_writer.py +0 -0
  203. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/compilation/template_builder.py +0 -0
  204. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/constants.py +0 -0
  205. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/__init__.py +0 -0
  206. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/apm_yml.py +0 -0
  207. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/auth.py +0 -0
  208. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/azure_cli.py +0 -0
  209. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/build_orchestrator.py +0 -0
  210. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/command_logger.py +0 -0
  211. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/conflict_detector.py +0 -0
  212. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/docker_args.py +0 -0
  213. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/install_audit.py +0 -0
  214. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/null_logger.py +0 -0
  215. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/operations.py +0 -0
  216. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/plugin_manifest.py +0 -0
  217. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/safe_installer.py +0 -0
  218. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/scope.py +0 -0
  219. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/script_runner.py +0 -0
  220. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/core/token_manager.py +0 -0
  221. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/__init__.py +0 -0
  222. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/_shared.py +0 -0
  223. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/aggregator.py +0 -0
  224. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/apm_resolver.py +0 -0
  225. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/artifactory_entry.py +0 -0
  226. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/artifactory_orchestrator.py +0 -0
  227. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/bare_cache.py +0 -0
  228. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/clone_engine.py +0 -0
  229. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/download_strategies.py +0 -0
  230. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/git_auth_env.py +0 -0
  231. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/git_file_transport.py +0 -0
  232. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/git_reference_resolver.py +0 -0
  233. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/git_remote_ops.py +0 -0
  234. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/git_semver_resolver.py +0 -0
  235. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/github_downloader.py +0 -0
  236. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/github_downloader_validation.py +0 -0
  237. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/host_backends.py +0 -0
  238. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/outdated_row.py +0 -0
  239. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/package_validator.py +0 -0
  240. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/path_anchoring.py +0 -0
  241. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/plugin_parser.py +0 -0
  242. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/registry/__init__.py +0 -0
  243. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/registry/auth.py +0 -0
  244. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/registry/client.py +0 -0
  245. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/registry/config_loader.py +0 -0
  246. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/registry/feature_gate.py +0 -0
  247. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/registry/semver.py +0 -0
  248. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/registry_proxy.py +0 -0
  249. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/revision_pins.py +0 -0
  250. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/shared_clone_cache.py +0 -0
  251. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/tiered_ref_resolver.py +0 -0
  252. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/transport_selection.py +0 -0
  253. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/verifier.py +0 -0
  254. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/deps/why_walker.py +0 -0
  255. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/__init__.py +0 -0
  256. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/errors.py +0 -0
  257. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/gitlab_resolver.py +0 -0
  258. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/heals/__init__.py +0 -0
  259. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/heals/base.py +0 -0
  260. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/heals/branch_ref_drift.py +0 -0
  261. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/heals/buggy_lockfile_recovery.py +0 -0
  262. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/helpers/__init__.py +0 -0
  263. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/helpers/security_scan.py +0 -0
  264. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/insecure_policy.py +0 -0
  265. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/lsp/__init__.py +0 -0
  266. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/lsp/integration.py +0 -0
  267. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/manifest_reconcile.py +0 -0
  268. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/mcp/__init__.py +0 -0
  269. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/mcp/args.py +0 -0
  270. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/mcp/command.py +0 -0
  271. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/mcp/conflicts.py +0 -0
  272. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/mcp/entry.py +0 -0
  273. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/mcp/registry.py +0 -0
  274. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/mcp/warnings.py +0 -0
  275. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/mcp/writer.py +0 -0
  276. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/package_selection.py +0 -0
  277. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/phases/__init__.py +0 -0
  278. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/phases/_redownload.py +0 -0
  279. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/phases/_skip_logic.py +0 -0
  280. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/phases/audit.py +0 -0
  281. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/phases/download.py +0 -0
  282. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/phases/heal.py +0 -0
  283. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/phases/policy_gate.py +0 -0
  284. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/phases/policy_target_check.py +0 -0
  285. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/phases/post_deps_local.py +0 -0
  286. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/presentation/__init__.py +0 -0
  287. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/presentation/dry_run.py +0 -0
  288. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/request.py +0 -0
  289. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/root_redirect.py +0 -0
  290. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/service.py +0 -0
  291. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/summary.py +0 -0
  292. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/install/validation.py +0 -0
  293. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/__init__.py +0 -0
  294. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/_shared.py +0 -0
  295. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/copilot_app_db.py +0 -0
  296. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/copilot_app_project.py +0 -0
  297. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/copilot_app_workflow_integrator.py +0 -0
  298. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/copilot_app_ws.py +0 -0
  299. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/copilot_cowork_paths.py +0 -0
  300. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/coverage.py +0 -0
  301. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/mcp_integrator_install.py +0 -0
  302. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/opencode_frontmatter.py +0 -0
  303. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/integration/utils.py +0 -0
  304. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/_git_utils.py +0 -0
  305. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/_io.py +0 -0
  306. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/_shared.py +0 -0
  307. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/audit.py +0 -0
  308. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/diagnostics.py +0 -0
  309. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/drift_check.py +0 -0
  310. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/errors.py +0 -0
  311. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/init_template.py +0 -0
  312. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/migration.py +0 -0
  313. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/output_mappers.py +0 -0
  314. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/output_profiles.py +0 -0
  315. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/ref_resolver.py +0 -0
  316. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/registry.py +0 -0
  317. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/semver.py +0 -0
  318. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/shadow_detector.py +0 -0
  319. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/tag_pattern.py +0 -0
  320. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/version_pins.py +0 -0
  321. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/version_resolver.py +0 -0
  322. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/marketplace/yml_editor.py +0 -0
  323. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/models/__init__.py +0 -0
  324. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/models/dependency/__init__.py +0 -0
  325. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/models/dependency/identity.py +0 -0
  326. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/models/dependency/lsp.py +0 -0
  327. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/models/dependency/types.py +0 -0
  328. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/models/format_detection.py +0 -0
  329. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/models/plugin.py +0 -0
  330. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/models/results.py +0 -0
  331. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/output/__init__.py +0 -0
  332. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/output/formatters.py +0 -0
  333. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/output/models.py +0 -0
  334. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/output/script_formatters.py +0 -0
  335. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/policy/__init__.py +0 -0
  336. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/policy/_constraint_pinning.py +0 -0
  337. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/policy/_shared.py +0 -0
  338. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/policy/ci_checks.py +0 -0
  339. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/policy/install_preflight.py +0 -0
  340. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/policy/outcome_routing.py +0 -0
  341. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/policy/project_config.py +0 -0
  342. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/primitives/__init__.py +0 -0
  343. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/primitives/discovery.py +0 -0
  344. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/primitives/models.py +0 -0
  345. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/primitives/parser.py +0 -0
  346. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/registry/__init__.py +0 -0
  347. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/registry/client.py +0 -0
  348. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/registry/integration.py +0 -0
  349. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/registry/operations.py +0 -0
  350. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/runtime/__init__.py +0 -0
  351. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/runtime/base.py +0 -0
  352. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/runtime/codex_runtime.py +0 -0
  353. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/runtime/copilot_runtime.py +0 -0
  354. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/runtime/factory.py +0 -0
  355. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/runtime/llm_runtime.py +0 -0
  356. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/runtime/manager.py +0 -0
  357. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/runtime/utils.py +0 -0
  358. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/security/audit_report.py +0 -0
  359. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/security/content_scanner.py +0 -0
  360. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/security/external/__init__.py +0 -0
  361. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/security/external/base.py +0 -0
  362. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/security/external/gate.py +0 -0
  363. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/security/external/generic_sarif.py +0 -0
  364. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/security/external/options.py +0 -0
  365. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/security/external/registry.py +0 -0
  366. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/security/external/runner.py +0 -0
  367. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/security/external/sarif_ingest.py +0 -0
  368. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/security/external/skillspector.py +0 -0
  369. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/security/file_scanner.py +0 -0
  370. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/security/gate.py +0 -0
  371. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/update_policy.py +0 -0
  372. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/__init__.py +0 -0
  373. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/archive.py +0 -0
  374. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/console.py +0 -0
  375. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/content_hash.py +0 -0
  376. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/diagnostics.py +0 -0
  377. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/exclude.py +0 -0
  378. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/file_ops.py +0 -0
  379. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/git_env.py +0 -0
  380. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/git_sparse.py +0 -0
  381. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/guards.py +0 -0
  382. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/helpers.py +0 -0
  383. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/install_tui.py +0 -0
  384. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/normalization.py +0 -0
  385. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/path_security.py +0 -0
  386. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/paths.py +0 -0
  387. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/patterns.py +0 -0
  388. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/perf_stats.py +0 -0
  389. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/reflink.py +0 -0
  390. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/short_sha.py +0 -0
  391. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/subprocess_env.py +0 -0
  392. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/utils/yaml_io.py +0 -0
  393. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/version.py +0 -0
  394. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/workflow/__init__.py +0 -0
  395. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/workflow/discovery.py +0 -0
  396. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/workflow/parser.py +0 -0
  397. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli/workflow/runner.py +0 -0
  398. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli.egg-info/dependency_links.txt +0 -0
  399. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli.egg-info/entry_points.txt +0 -0
  400. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli.egg-info/requires.txt +0 -0
  401. {apm_cli-0.20.0 → apm_cli-0.22.0}/src/apm_cli.egg-info/top_level.txt +0 -0
  402. {apm_cli-0.20.0 → apm_cli-0.22.0}/tests/test_apm_package_models.py +0 -0
  403. {apm_cli-0.20.0 → apm_cli-0.22.0}/tests/test_apm_resolver.py +0 -0
  404. {apm_cli-0.20.0 → apm_cli-0.22.0}/tests/test_codex_docker_args_fix.py +0 -0
  405. {apm_cli-0.20.0 → apm_cli-0.22.0}/tests/test_codex_empty_string_and_defaults.py +0 -0
  406. {apm_cli-0.20.0 → apm_cli-0.22.0}/tests/test_collision_integration.py +0 -0
  407. {apm_cli-0.20.0 → apm_cli-0.22.0}/tests/test_console.py +0 -0
  408. {apm_cli-0.20.0 → apm_cli-0.22.0}/tests/test_distributed_compilation.py +0 -0
  409. {apm_cli-0.20.0 → apm_cli-0.22.0}/tests/test_empty_string_and_defaults.py +0 -0
  410. {apm_cli-0.20.0 → apm_cli-0.22.0}/tests/test_enhanced_discovery.py +0 -0
  411. {apm_cli-0.20.0 → apm_cli-0.22.0}/tests/test_github_downloader.py +0 -0
  412. {apm_cli-0.20.0 → apm_cli-0.22.0}/tests/test_github_downloader_token_precedence.py +0 -0
  413. {apm_cli-0.20.0 → apm_cli-0.22.0}/tests/test_gitlab_git_transport.py +0 -0
  414. {apm_cli-0.20.0 → apm_cli-0.22.0}/tests/test_runnable_prompts.py +0 -0
  415. {apm_cli-0.20.0 → apm_cli-0.22.0}/tests/test_runtime_manager_token_precedence.py +0 -0
  416. {apm_cli-0.20.0 → apm_cli-0.22.0}/tests/test_token_manager.py +0 -0
  417. {apm_cli-0.20.0 → apm_cli-0.22.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.20.0
3
+ Version: 0.22.0
4
4
  Summary: MCP configuration tool
5
5
  Author-email: Daniel Meppiel <user@example.com>
6
6
  License: MIT License
@@ -149,6 +149,7 @@ Agent context is executable in effect — a prompt is a program for an LLM. APM
149
149
 
150
150
  - **[Content security](https://microsoft.github.io/apm/enterprise/security/)** — `apm install` blocks compromised packages before agents read them; `apm audit` runs the same checks on demand
151
151
  - **[Lockfile integrity](https://microsoft.github.io/apm/enterprise/governance/)** — `apm.lock` records resolved sources and content hashes for full provenance
152
+ - **[SBOM export](https://microsoft.github.io/apm/reference/cli/lock/)** — `apm lock export --format cyclonedx|spdx` emits a standard inventory of what reached disk, straight from the lockfile — provenance for procurement, not a compliance attestation
152
153
  - **[Drift detection](https://microsoft.github.io/apm/guides/drift-detection/)** — `apm audit` rebuilds your agent context in scratch and diffs it against your working tree to catch hand-edits before they ship
153
154
  - **[MCP trust boundaries](https://microsoft.github.io/apm/guides/mcp-servers/)** — transitive MCP servers require explicit consent
154
155
 
@@ -156,6 +157,8 @@ Agent context is executable in effect — a prompt is a program for an LLM. APM
156
157
 
157
158
  `apm-policy.yml` lets a security team say *"these are the only sources, scopes, and primitives this org will allow"* and have every `apm install` enforce it — with tighten-only inheritance from enterprise to org to repo, a published bypass contract, and audit-mode CI gates.
158
159
 
160
+ apm-policy.yml governs what gets installed; your agent harness governs what runs. The two planes do not overlap.
161
+
159
162
  - **[Governance Guide](https://microsoft.github.io/apm/enterprise/governance-guide/)** — the canonical enterprise reference: enforcement points, bypass contract, air-gapped story, failure semantics, rollout playbook
160
163
  - **[Policy reference](https://microsoft.github.io/apm/enterprise/policy-reference/)** — every check, every field, every default
161
164
  - **[Adoption playbook](https://microsoft.github.io/apm/enterprise/adoption-playbook/)** — staged rollout from warn to block across hundreds of repos
@@ -81,6 +81,7 @@ Agent context is executable in effect — a prompt is a program for an LLM. APM
81
81
 
82
82
  - **[Content security](https://microsoft.github.io/apm/enterprise/security/)** — `apm install` blocks compromised packages before agents read them; `apm audit` runs the same checks on demand
83
83
  - **[Lockfile integrity](https://microsoft.github.io/apm/enterprise/governance/)** — `apm.lock` records resolved sources and content hashes for full provenance
84
+ - **[SBOM export](https://microsoft.github.io/apm/reference/cli/lock/)** — `apm lock export --format cyclonedx|spdx` emits a standard inventory of what reached disk, straight from the lockfile — provenance for procurement, not a compliance attestation
84
85
  - **[Drift detection](https://microsoft.github.io/apm/guides/drift-detection/)** — `apm audit` rebuilds your agent context in scratch and diffs it against your working tree to catch hand-edits before they ship
85
86
  - **[MCP trust boundaries](https://microsoft.github.io/apm/guides/mcp-servers/)** — transitive MCP servers require explicit consent
86
87
 
@@ -88,6 +89,8 @@ Agent context is executable in effect — a prompt is a program for an LLM. APM
88
89
 
89
90
  `apm-policy.yml` lets a security team say *"these are the only sources, scopes, and primitives this org will allow"* and have every `apm install` enforce it — with tighten-only inheritance from enterprise to org to repo, a published bypass contract, and audit-mode CI gates.
90
91
 
92
+ apm-policy.yml governs what gets installed; your agent harness governs what runs. The two planes do not overlap.
93
+
91
94
  - **[Governance Guide](https://microsoft.github.io/apm/enterprise/governance-guide/)** — the canonical enterprise reference: enforcement points, bypass contract, air-gapped story, failure semantics, rollout playbook
92
95
  - **[Policy reference](https://microsoft.github.io/apm/enterprise/policy-reference/)** — every check, every field, every default
93
96
  - **[Adoption playbook](https://microsoft.github.io/apm/enterprise/adoption-playbook/)** — staged rollout from warn to block across hundreds of repos
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "apm-cli"
7
- version = "0.20.0"
7
+ version = "0.22.0"
8
8
  description = "MCP configuration tool"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -105,6 +105,9 @@ max-returns = 12 # Stage 1 (was 18)
105
105
  # Stage 1 (was 100). Stage 2 target: <=20 (McCabe industry standard).
106
106
  max-complexity = 50
107
107
 
108
+ [tool.ruff.lint.isort]
109
+ known-first-party = ["apm_cli"]
110
+
108
111
  [tool.ruff.lint.per-file-ignores]
109
112
  # Subprocess calls are intentional in a CLI tool
110
113
  "src/apm_cli/**" = ["S603", "S607"]
@@ -0,0 +1,54 @@
1
+ """Antigravity CLI (agy) implementation of MCP client adapter.
2
+
3
+ Antigravity CLI is Google's Gemini-derived agentic CLI. Unlike Gemini
4
+ CLI (which stores MCP servers in ``settings.json``), Antigravity reads a
5
+ dedicated ``mcp_config.json`` with an ``mcpServers`` key -- the same JSON
6
+ schema, a different file:
7
+
8
+ .. code-block:: json
9
+
10
+ {
11
+ "mcpServers": {
12
+ "server-name": {
13
+ "command": "npx",
14
+ "args": ["-y", "@modelcontextprotocol/server-foo"],
15
+ "env": { "KEY": "value" }
16
+ }
17
+ }
18
+ }
19
+
20
+ Scope resolution: project scope writes to
21
+ ``<project_root>/.agents/mcp_config.json`` (opt-in -- the directory must
22
+ already exist). User scope writes to ``~/.gemini/config/mcp_config.json``
23
+ unconditionally, creating the directory if needed.
24
+
25
+ Ref: https://antigravity.google/docs/mcp
26
+ """
27
+
28
+ from pathlib import Path
29
+
30
+ from .gemini import GeminiClientAdapter
31
+
32
+
33
+ class AntigravityClientAdapter(GeminiClientAdapter):
34
+ """Antigravity CLI MCP client adapter.
35
+
36
+ Reuses GeminiClientAdapter's ``_format_server_config`` and
37
+ ``configure_mcp_server`` (identical ``mcpServers`` JSON schema) and
38
+ overrides only the config directory, the config filename, and the
39
+ display name. Antigravity writes MCP servers to a dedicated
40
+ ``mcp_config.json`` rather than ``settings.json``.
41
+ """
42
+
43
+ supports_user_scope: bool = True
44
+ target_name: str = "antigravity"
45
+
46
+ def _get_config_dir(self) -> Path:
47
+ """Return the ``.agents`` or ``~/.gemini/config`` directory."""
48
+ if self.user_scope:
49
+ return Path.home() / ".gemini" / "config"
50
+ return self.project_root / ".agents"
51
+
52
+ def get_config_path(self):
53
+ """Return the path to ``mcp_config.json`` for the active scope."""
54
+ return str(self._get_config_dir() / "mcp_config.json")
@@ -6,6 +6,7 @@ from abc import ABC, abstractmethod
6
6
  from pathlib import Path
7
7
  from typing import Any, ClassVar
8
8
 
9
+ from ...models.dependency.mcp import _RESERVED_EXTRA_KEYS
9
10
  from ...utils.console import _rich_error, _rich_warning
10
11
 
11
12
  _INPUT_VAR_RE = re.compile(r"\$\{input:([^}]+)\}")
@@ -28,6 +29,15 @@ _ENV_PLACEHOLDER_RE = re.compile(r"<([A-Z_][A-Z0-9_]*)>|" + _ENV_VAR_RE.pattern)
28
29
  # deprecation warnings across all servers in a single install run.
29
30
  _LEGACY_ANGLE_VAR_RE = re.compile(r"<([A-Z_][A-Z0-9_]*)>")
30
31
 
32
+ # Config keys that ``_extra`` passthrough must NEVER set on a rendered harness
33
+ # config. Covers the modeled MCP fields (imported single-source from the model)
34
+ # plus harness-specific aliases that mirror a modeled field under a different
35
+ # name -- e.g. Codex emits ``http_headers`` for remote auth headers, which must
36
+ # not be injectable via passthrough. Enforced unconditionally per adapter path
37
+ # (NOT guarded by "key absent from config"), so it also closes paths that do not
38
+ # pre-set the key. Security boundary for PR #1765 / issue #1670.
39
+ _EXTRA_DENYLIST = _RESERVED_EXTRA_KEYS | frozenset({"http_headers"})
40
+
31
41
 
32
42
  def registry_field_is_required(field: dict[str, Any]) -> bool:
33
43
  """Return True unless registry metadata explicitly marks a field optional."""
@@ -118,6 +128,29 @@ class MCPClientAdapter(ABC):
118
128
  # (e.g. ``VSCodeClientAdapter``) that have no ``KNOWN_TARGETS`` entry.
119
129
  mcp_servers_key: str = ""
120
130
 
131
+ @staticmethod
132
+ def _merge_extra(config: dict, server_info: dict) -> dict:
133
+ """Merge harness-specific ``_extra`` keys from server_info into config.
134
+
135
+ Two guards apply:
136
+
137
+ * Denylist (unconditional): a key naming a modeled MCP field -- or a
138
+ harness alias of one (see ``_EXTRA_DENYLIST``) -- is dropped on EVERY
139
+ path, even when the config does not already carry it. This stops a
140
+ passthrough value from shadowing/redirecting a modeled field on
141
+ adapter paths that start empty or set only a subset of keys.
142
+ * Shadow guard: a non-reserved key is appended only when absent, so it
143
+ never overwrites a value the adapter set itself.
144
+ """
145
+ extra = server_info.get("_extra")
146
+ if extra and isinstance(extra, dict):
147
+ for k, v in extra.items():
148
+ if k in _EXTRA_DENYLIST:
149
+ continue
150
+ if k not in config:
151
+ config[k] = v
152
+ return config
153
+
121
154
  # Whether this adapter's config path is user/global-scoped (e.g.
122
155
  # ``~/.copilot/``) rather than workspace-scoped (e.g. ``.vscode/``).
123
156
  # Adapters that target a global path should override this to ``True``
@@ -10,6 +10,7 @@ import toml
10
10
  from ...registry.client import SimpleRegistryClient
11
11
  from ...registry.integration import RegistryIntegration
12
12
  from ...utils.console import _rich_success, _rich_warning
13
+ from ...utils.path_security import PathTraversalError
13
14
  from ._mcp_runtime_args import process_v01_value_hint_arg
14
15
  from .base import MCPClientAdapter
15
16
 
@@ -49,13 +50,22 @@ class CodexClientAdapter(MCPClientAdapter):
49
50
  self.registry_client = SimpleRegistryClient(registry_url)
50
51
  self.registry_integration = RegistryIntegration(registry_url)
51
52
 
52
- def _get_codex_dir(self):
53
+ def _get_codex_dir(self) -> Path:
53
54
  """Return the root directory used for Codex config in the current scope."""
54
55
  if self.user_scope:
56
+ codex_home = os.environ.get("CODEX_HOME", "")
57
+ if codex_home.strip():
58
+ codex_home_path = Path(codex_home).expanduser()
59
+ if not codex_home_path.is_absolute():
60
+ raise PathTraversalError(
61
+ "CODEX_HOME is set to a non-absolute path; cannot locate the "
62
+ "Codex CLI configuration directory."
63
+ )
64
+ return codex_home_path
55
65
  return Path.home() / ".codex"
56
66
  return self.project_root / ".codex"
57
67
 
58
- def get_config_path(self):
68
+ def get_config_path(self) -> str:
59
69
  """Get the path to the Codex CLI MCP configuration file.
60
70
 
61
71
  Returns:
@@ -219,6 +229,7 @@ class CodexClientAdapter(MCPClientAdapter):
219
229
  return self.normalize_project_arg(arg)
220
230
 
221
231
  config["args"] = [_process_stdio_arg(arg) for arg in raw.get("args") or []]
232
+ self._merge_extra(config, server_info)
222
233
  return config
223
234
 
224
235
  # Remote MCP handling.
@@ -273,6 +284,7 @@ class CodexClientAdapter(MCPClientAdapter):
273
284
  if http_headers:
274
285
  remote_config["http_headers"] = http_headers
275
286
  self._warn_input_variables(http_headers, server_name, "Codex CLI")
287
+ self._merge_extra(remote_config, server_info)
276
288
  return remote_config
277
289
 
278
290
  if not packages:
@@ -320,7 +332,7 @@ class CodexClientAdapter(MCPClientAdapter):
320
332
  all_args = processed_runtime_args + processed_package_args
321
333
  if all_args:
322
334
  # If runtime_arguments already include the package (bare or
323
- # versioned), use them as-is they are authoritative from
335
+ # versioned), use them as-is -- they are authoritative from
324
336
  # the registry and may carry a version pin.
325
337
  has_pkg = any(
326
338
  a == package_name or a.startswith(f"{package_name}@") for a in all_args
@@ -361,6 +373,7 @@ class CodexClientAdapter(MCPClientAdapter):
361
373
  resolved_env,
362
374
  )
363
375
 
376
+ self._merge_extra(config, server_info)
364
377
  return config
365
378
 
366
379
  def _process_arguments( # pylint: disable=duplicate-code # structural similarity with copilot adapter is intentional
@@ -442,6 +442,7 @@ class CopilotClientAdapter(MCPClientAdapter):
442
442
  tools_override = server_info.get("_apm_tools_override")
443
443
  if tools_override:
444
444
  config["tools"] = tools_override
445
+ self._merge_extra(config, server_info)
445
446
  return config
446
447
 
447
448
  # Check for remote endpoints first (registry-defined priority)
@@ -484,6 +485,7 @@ class CopilotClientAdapter(MCPClientAdapter):
484
485
  if tools_override:
485
486
  config["tools"] = tools_override
486
487
 
488
+ self._merge_extra(config, server_info)
487
489
  return config
488
490
 
489
491
  # Get packages from server info
@@ -507,6 +509,7 @@ class CopilotClientAdapter(MCPClientAdapter):
507
509
  if tools_override:
508
510
  config["tools"] = tools_override
509
511
 
512
+ self._merge_extra(config, server_info)
510
513
  return config
511
514
 
512
515
  def _apply_auth_and_headers(
@@ -148,6 +148,7 @@ class CursorClientAdapter(CopilotClientAdapter):
148
148
  else arg
149
149
  for arg in args
150
150
  ]
151
+ self._merge_extra(config, server_info)
151
152
  return config
152
153
 
153
154
  # --- remote endpoints ---
@@ -169,6 +170,7 @@ class CursorClientAdapter(CopilotClientAdapter):
169
170
  config["url"] = (remote.get("url") or "").strip()
170
171
 
171
172
  self._apply_auth_and_headers(config, remote, server_info, env_overrides, "Cursor")
173
+ self._merge_extra(config, server_info)
172
174
  return config
173
175
 
174
176
  # --- local packages ---
@@ -194,6 +196,7 @@ class CursorClientAdapter(CopilotClientAdapter):
194
196
  f"{[p.get('registry_name', 'unknown') for p in packages]}."
195
197
  )
196
198
 
199
+ self._merge_extra(config, server_info)
197
200
  return config
198
201
 
199
202
  # ------------------------------------------------------------------ #
@@ -61,7 +61,7 @@ class GeminiClientAdapter(CopilotClientAdapter):
61
61
  # revisit in a follow-up.
62
62
  _supports_runtime_env_substitution: bool = False
63
63
 
64
- def _get_gemini_dir(self) -> Path:
64
+ def _get_config_dir(self) -> Path:
65
65
  """Return the ``.gemini`` directory for the active scope."""
66
66
  if self.user_scope:
67
67
  return Path.home() / ".gemini"
@@ -69,22 +69,24 @@ class GeminiClientAdapter(CopilotClientAdapter):
69
69
 
70
70
  def get_config_path(self):
71
71
  """Return the path to ``settings.json`` for the active scope."""
72
- return str(self._get_gemini_dir() / "settings.json")
72
+ return str(self._get_config_dir() / "settings.json")
73
73
 
74
74
  def update_config(self, config_updates):
75
75
  """Merge *config_updates* into the ``mcpServers`` section of settings.json.
76
76
 
77
- Project scope is opt-in: if ``<project_root>/.gemini/`` does not
77
+ Project scope is opt-in: if the target config directory does not
78
78
  exist, this method returns silently. User scope always writes,
79
- creating ``~/.gemini/`` if needed.
79
+ creating the directory if needed.
80
80
 
81
81
  Preserves all other top-level keys in settings.json (theme, tools,
82
82
  hooks, etc.).
83
83
  """
84
- gemini_dir = self._get_gemini_dir()
85
- if not self.user_scope and not gemini_dir.is_dir():
84
+ config_dir = self._get_config_dir()
85
+ if not self.user_scope and not config_dir.is_dir():
86
86
  logger.debug(
87
- "Skipping Gemini project-scope write -- %s does not exist (opt-in)", gemini_dir
87
+ "Skipping %s project-scope write -- %s does not exist (opt-in)",
88
+ self.target_name,
89
+ config_dir,
88
90
  )
89
91
  return
90
92
 
@@ -97,7 +99,9 @@ class GeminiClientAdapter(CopilotClientAdapter):
97
99
  current_config["mcpServers"][name] = entry
98
100
 
99
101
  if not config_path.parent.is_dir():
100
- logger.debug("Creating %s for Gemini CLI user configuration", config_path.parent)
102
+ logger.debug(
103
+ "Creating %s for %s user configuration", config_path.parent, self.target_name
104
+ )
101
105
  config_path.parent.mkdir(parents=True, exist_ok=True)
102
106
  with open(config_path, "w", encoding="utf-8") as f:
103
107
  json.dump(current_config, f, indent=2)
@@ -151,13 +155,16 @@ class GeminiClientAdapter(CopilotClientAdapter):
151
155
  raw["env"], env_overrides=env_overrides
152
156
  )
153
157
  config["env"] = resolved_env_for_args
154
- self._warn_input_variables(raw["env"], server_info.get("name", ""), "Gemini CLI")
158
+ self._warn_input_variables(
159
+ raw["env"], server_info.get("name", ""), self.target_name
160
+ )
155
161
  config["args"] = [
156
162
  self._resolve_variable_placeholders(arg, resolved_env_for_args, runtime_vars)
157
163
  if isinstance(arg, str)
158
164
  else arg
159
165
  for arg in raw.get("args") or []
160
166
  ]
167
+ self._merge_extra(config, server_info)
161
168
  return config
162
169
 
163
170
  # --- remote endpoints ---
@@ -170,7 +177,7 @@ class GeminiClientAdapter(CopilotClientAdapter):
170
177
  transport = "http"
171
178
  elif transport not in ("sse", "http", "streamable-http"):
172
179
  raise ValueError(
173
- f"Unsupported remote transport '{transport}' for Gemini. "
180
+ f"Unsupported remote transport '{transport}' for {self.target_name}. "
174
181
  f"Server: {server_info.get('name', 'unknown')}. "
175
182
  f"Supported transports: http, sse, streamable-http."
176
183
  )
@@ -192,9 +199,10 @@ class GeminiClientAdapter(CopilotClientAdapter):
192
199
 
193
200
  if config.get("headers"):
194
201
  self._warn_input_variables(
195
- config["headers"], server_info.get("name", ""), "Gemini CLI"
202
+ config["headers"], server_info.get("name", ""), self.target_name
196
203
  )
197
204
 
205
+ self._merge_extra(config, server_info)
198
206
  return config
199
207
 
200
208
  # --- local packages ---
@@ -208,6 +216,7 @@ class GeminiClientAdapter(CopilotClientAdapter):
208
216
 
209
217
  package = self._select_best_package(packages)
210
218
  if not package:
219
+ self._merge_extra(config, server_info)
211
220
  return config
212
221
 
213
222
  registry_name = self._infer_registry_name(package)
@@ -245,6 +254,7 @@ class GeminiClientAdapter(CopilotClientAdapter):
245
254
  if resolved_env:
246
255
  config["env"] = resolved_env
247
256
 
257
+ self._merge_extra(config, server_info)
248
258
  return config
249
259
 
250
260
  def configure_mcp_server(
@@ -256,19 +266,20 @@ class GeminiClientAdapter(CopilotClientAdapter):
256
266
  server_info_cache=None,
257
267
  runtime_vars=None,
258
268
  ):
259
- """Configure an MCP server in ``.gemini/settings.json``.
269
+ """Configure an MCP server in the target's ``settings.json``.
260
270
 
261
271
  Delegates to the parent for config formatting, then writes to
262
- the Gemini CLI settings file.
272
+ the target CLI settings file.
263
273
  """
264
274
  if not server_url:
265
275
  _rich_error("server_url cannot be empty", symbol="error")
266
276
  return False
267
277
 
268
- if not self.user_scope and not self._get_gemini_dir().is_dir():
278
+ if not self.user_scope and not self._get_config_dir().is_dir():
269
279
  logger.debug(
270
- "Gemini opt-in gate: %s absent, skipping configure_mcp_server",
271
- self._get_gemini_dir(),
280
+ "%s opt-in gate: %s absent, skipping configure_mcp_server",
281
+ self.target_name,
282
+ self._get_config_dir(),
272
283
  )
273
284
  return True
274
285
 
@@ -292,10 +303,16 @@ class GeminiClientAdapter(CopilotClientAdapter):
292
303
  server_config = self._format_server_config(server_info, env_overrides, runtime_vars)
293
304
  self.update_config({config_key: server_config})
294
305
 
295
- _rich_success(f"Configured MCP server '{config_key}' for Gemini CLI", symbol="success")
306
+ _rich_success(
307
+ f"Configured MCP server '{config_key}' for {self.target_name}",
308
+ symbol="success",
309
+ )
296
310
  return True
297
311
 
298
312
  except Exception as e:
299
- logger.debug("Gemini MCP configuration failed: %s", e)
300
- _rich_error("Failed to configure MCP server for Gemini CLI", symbol="error")
313
+ logger.debug("%s MCP configuration failed: %s", self.target_name, e)
314
+ _rich_error(
315
+ f"Failed to configure MCP server for {self.target_name}",
316
+ symbol="error",
317
+ )
301
318
  return False
@@ -130,6 +130,7 @@ class KiroClientAdapter(CopilotClientAdapter):
130
130
  for arg in raw.get("args") or []
131
131
  ]
132
132
  self._copy_kiro_extensions(config, server_info)
133
+ self._merge_extra(config, server_info)
133
134
  return config
134
135
 
135
136
  remotes = server_info.get("remotes", [])
@@ -157,6 +158,7 @@ class KiroClientAdapter(CopilotClientAdapter):
157
158
  config["headers"] = headers
158
159
  self._warn_input_variables(headers, server_info.get("name", ""), "Kiro")
159
160
  self._copy_kiro_extensions(config, server_info)
161
+ self._merge_extra(config, server_info)
160
162
  return config
161
163
 
162
164
  packages = server_info.get("packages", [])
@@ -180,6 +182,7 @@ class KiroClientAdapter(CopilotClientAdapter):
180
182
  f"Server: {server_info.get('name', 'unknown')}."
181
183
  )
182
184
  self._copy_kiro_extensions(config, server_info)
185
+ self._merge_extra(config, server_info)
183
186
  return config
184
187
 
185
188
  def configure_mcp_server(
@@ -281,6 +281,7 @@ class VSCodeClientAdapter(MCPClientAdapter):
281
281
  input_vars.extend(
282
282
  self._extract_input_variables(env_translated, server_info.get("name", ""))
283
283
  )
284
+ self._merge_extra(server_config, server_info)
284
285
  return server_config, input_vars
285
286
 
286
287
  # Check for packages information
@@ -448,6 +449,7 @@ class VSCodeClientAdapter(MCPClientAdapter):
448
449
  f"Server: {server_info.get('name', 'unknown')}"
449
450
  )
450
451
 
452
+ self._merge_extra(server_config, server_info)
451
453
  return server_config, input_vars
452
454
 
453
455
  @staticmethod
@@ -13,12 +13,10 @@ from ..integration.targets import KNOWN_TARGETS
13
13
  # .github/ is the canonical interop prefix -- install always creates it, so
14
14
  # all non-github targets map FROM .github/. The copilot target additionally
15
15
  # maps FROM .claude/ for the common case of Claude-first projects packing
16
- # for Copilot. Cursor/opencode sources are niche; if someone publishes
17
- # skills exclusively under .cursor/, they must pack with --target cursor.
18
- #
19
- # Windsurf converts agents -> skills (lossy: AGENTS.md format is collapsed
20
- # into the windsurf skill envelope), so .github/agents/ maps to
21
- # .windsurf/skills/.
16
+ # for Copilot. Cursor, opencode, and windsurf skills converge on the
17
+ # shared .agents/skills/ convention rather than bespoke per-target paths.
18
+ # Windsurf agents still collapse into .windsurf/skills/ because the target
19
+ # has no distinct agent envelope.
22
20
  _CROSS_TARGET_MAPS: dict[str, dict[str, str]] = {
23
21
  "claude": {
24
22
  ".github/skills/": ".claude/skills/",
@@ -33,11 +31,11 @@ _CROSS_TARGET_MAPS: dict[str, dict[str, str]] = {
33
31
  ".claude/agents/": ".github/agents/",
34
32
  },
35
33
  "cursor": {
36
- ".github/skills/": ".cursor/skills/",
34
+ ".github/skills/": ".agents/skills/",
37
35
  ".github/agents/": ".cursor/agents/",
38
36
  },
39
37
  "opencode": {
40
- ".github/skills/": ".opencode/skills/",
38
+ ".github/skills/": ".agents/skills/",
41
39
  ".github/agents/": ".opencode/agents/",
42
40
  },
43
41
  "codex": {
@@ -45,7 +43,7 @@ _CROSS_TARGET_MAPS: dict[str, dict[str, str]] = {
45
43
  ".github/agents/": ".codex/agents/",
46
44
  },
47
45
  "windsurf": {
48
- ".github/skills/": ".windsurf/skills/",
46
+ ".github/skills/": ".agents/skills/",
49
47
  ".github/agents/": ".windsurf/skills/",
50
48
  },
51
49
  "agent-skills": {
@@ -108,6 +108,12 @@ def _collect_apm_components(apm_dir: Path) -> list[tuple[Path, str]]:
108
108
  # commands/ -> commands/
109
109
  _collect_recursive(apm_dir / "commands", "commands", components)
110
110
 
111
+ # extensions/ -> extensions/ (canvas extensions, experimental Copilot-only).
112
+ # Preserved verbatim so an offline bundle can carry a canvas; the files are
113
+ # inert until the consumer enables the ``canvas`` experimental flag AND
114
+ # approves the package via allowExecutables / ``apm approve`` at install time.
115
+ _collect_recursive(apm_dir / "extensions", "extensions", components)
116
+
111
117
  return components
112
118
 
113
119
 
@@ -118,7 +124,7 @@ def _collect_root_plugin_components(project_root: Path) -> list[tuple[Path, str]
118
124
  ``skills/``, etc. at the repo root) have their files picked up here.
119
125
  """
120
126
  components: list[tuple[Path, str]] = []
121
- for dir_name in ("agents", "skills", "commands", "instructions"):
127
+ for dir_name in ("agents", "skills", "commands", "instructions", "extensions"):
122
128
  _collect_recursive(project_root / dir_name, dir_name, components)
123
129
  return components
124
130
 
@@ -30,6 +30,7 @@ class UnpackResult:
30
30
  skipped_count: int = 0
31
31
  security_warnings: int = 0
32
32
  security_critical: int = 0
33
+ canvas_blocked: int = 0
33
34
  pack_meta: dict = field(default_factory=dict)
34
35
 
35
36
 
@@ -163,6 +164,27 @@ def unpack_bundle(
163
164
  if dep_files:
164
165
  dep_file_map[dep_key] = dep_files
165
166
 
167
+ # Security + feature gate: canvas extensions are executable Node
168
+ # bundles (``extension.mjs``). ``apm unpack`` (deprecated) copies
169
+ # deployed files verbatim WITHOUT routing through ``CanvasIntegrator``.
170
+ # When the canvas feature flag is OFF, drop paths silently.
171
+ # When ON, canvas files are allowed (apm unpack has no project context
172
+ # so no allowExecutables enforcement is available; the user is assumed
173
+ # to understand what they are unpacking for this deprecated command).
174
+ canvas_blocked = 0
175
+ from ..core.experimental import is_enabled
176
+ from ..integration.canvas_integrator import is_canvas_bundle_path
177
+
178
+ if not is_enabled("canvas"):
179
+ _blocked = {f for f in unique_files if is_canvas_bundle_path(f)}
180
+ if _blocked:
181
+ canvas_blocked = len(_blocked)
182
+ unique_files = [f for f in unique_files if f not in _blocked]
183
+ for _k in list(dep_file_map):
184
+ dep_file_map[_k] = [f for f in dep_file_map[_k] if f not in _blocked]
185
+ if not dep_file_map[_k]:
186
+ del dep_file_map[_k]
187
+
166
188
  # 3. Verify completeness
167
189
  verified = True
168
190
  if not skip_verify:
@@ -211,6 +233,7 @@ def unpack_bundle(
211
233
  dependency_files=dep_file_map,
212
234
  security_warnings=security_warnings,
213
235
  security_critical=security_critical,
236
+ canvas_blocked=canvas_blocked,
214
237
  pack_meta=pack_meta,
215
238
  )
216
239
 
@@ -254,6 +277,7 @@ def unpack_bundle(
254
277
  skipped_count=skipped,
255
278
  security_warnings=security_warnings,
256
279
  security_critical=security_critical,
280
+ canvas_blocked=canvas_blocked,
257
281
  pack_meta=pack_meta,
258
282
  )
259
283
  finally:
@@ -18,6 +18,7 @@ from apm_cli.commands._helpers import (
18
18
  _check_and_notify_updates,
19
19
  print_version,
20
20
  )
21
+ from apm_cli.commands.approve import approve_cmd, deny_cmd
21
22
  from apm_cli.commands.audit import audit
22
23
  from apm_cli.commands.cache import cache
23
24
  from apm_cli.commands.compile import compile as compile_cmd
@@ -147,8 +148,10 @@ def cli(ctx, verbose: bool) -> None:
147
148
 
148
149
 
149
150
  # Register command groups
151
+ cli.add_command(approve_cmd, name="approve")
150
152
  cli.add_command(audit)
151
153
  cli.add_command(cache)
154
+ cli.add_command(deny_cmd, name="deny")
152
155
  cli.add_command(deps)
153
156
  cli.add_command(view_cmd)
154
157
  # Hidden backward-compatible alias: ``apm info`` → ``apm view``