apm-cli 0.18.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.18.0 → apm_cli-0.19.0}/AUTHORS +1 -0
  2. {apm_cli-0.18.0/src/apm_cli.egg-info → apm_cli-0.19.0}/PKG-INFO +1 -1
  3. {apm_cli-0.18.0 → apm_cli-0.19.0}/pyproject.toml +1 -1
  4. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/base.py +8 -5
  5. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/claude.py +1 -6
  6. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/codex.py +1 -13
  7. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/copilot.py +1 -13
  8. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/bundle/lockfile_enrichment.py +3 -0
  9. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/cli.py +57 -1
  10. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/audit.py +82 -23
  11. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/compile/cli.py +14 -3
  12. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/experimental.py +2 -2
  13. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/publish.py +34 -34
  14. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/agents_compiler.py +25 -8
  15. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/auth.py +148 -18
  16. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/experimental.py +10 -0
  17. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/safe_installer.py +2 -0
  18. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/target_detection.py +31 -1
  19. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/download_strategies.py +48 -3
  20. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/plugin_parser.py +123 -15
  21. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/drift.py +19 -2
  22. apm_cli-0.19.0/src/apm_cli/install/manifest_reconcile.py +112 -0
  23. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/local_content.py +109 -13
  24. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/lockfile.py +46 -10
  25. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/post_deps_local.py +17 -3
  26. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/targets.py +248 -268
  27. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/services.py +88 -4
  28. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/base_integrator.py +7 -1
  29. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/hook_integrator.py +131 -4
  30. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/instruction_integrator.py +83 -21
  31. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/skill_integrator.py +33 -7
  32. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/targets.py +103 -3
  33. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/dependency/mcp.py +29 -1
  34. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/dependency/reference.py +9 -3
  35. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/skillspector.py +18 -5
  36. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/github_host.py +24 -5
  37. {apm_cli-0.18.0 → apm_cli-0.19.0/src/apm_cli.egg-info}/PKG-INFO +1 -1
  38. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli.egg-info/SOURCES.txt +1 -0
  39. {apm_cli-0.18.0 → apm_cli-0.19.0}/LICENSE +0 -0
  40. {apm_cli-0.18.0 → apm_cli-0.19.0}/NOTICE +0 -0
  41. {apm_cli-0.18.0 → apm_cli-0.19.0}/README.md +0 -0
  42. {apm_cli-0.18.0 → apm_cli-0.19.0}/setup.cfg +0 -0
  43. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/__init__.py +0 -0
  44. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/__init__.py +0 -0
  45. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/__init__.py +0 -0
  46. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/_mcp_runtime_args.py +0 -0
  47. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/cursor.py +0 -0
  48. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/gemini.py +0 -0
  49. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/intellij.py +0 -0
  50. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/opencode.py +0 -0
  51. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/vscode.py +0 -0
  52. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/client/windsurf.py +0 -0
  53. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/package_manager/__init__.py +0 -0
  54. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/package_manager/base.py +0 -0
  55. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/adapters/package_manager/default_manager.py +0 -0
  56. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/bundle/__init__.py +0 -0
  57. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/bundle/local_bundle.py +0 -0
  58. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/bundle/packer.py +0 -0
  59. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/bundle/plugin_exporter.py +0 -0
  60. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/bundle/unpacker.py +0 -0
  61. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/cache/__init__.py +0 -0
  62. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/cache/git_cache.py +0 -0
  63. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/cache/http_cache.py +0 -0
  64. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/cache/integrity.py +0 -0
  65. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/cache/locking.py +0 -0
  66. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/cache/paths.py +0 -0
  67. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/cache/url_normalize.py +0 -0
  68. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/__init__.py +0 -0
  69. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/_apm_yml_writer.py +0 -0
  70. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/_helpers.py +0 -0
  71. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/cache.py +0 -0
  72. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/compile/__init__.py +0 -0
  73. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/compile/watcher.py +0 -0
  74. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/config.py +0 -0
  75. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/deps/__init__.py +0 -0
  76. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/deps/_utils.py +0 -0
  77. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/deps/cli.py +0 -0
  78. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/deps/why.py +0 -0
  79. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/doctor.py +0 -0
  80. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/find.py +0 -0
  81. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/init.py +0 -0
  82. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/install.py +0 -0
  83. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/list_cmd.py +0 -0
  84. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/lock.py +0 -0
  85. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/__init__.py +0 -0
  86. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/audit.py +0 -0
  87. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/check.py +0 -0
  88. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/doctor.py +0 -0
  89. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/init.py +0 -0
  90. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/migrate.py +0 -0
  91. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/outdated.py +0 -0
  92. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/plugin/__init__.py +0 -0
  93. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/plugin/add.py +0 -0
  94. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/plugin/remove.py +0 -0
  95. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/plugin/set.py +0 -0
  96. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/publish.py +0 -0
  97. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/marketplace/validate.py +0 -0
  98. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/mcp.py +0 -0
  99. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/outdated.py +0 -0
  100. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/pack.py +0 -0
  101. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/plugin/__init__.py +0 -0
  102. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/plugin/init.py +0 -0
  103. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/policy.py +0 -0
  104. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/prune.py +0 -0
  105. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/run.py +0 -0
  106. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/runtime.py +0 -0
  107. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/self_update.py +0 -0
  108. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/targets.py +0 -0
  109. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/uninstall/__init__.py +0 -0
  110. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/uninstall/cli.py +0 -0
  111. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/uninstall/engine.py +0 -0
  112. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/update.py +0 -0
  113. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/commands/view.py +0 -0
  114. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/__init__.py +0 -0
  115. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/build_id.py +0 -0
  116. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/claude_formatter.py +0 -0
  117. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/constants.py +0 -0
  118. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/constitution.py +0 -0
  119. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/constitution_block.py +0 -0
  120. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/context_optimizer.py +0 -0
  121. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/distributed_compiler.py +0 -0
  122. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/gemini_formatter.py +0 -0
  123. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/injector.py +0 -0
  124. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/link_resolver.py +0 -0
  125. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/managed_section.py +0 -0
  126. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/output_writer.py +0 -0
  127. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/compilation/template_builder.py +0 -0
  128. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/config.py +0 -0
  129. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/constants.py +0 -0
  130. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/__init__.py +0 -0
  131. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/apm_yml.py +0 -0
  132. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/azure_cli.py +0 -0
  133. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/build_orchestrator.py +0 -0
  134. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/command_logger.py +0 -0
  135. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/conflict_detector.py +0 -0
  136. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/docker_args.py +0 -0
  137. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/errors.py +0 -0
  138. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/install_audit.py +0 -0
  139. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/null_logger.py +0 -0
  140. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/operations.py +0 -0
  141. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/plugin_manifest.py +0 -0
  142. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/scope.py +0 -0
  143. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/script_runner.py +0 -0
  144. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/core/token_manager.py +0 -0
  145. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/__init__.py +0 -0
  146. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/_shared.py +0 -0
  147. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/aggregator.py +0 -0
  148. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/apm_resolver.py +0 -0
  149. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/artifactory_entry.py +0 -0
  150. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/artifactory_orchestrator.py +0 -0
  151. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/bare_cache.py +0 -0
  152. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/clone_engine.py +0 -0
  153. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/dependency_graph.py +0 -0
  154. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/git_auth_env.py +0 -0
  155. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/git_reference_resolver.py +0 -0
  156. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/git_remote_ops.py +0 -0
  157. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/git_semver_resolver.py +0 -0
  158. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/github_downloader.py +0 -0
  159. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/github_downloader_validation.py +0 -0
  160. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/host_backends.py +0 -0
  161. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/installed_package.py +0 -0
  162. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/lockfile.py +0 -0
  163. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/outdated_row.py +0 -0
  164. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/package_validator.py +0 -0
  165. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/path_anchoring.py +0 -0
  166. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/__init__.py +0 -0
  167. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/auth.py +0 -0
  168. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/client.py +0 -0
  169. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/config_loader.py +0 -0
  170. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/extractor.py +0 -0
  171. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/feature_gate.py +0 -0
  172. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/outdated.py +0 -0
  173. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/resolver.py +0 -0
  174. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry/semver.py +0 -0
  175. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/registry_proxy.py +0 -0
  176. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/shared_clone_cache.py +0 -0
  177. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/tiered_ref_resolver.py +0 -0
  178. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/transport_selection.py +0 -0
  179. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/verifier.py +0 -0
  180. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/deps/why_walker.py +0 -0
  181. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/drift.py +0 -0
  182. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/factory.py +0 -0
  183. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/__init__.py +0 -0
  184. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/artifactory_resolver.py +0 -0
  185. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/cache_pin.py +0 -0
  186. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/context.py +0 -0
  187. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/errors.py +0 -0
  188. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/gitlab_resolver.py +0 -0
  189. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/heals/__init__.py +0 -0
  190. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/heals/base.py +0 -0
  191. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/heals/branch_ref_drift.py +0 -0
  192. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/heals/buggy_lockfile_recovery.py +0 -0
  193. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/helpers/__init__.py +0 -0
  194. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/helpers/security_scan.py +0 -0
  195. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/insecure_policy.py +0 -0
  196. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/local_bundle_handler.py +0 -0
  197. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/lsp/__init__.py +0 -0
  198. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/lsp/integration.py +0 -0
  199. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/__init__.py +0 -0
  200. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/args.py +0 -0
  201. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/command.py +0 -0
  202. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/conflicts.py +0 -0
  203. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/entry.py +0 -0
  204. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/registry.py +0 -0
  205. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/warnings.py +0 -0
  206. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/mcp/writer.py +0 -0
  207. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/package_resolution.py +0 -0
  208. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/package_selection.py +0 -0
  209. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/__init__.py +0 -0
  210. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/_redownload.py +0 -0
  211. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/_skip_logic.py +0 -0
  212. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/audit.py +0 -0
  213. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/cleanup.py +0 -0
  214. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/download.py +0 -0
  215. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/finalize.py +0 -0
  216. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/heal.py +0 -0
  217. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/integrate.py +0 -0
  218. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/policy_gate.py +0 -0
  219. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/policy_target_check.py +0 -0
  220. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/phases/resolve.py +0 -0
  221. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/pipeline.py +0 -0
  222. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/plan.py +0 -0
  223. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/presentation/__init__.py +0 -0
  224. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/presentation/dry_run.py +0 -0
  225. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/registry_wiring.py +0 -0
  226. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/request.py +0 -0
  227. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/root_redirect.py +0 -0
  228. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/service.py +0 -0
  229. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/skill_path_migration.py +0 -0
  230. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/sources.py +0 -0
  231. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/summary.py +0 -0
  232. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/template.py +0 -0
  233. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/install/validation.py +0 -0
  234. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/__init__.py +0 -0
  235. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/_shared.py +0 -0
  236. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/agent_integrator.py +0 -0
  237. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/cleanup.py +0 -0
  238. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/command_integrator.py +0 -0
  239. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/copilot_app_db.py +0 -0
  240. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/copilot_app_project.py +0 -0
  241. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/copilot_app_workflow_integrator.py +0 -0
  242. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/copilot_app_ws.py +0 -0
  243. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/copilot_cowork_paths.py +0 -0
  244. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/coverage.py +0 -0
  245. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/dispatch.py +0 -0
  246. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/lsp_integrator.py +0 -0
  247. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/mcp_integrator.py +0 -0
  248. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/mcp_integrator_install.py +0 -0
  249. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/opencode_frontmatter.py +0 -0
  250. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/prompt_integrator.py +0 -0
  251. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/skill_transformer.py +0 -0
  252. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/integration/utils.py +0 -0
  253. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/__init__.py +0 -0
  254. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/_git_utils.py +0 -0
  255. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/_io.py +0 -0
  256. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/_shared.py +0 -0
  257. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/audit.py +0 -0
  258. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/builder.py +0 -0
  259. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/client.py +0 -0
  260. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/diagnostics.py +0 -0
  261. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/drift_check.py +0 -0
  262. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/errors.py +0 -0
  263. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/git_stderr.py +0 -0
  264. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/init_template.py +0 -0
  265. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/migration.py +0 -0
  266. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/models.py +0 -0
  267. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/output_mappers.py +0 -0
  268. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/output_profiles.py +0 -0
  269. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/pr_integration.py +0 -0
  270. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/publisher.py +0 -0
  271. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/ref_resolver.py +0 -0
  272. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/registry.py +0 -0
  273. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/resolver.py +0 -0
  274. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/semver.py +0 -0
  275. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/shadow_detector.py +0 -0
  276. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/tag_pattern.py +0 -0
  277. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/validator.py +0 -0
  278. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/version_check.py +0 -0
  279. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/version_pins.py +0 -0
  280. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/version_resolver.py +0 -0
  281. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/yml_editor.py +0 -0
  282. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/marketplace/yml_schema.py +0 -0
  283. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/__init__.py +0 -0
  284. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/apm_package.py +0 -0
  285. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/dependency/__init__.py +0 -0
  286. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/dependency/lsp.py +0 -0
  287. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/dependency/types.py +0 -0
  288. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/format_detection.py +0 -0
  289. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/plugin.py +0 -0
  290. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/results.py +0 -0
  291. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/models/validation.py +0 -0
  292. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/output/__init__.py +0 -0
  293. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/output/formatters.py +0 -0
  294. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/output/models.py +0 -0
  295. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/output/script_formatters.py +0 -0
  296. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/__init__.py +0 -0
  297. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/_constraint_pinning.py +0 -0
  298. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/_help_text.py +0 -0
  299. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/_shared.py +0 -0
  300. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/ci_checks.py +0 -0
  301. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/discovery.py +0 -0
  302. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/inheritance.py +0 -0
  303. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/install_preflight.py +0 -0
  304. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/matcher.py +0 -0
  305. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/models.py +0 -0
  306. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/outcome_routing.py +0 -0
  307. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/parser.py +0 -0
  308. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/policy_checks.py +0 -0
  309. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/project_config.py +0 -0
  310. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/policy/schema.py +0 -0
  311. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/primitives/__init__.py +0 -0
  312. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/primitives/discovery.py +0 -0
  313. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/primitives/models.py +0 -0
  314. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/primitives/parser.py +0 -0
  315. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/registry/__init__.py +0 -0
  316. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/registry/client.py +0 -0
  317. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/registry/integration.py +0 -0
  318. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/registry/operations.py +0 -0
  319. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/runtime/__init__.py +0 -0
  320. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/runtime/base.py +0 -0
  321. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/runtime/codex_runtime.py +0 -0
  322. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/runtime/copilot_runtime.py +0 -0
  323. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/runtime/factory.py +0 -0
  324. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/runtime/llm_runtime.py +0 -0
  325. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/runtime/manager.py +0 -0
  326. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/runtime/utils.py +0 -0
  327. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/__init__.py +0 -0
  328. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/audit_report.py +0 -0
  329. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/content_scanner.py +0 -0
  330. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/__init__.py +0 -0
  331. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/base.py +0 -0
  332. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/gate.py +0 -0
  333. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/generic_sarif.py +0 -0
  334. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/options.py +0 -0
  335. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/registry.py +0 -0
  336. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/runner.py +0 -0
  337. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/external/sarif_ingest.py +0 -0
  338. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/file_scanner.py +0 -0
  339. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/security/gate.py +0 -0
  340. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/update_policy.py +0 -0
  341. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/__init__.py +0 -0
  342. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/atomic_io.py +0 -0
  343. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/console.py +0 -0
  344. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/content_hash.py +0 -0
  345. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/diagnostics.py +0 -0
  346. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/exclude.py +0 -0
  347. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/file_ops.py +0 -0
  348. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/git_env.py +0 -0
  349. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/git_sparse.py +0 -0
  350. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/guards.py +0 -0
  351. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/helpers.py +0 -0
  352. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/install_tui.py +0 -0
  353. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/normalization.py +0 -0
  354. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/path_security.py +0 -0
  355. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/paths.py +0 -0
  356. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/patterns.py +0 -0
  357. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/perf_stats.py +0 -0
  358. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/reflink.py +0 -0
  359. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/short_sha.py +0 -0
  360. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/subprocess_env.py +0 -0
  361. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/version_checker.py +0 -0
  362. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/utils/yaml_io.py +0 -0
  363. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/version.py +0 -0
  364. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/workflow/__init__.py +0 -0
  365. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/workflow/discovery.py +0 -0
  366. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/workflow/parser.py +0 -0
  367. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli/workflow/runner.py +0 -0
  368. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli.egg-info/dependency_links.txt +0 -0
  369. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli.egg-info/entry_points.txt +0 -0
  370. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli.egg-info/requires.txt +0 -0
  371. {apm_cli-0.18.0 → apm_cli-0.19.0}/src/apm_cli.egg-info/top_level.txt +0 -0
  372. {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_apm_package_models.py +0 -0
  373. {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_apm_resolver.py +0 -0
  374. {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_codex_docker_args_fix.py +0 -0
  375. {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_codex_empty_string_and_defaults.py +0 -0
  376. {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_collision_integration.py +0 -0
  377. {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_console.py +0 -0
  378. {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_distributed_compilation.py +0 -0
  379. {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_empty_string_and_defaults.py +0 -0
  380. {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_enhanced_discovery.py +0 -0
  381. {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_github_downloader.py +0 -0
  382. {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_github_downloader_token_precedence.py +0 -0
  383. {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_lockfile.py +0 -0
  384. {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_runnable_prompts.py +0 -0
  385. {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_runtime_manager_token_precedence.py +0 -0
  386. {apm_cli-0.18.0 → apm_cli-0.19.0}/tests/test_token_manager.py +0 -0
  387. {apm_cli-0.18.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.18.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.18.0"
7
+ version = "0.19.0"
8
8
  description = "MCP configuration tool"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -633,22 +633,25 @@ class MCPClientAdapter(ABC):
633
633
  return server_info
634
634
 
635
635
  @staticmethod
636
- def _determine_config_key(server_url: str, server_name: str) -> str:
636
+ def _determine_config_key(server_url: str, server_name: str | None) -> str:
637
637
  """Return the configuration key to use for *server_url*/*server_name*.
638
638
 
639
- The caller-supplied *server_name* takes precedence; if empty the last
640
- path segment of *server_url* is used as a fallback, which mirrors the
641
- 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.
642
643
 
643
644
  Args:
644
645
  server_url: Registry reference used as fallback source.
645
- server_name: Explicit caller-supplied name (may be empty string).
646
+ server_name: Explicit caller-supplied name, if any.
646
647
 
647
648
  Returns:
648
649
  Non-empty configuration key string.
649
650
  """
650
651
  if server_name:
651
652
  return server_name
653
+ if server_url.startswith("@") and server_url.count("/") == 1:
654
+ return server_url
652
655
  if "/" in server_url:
653
656
  return server_url.split("/")[-1]
654
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)
@@ -206,19 +206,7 @@ class CopilotClientAdapter(MCPClientAdapter):
206
206
  # Generate server configuration with environment and runtime variable resolution
207
207
  server_config = self._format_server_config(server_info, env_overrides, runtime_vars)
208
208
 
209
- # Determine the server name for configuration key
210
- if server_name:
211
- # Use explicitly provided server name
212
- config_key = server_name
213
- else: # noqa: PLR5501
214
- # Extract name from server_url (part after last slash)
215
- # For URLs like "microsoft/azure-devops-mcp" -> "azure-devops-mcp"
216
- # For URLs like "github/github-mcp-server" -> "github-mcp-server"
217
- if "/" in server_url: # noqa: SIM108
218
- config_key = server_url.split("/")[-1]
219
- else:
220
- # Fallback to full server_url if no slash
221
- config_key = server_url
209
+ config_key = self._determine_config_key(server_url, server_name)
222
210
 
223
211
  # Update configuration using the chosen key
224
212
  self.update_config({config_key: server_config})
@@ -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)
@@ -10,20 +10,21 @@ resolver (``apm experimental enable registries``).
10
10
  from __future__ import annotations
11
11
 
12
12
  import re
13
- import tarfile
13
+ import zipfile
14
14
  from pathlib import Path
15
15
 
16
16
  import click
17
17
 
18
18
  from ..core.command_logger import CommandLogger
19
19
  from ..deps.registry.feature_gate import require_package_registry_enabled
20
+ from ..utils.paths import portable_relpath
20
21
 
21
22
  _PUBLISH_HELP = """\
22
23
  Publish a package to a registry.
23
24
 
24
- Reads apm.yml for the package name/version, packs a flat registry archive
25
- (``apm.yml`` + ``.apm/`` at the tarball root — not ``apm pack`` plugin bundles),
26
- or uses a pre-built tarball via --tarball, then uploads to the registry via
25
+ Reads apm.yml for the package name/version, packs a flat registry zip archive
26
+ (``apm.yml`` + ``.apm/`` at the archive root — not ``apm pack`` plugin bundles),
27
+ or uses a pre-built zip via --zip, then uploads to the registry via
27
28
  PUT /v1/packages/{owner}/{repo}/versions/{version}.
28
29
 
29
30
  Requires the 'registries' experimental feature:
@@ -37,8 +38,8 @@ Examples:
37
38
  # Choose a registry when multiple are configured:
38
39
  apm publish --registry corp-main
39
40
 
40
- # Publish a pre-built tarball (skip the pack step):
41
- apm publish --tarball ./build/my-package-1.0.0.tar.gz
41
+ # Publish a pre-built zip (skip the pack step):
42
+ apm publish --zip ./build/my-package-1.0.0.zip
42
43
 
43
44
  # Preview what would be uploaded:
44
45
  apm publish --dry-run
@@ -60,16 +61,16 @@ Examples:
60
61
  help="Package identity to publish as (owner/repo, e.g. acme/my-skill).",
61
62
  )
62
63
  @click.option(
63
- "--tarball",
64
- "tarball_path",
64
+ "--zip",
65
+ "zip_path",
65
66
  type=click.Path(exists=True, dir_okay=False),
66
67
  default=None,
67
- help="Path to a pre-built .tar.gz tarball. Skips the pack step.",
68
+ help="Path to a pre-built .zip archive. Skips the pack step.",
68
69
  )
69
70
  @click.option("--dry-run", is_flag=True, default=False, help="Preview without uploading.")
70
71
  @click.option("--verbose", "-v", is_flag=True, help="Show detailed output.")
71
72
  @click.pass_context
72
- def publish_cmd(ctx, registry_name, package_id, tarball_path, dry_run, verbose):
73
+ def publish_cmd(ctx, registry_name, package_id, zip_path, dry_run, verbose):
73
74
  """Publish a package version to a registry."""
74
75
  require_package_registry_enabled("apm publish")
75
76
 
@@ -100,18 +101,18 @@ def publish_cmd(ctx, registry_name, package_id, tarball_path, dry_run, verbose):
100
101
  registry_name = _resolve_registry_name(registry_name, registries)
101
102
  base_url = registries[registry_name]
102
103
 
103
- # ----------------------------------------------------------- tarball
104
- if tarball_path:
105
- tarball = Path(tarball_path)
104
+ # ----------------------------------------------------------- zip archive
105
+ if zip_path:
106
+ archive = Path(zip_path)
106
107
  else:
107
- tarball = _pack_archive(project_root, apm_yml_path, pkg, logger, verbose)
108
+ archive = _pack_archive(project_root, apm_yml_path, pkg, logger, verbose)
108
109
 
109
- tarball_size = tarball.stat().st_size
110
+ archive_size = archive.stat().st_size
110
111
 
111
112
  # ----------------------------------------------------------- dry-run
112
113
  if dry_run:
113
114
  logger.info(f"Would publish {owner}/{repo}@{version} to {registry_name} ({base_url})")
114
- logger.info(f" tarball : {tarball} ({tarball_size:,} bytes)")
115
+ logger.info(f" archive : {archive} ({archive_size:,} bytes)")
115
116
  logger.info("(dry-run — nothing uploaded)")
116
117
  return
117
118
 
@@ -124,9 +125,9 @@ def publish_cmd(ctx, registry_name, package_id, tarball_path, dry_run, verbose):
124
125
 
125
126
  logger.info(f"Publishing {owner}/{repo}@{version} to {registry_name} …")
126
127
 
127
- tarball_bytes = tarball.read_bytes()
128
+ archive_bytes = archive.read_bytes()
128
129
  try:
129
- result = client.publish_version(owner, repo, version, tarball_bytes)
130
+ result = client.publish_version(owner, repo, version, archive_bytes)
130
131
  except RegistryError as exc:
131
132
  _handle_publish_error(exc, owner, repo, version, registry_name, base_url)
132
133
 
@@ -184,14 +185,14 @@ def _resolve_registry_name(name: str | None, registries: dict[str, str]) -> str:
184
185
 
185
186
 
186
187
  def _pack_archive(project_root: Path, apm_yml_path: Path, pkg, logger, verbose: bool) -> Path:
187
- """Build a flat registry tarball (``apm.yml`` + ``.apm/`` at archive root).
188
+ """Build a flat registry zip archive (``apm.yml`` + ``.apm/`` at archive root).
188
189
 
189
190
  Also includes ``README.md``, ``CHANGELOG.md``, and ``LICENSE`` (case-
190
191
  insensitive, no extension required for LICENSE) when present — matching
191
192
  npm's behaviour of bundling standard root-level documentation files.
192
193
 
193
194
  Registry servers and ``apm install`` expect the APM source layout at the
194
- tarball root — not the ``apm pack --archive`` plugin bundle wrapper
195
+ archive root — not the ``apm pack --archive`` plugin bundle wrapper
195
196
  (``{name}-{version}/plugin.json``). See registry HTTP API §6.
196
197
  """
197
198
  apm_dir = project_root / ".apm"
@@ -199,10 +200,10 @@ def _pack_archive(project_root: Path, apm_yml_path: Path, pkg, logger, verbose:
199
200
  raise click.ClickException(
200
201
  "Registry publish requires a flat APM package (.apm/ directory).\n"
201
202
  "Add .apm/ with your primitives (skills, instructions, etc.), "
202
- "or pass --tarball with a pre-built flat archive."
203
+ "or pass --zip with a pre-built flat archive."
203
204
  )
204
205
 
205
- archive_name = f"{pkg.name}-{pkg.version}.tar.gz"
206
+ archive_name = f"{pkg.name}-{pkg.version}.zip"
206
207
  dest = project_root / archive_name
207
208
  if dest.exists():
208
209
  dest.unlink()
@@ -210,21 +211,20 @@ def _pack_archive(project_root: Path, apm_yml_path: Path, pkg, logger, verbose:
210
211
  if verbose:
211
212
  logger.info(f"Packing flat registry archive -> {dest.name}")
212
213
 
213
- def _tar_filter(ti: tarfile.TarInfo) -> tarfile.TarInfo | None:
214
- # Skip macOS AppleDouble sidecars (._*) that break registry validation.
215
- if any(part.startswith("._") for part in Path(ti.name).parts):
216
- return None
217
- if Path(ti.name).name == ".DS_Store":
218
- return None
219
- return ti
214
+ def _should_skip(path: Path) -> bool:
215
+ # Skip macOS AppleDouble sidecars (._*) and .DS_Store that break registry validation.
216
+ return any(part.startswith("._") for part in path.parts) or path.name == ".DS_Store"
220
217
 
221
218
  # Standard root-level doc files included when present (npm parity).
222
219
  # Matched case-insensitively; LICENSE has no required extension.
223
220
  _DOC_CANDIDATES = ("README.md", "CHANGELOG.md", "LICENSE", "LICENCE")
224
221
 
225
- with tarfile.open(dest, mode="w:gz") as tar:
226
- tar.add(apm_yml_path, arcname="apm.yml", filter=_tar_filter, recursive=False)
227
- tar.add(apm_dir, arcname=".apm", filter=_tar_filter)
222
+ with zipfile.ZipFile(dest, mode="w", compression=zipfile.ZIP_DEFLATED) as zf:
223
+ if not _should_skip(apm_yml_path):
224
+ zf.write(apm_yml_path, arcname="apm.yml")
225
+ for file in sorted(apm_dir.rglob("*")):
226
+ if file.is_file() and not file.is_symlink() and not _should_skip(file):
227
+ zf.write(file, arcname=portable_relpath(file, project_root))
228
228
  for candidate in _DOC_CANDIDATES:
229
229
  # Case-insensitive match against actual filenames in project root.
230
230
  match = next(
@@ -235,8 +235,8 @@ def _pack_archive(project_root: Path, apm_yml_path: Path, pkg, logger, verbose:
235
235
  ),
236
236
  None,
237
237
  )
238
- if match:
239
- tar.add(match, arcname=match.name, filter=_tar_filter, recursive=False)
238
+ if match and not _should_skip(match):
239
+ zf.write(match, arcname=match.name)
240
240
  if verbose:
241
241
  logger.info(f" bundling {match.name}")
242
242