apm-cli 0.23.1__tar.gz → 0.24.1__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 (425) hide show
  1. {apm_cli-0.23.1 → apm_cli-0.24.1}/NOTICE +35 -0
  2. {apm_cli-0.23.1/src/apm_cli.egg-info → apm_cli-0.24.1}/PKG-INFO +2 -1
  3. {apm_cli-0.23.1 → apm_cli-0.24.1}/pyproject.toml +2 -2
  4. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/client/claude.py +20 -5
  5. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/client/codex.py +13 -10
  6. apm_cli-0.24.1/src/apm_cli/bundle/attest.py +64 -0
  7. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/bundle/packer.py +43 -1
  8. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/bundle/plugin_exporter.py +261 -24
  9. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/cache/git_cache.py +35 -29
  10. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/_helpers.py +1 -1
  11. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/audit.py +6 -6
  12. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/compile/cli.py +9 -3
  13. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/config.py +76 -63
  14. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/deps/cli.py +82 -19
  15. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/install.py +44 -117
  16. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/mcp.py +3 -5
  17. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/outdated.py +8 -0
  18. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/prune.py +1 -1
  19. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/publish.py +7 -1
  20. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/uninstall/cli.py +3 -3
  21. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/update.py +114 -0
  22. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/compilation/agents_compiler.py +81 -24
  23. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/compilation/claude_formatter.py +4 -3
  24. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/compilation/context_optimizer.py +12 -2
  25. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/compilation/template_builder.py +16 -5
  26. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/apm_yml.py +1 -0
  27. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/target_detection.py +39 -15
  28. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/download_strategies.py +97 -39
  29. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/github_downloader.py +8 -2
  30. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/lockfile.py +23 -0
  31. apm_cli-0.24.1/src/apm_cli/deps/outdated_ref_cache.py +107 -0
  32. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/tiered_ref_resolver.py +33 -0
  33. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/context.py +5 -0
  34. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/drift.py +2 -0
  35. apm_cli-0.24.1/src/apm_cli/install/helpers/ref_reuse.py +96 -0
  36. apm_cli-0.24.1/src/apm_cli/install/helpers/ref_seed.py +66 -0
  37. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/mcp/__init__.py +5 -0
  38. apm_cli-0.24.1/src/apm_cli/install/mcp/integration.py +198 -0
  39. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/package_resolution.py +12 -3
  40. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/phases/lockfile.py +45 -0
  41. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/phases/resolve.py +16 -17
  42. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/plan.py +23 -12
  43. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/validation.py +97 -1
  44. apm_cli-0.24.1/src/apm_cli/integration/hook_bundle.py +191 -0
  45. apm_cli-0.24.1/src/apm_cli/integration/hook_file_routing.py +217 -0
  46. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/hook_integrator.py +69 -39
  47. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/instruction_integrator.py +52 -11
  48. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/kiro_hook_integrator.py +27 -23
  49. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/mcp_integrator.py +56 -6
  50. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/mcp_integrator_install.py +4 -2
  51. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/skill_integrator.py +45 -21
  52. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/targets.py +2 -1
  53. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/output_mappers.py +64 -4
  54. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/ref_resolver.py +0 -4
  55. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/models/apm_package.py +9 -0
  56. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/models/dependency/identity.py +39 -0
  57. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/models/dependency/mcp.py +13 -0
  58. apm_cli-0.24.1/src/apm_cli/models/dependency/object_fields.py +63 -0
  59. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/models/dependency/reference.py +40 -39
  60. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/policy/ci_checks.py +14 -8
  61. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/policy/schema.py +3 -2
  62. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/security/executables.py +22 -3
  63. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/archive.py +11 -2
  64. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/github_host.py +7 -1
  65. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/yaml_io.py +67 -4
  66. {apm_cli-0.23.1 → apm_cli-0.24.1/src/apm_cli.egg-info}/PKG-INFO +2 -1
  67. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli.egg-info/SOURCES.txt +7 -0
  68. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli.egg-info/requires.txt +1 -0
  69. {apm_cli-0.23.1 → apm_cli-0.24.1}/tests/test_apm_package_models.py +33 -0
  70. {apm_cli-0.23.1 → apm_cli-0.24.1}/tests/test_github_downloader_token_precedence.py +1 -1
  71. {apm_cli-0.23.1 → apm_cli-0.24.1}/tests/test_lockfile.py +15 -0
  72. apm_cli-0.23.1/src/apm_cli/integration/hook_file_routing.py +0 -120
  73. {apm_cli-0.23.1 → apm_cli-0.24.1}/AUTHORS +0 -0
  74. {apm_cli-0.23.1 → apm_cli-0.24.1}/LICENSE +0 -0
  75. {apm_cli-0.23.1 → apm_cli-0.24.1}/README.md +0 -0
  76. {apm_cli-0.23.1 → apm_cli-0.24.1}/setup.cfg +0 -0
  77. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/__init__.py +0 -0
  78. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/__init__.py +0 -0
  79. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/client/__init__.py +0 -0
  80. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/client/_mcp_runtime_args.py +0 -0
  81. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/client/antigravity.py +0 -0
  82. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/client/base.py +0 -0
  83. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/client/copilot.py +0 -0
  84. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/client/cursor.py +0 -0
  85. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/client/gemini.py +0 -0
  86. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/client/hermes.py +0 -0
  87. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/client/intellij.py +0 -0
  88. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/client/kiro.py +0 -0
  89. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/client/opencode.py +0 -0
  90. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/client/vscode.py +0 -0
  91. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/client/windsurf.py +0 -0
  92. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/package_manager/__init__.py +0 -0
  93. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/package_manager/base.py +0 -0
  94. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/adapters/package_manager/default_manager.py +0 -0
  95. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/bootstrap_mirror.py +0 -0
  96. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/bundle/__init__.py +0 -0
  97. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/bundle/local_bundle.py +0 -0
  98. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/bundle/lockfile_enrichment.py +0 -0
  99. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/bundle/unpacker.py +0 -0
  100. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/cache/__init__.py +0 -0
  101. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/cache/http_cache.py +0 -0
  102. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/cache/integrity.py +0 -0
  103. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/cache/locking.py +0 -0
  104. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/cache/paths.py +0 -0
  105. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/cache/url_normalize.py +0 -0
  106. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/cli.py +0 -0
  107. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/__init__.py +0 -0
  108. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/_apm_yml_writer.py +0 -0
  109. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/approve.py +0 -0
  110. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/cache.py +0 -0
  111. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/compile/__init__.py +0 -0
  112. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/compile/watcher.py +0 -0
  113. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/deps/__init__.py +0 -0
  114. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/deps/_utils.py +0 -0
  115. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/deps/why.py +0 -0
  116. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/doctor.py +0 -0
  117. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/experimental.py +0 -0
  118. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/find.py +0 -0
  119. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/init.py +0 -0
  120. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/lifecycle.py +0 -0
  121. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/list_cmd.py +0 -0
  122. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/lock.py +0 -0
  123. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/marketplace/__init__.py +0 -0
  124. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/marketplace/audit.py +0 -0
  125. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/marketplace/check.py +0 -0
  126. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/marketplace/doctor.py +0 -0
  127. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/marketplace/init.py +0 -0
  128. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/marketplace/migrate.py +0 -0
  129. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/marketplace/outdated.py +0 -0
  130. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/marketplace/plugin/__init__.py +0 -0
  131. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/marketplace/plugin/add.py +0 -0
  132. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/marketplace/plugin/remove.py +0 -0
  133. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/marketplace/plugin/set.py +0 -0
  134. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/marketplace/validate.py +0 -0
  135. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/pack.py +0 -0
  136. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/plugin/__init__.py +0 -0
  137. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/plugin/init.py +0 -0
  138. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/policy.py +0 -0
  139. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/run.py +0 -0
  140. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/runtime.py +0 -0
  141. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/self_update.py +0 -0
  142. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/targets.py +0 -0
  143. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/uninstall/__init__.py +0 -0
  144. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/uninstall/engine.py +0 -0
  145. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/commands/view.py +0 -0
  146. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/compilation/__init__.py +0 -0
  147. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/compilation/build_id.py +0 -0
  148. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/compilation/constants.py +0 -0
  149. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/compilation/constitution.py +0 -0
  150. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/compilation/constitution_block.py +0 -0
  151. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/compilation/distributed_compiler.py +0 -0
  152. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/compilation/gemini_formatter.py +0 -0
  153. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/compilation/injector.py +0 -0
  154. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/compilation/link_resolver.py +0 -0
  155. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/compilation/managed_section.py +0 -0
  156. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/compilation/output_writer.py +0 -0
  157. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/compilation/user_root_context.py +0 -0
  158. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/config.py +0 -0
  159. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/constants.py +0 -0
  160. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/__init__.py +0 -0
  161. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/auth.py +0 -0
  162. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/azure_cli.py +0 -0
  163. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/build_orchestrator.py +0 -0
  164. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/command_logger.py +0 -0
  165. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/conflict_detector.py +0 -0
  166. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/docker_args.py +0 -0
  167. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/errors.py +0 -0
  168. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/experimental.py +0 -0
  169. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/install_audit.py +0 -0
  170. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/lifecycle_scripts.py +0 -0
  171. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/null_logger.py +0 -0
  172. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/operations.py +0 -0
  173. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/plugin_manifest.py +0 -0
  174. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/safe_installer.py +0 -0
  175. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/scope.py +0 -0
  176. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/script_executors.py +0 -0
  177. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/script_runner.py +0 -0
  178. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/script_trust.py +0 -0
  179. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/core/token_manager.py +0 -0
  180. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/__init__.py +0 -0
  181. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/_shared.py +0 -0
  182. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/aggregator.py +0 -0
  183. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/apm_resolver.py +0 -0
  184. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/artifactory_entry.py +0 -0
  185. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/artifactory_orchestrator.py +0 -0
  186. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/bare_cache.py +0 -0
  187. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/clone_engine.py +0 -0
  188. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/dependency_graph.py +0 -0
  189. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/git_auth_env.py +0 -0
  190. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/git_file_transport.py +0 -0
  191. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/git_reference_resolver.py +0 -0
  192. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/git_remote_ops.py +0 -0
  193. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/git_semver_resolver.py +0 -0
  194. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/github_downloader_validation.py +0 -0
  195. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/host_backends.py +0 -0
  196. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/installed_package.py +0 -0
  197. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/outdated_row.py +0 -0
  198. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/package_validator.py +0 -0
  199. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/path_anchoring.py +0 -0
  200. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/plugin_parser.py +0 -0
  201. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/registry/__init__.py +0 -0
  202. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/registry/auth.py +0 -0
  203. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/registry/client.py +0 -0
  204. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/registry/config_loader.py +0 -0
  205. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/registry/extractor.py +0 -0
  206. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/registry/feature_gate.py +0 -0
  207. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/registry/outdated.py +0 -0
  208. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/registry/resolver.py +0 -0
  209. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/registry/semver.py +0 -0
  210. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/registry_proxy.py +0 -0
  211. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/revision_pins.py +0 -0
  212. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/shared_clone_cache.py +0 -0
  213. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/transport_selection.py +0 -0
  214. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/verifier.py +0 -0
  215. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/deps/why_walker.py +0 -0
  216. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/drift.py +0 -0
  217. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/export/__init__.py +0 -0
  218. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/export/authoring.py +0 -0
  219. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/export/declared_license.py +0 -0
  220. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/export/formats.py +0 -0
  221. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/export/purl.py +0 -0
  222. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/export/sbom.py +0 -0
  223. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/export/spdx.py +0 -0
  224. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/export/spdx_data.py +0 -0
  225. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/factory.py +0 -0
  226. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/__init__.py +0 -0
  227. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/artifactory_resolver.py +0 -0
  228. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/cache_pin.py +0 -0
  229. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/deployed_paths.py +0 -0
  230. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/errors.py +0 -0
  231. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/exec_gate.py +0 -0
  232. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/gitlab_resolver.py +0 -0
  233. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/heals/__init__.py +0 -0
  234. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/heals/base.py +0 -0
  235. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/heals/branch_ref_drift.py +0 -0
  236. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/heals/buggy_lockfile_recovery.py +0 -0
  237. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/helpers/__init__.py +0 -0
  238. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/helpers/security_scan.py +0 -0
  239. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/insecure_policy.py +0 -0
  240. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/integrity.py +0 -0
  241. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/local_bundle_handler.py +0 -0
  242. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/lsp/__init__.py +0 -0
  243. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/lsp/integration.py +0 -0
  244. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/manifest_reconcile.py +0 -0
  245. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/mcp/args.py +0 -0
  246. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/mcp/command.py +0 -0
  247. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/mcp/conflicts.py +0 -0
  248. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/mcp/entry.py +0 -0
  249. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/mcp/registry.py +0 -0
  250. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/mcp/warnings.py +0 -0
  251. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/mcp/writer.py +0 -0
  252. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/package_selection.py +0 -0
  253. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/phases/__init__.py +0 -0
  254. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/phases/_redownload.py +0 -0
  255. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/phases/_skip_logic.py +0 -0
  256. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/phases/audit.py +0 -0
  257. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/phases/cleanup.py +0 -0
  258. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/phases/download.py +0 -0
  259. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/phases/finalize.py +0 -0
  260. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/phases/heal.py +0 -0
  261. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/phases/integrate.py +0 -0
  262. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/phases/local_content.py +0 -0
  263. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/phases/policy_gate.py +0 -0
  264. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/phases/policy_target_check.py +0 -0
  265. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/phases/post_deps_local.py +0 -0
  266. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/phases/targets.py +0 -0
  267. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/pipeline.py +0 -0
  268. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/presentation/__init__.py +0 -0
  269. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/presentation/dry_run.py +0 -0
  270. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/registry_wiring.py +0 -0
  271. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/request.py +0 -0
  272. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/root_redirect.py +0 -0
  273. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/service.py +0 -0
  274. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/services.py +0 -0
  275. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/skill_path_migration.py +0 -0
  276. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/sources.py +0 -0
  277. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/summary.py +0 -0
  278. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/target_filter.py +0 -0
  279. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/install/template.py +0 -0
  280. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/__init__.py +0 -0
  281. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/_shared.py +0 -0
  282. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/agent_integrator.py +0 -0
  283. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/base_integrator.py +0 -0
  284. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/canvas_integrator.py +0 -0
  285. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/cleanup.py +0 -0
  286. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/command_integrator.py +0 -0
  287. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/copilot_app_db.py +0 -0
  288. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/copilot_app_project.py +0 -0
  289. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/copilot_app_workflow_integrator.py +0 -0
  290. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/copilot_app_ws.py +0 -0
  291. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/copilot_cowork_paths.py +0 -0
  292. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/coverage.py +0 -0
  293. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/dispatch.py +0 -0
  294. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/lsp_integrator.py +0 -0
  295. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/opencode_frontmatter.py +0 -0
  296. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/prompt_integrator.py +0 -0
  297. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/skill_transformer.py +0 -0
  298. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/integration/utils.py +0 -0
  299. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/__init__.py +0 -0
  300. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/_git_utils.py +0 -0
  301. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/_io.py +0 -0
  302. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/_shared.py +0 -0
  303. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/audit.py +0 -0
  304. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/auth_helpers.py +0 -0
  305. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/builder.py +0 -0
  306. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/client.py +0 -0
  307. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/diagnostics.py +0 -0
  308. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/drift_check.py +0 -0
  309. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/errors.py +0 -0
  310. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/git_stderr.py +0 -0
  311. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/init_template.py +0 -0
  312. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/migration.py +0 -0
  313. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/models.py +0 -0
  314. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/output_profiles.py +0 -0
  315. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/registry.py +0 -0
  316. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/resolver.py +0 -0
  317. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/semver.py +0 -0
  318. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/shadow_detector.py +0 -0
  319. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/tag_pattern.py +0 -0
  320. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/validator.py +0 -0
  321. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/version_check.py +0 -0
  322. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/version_pins.py +0 -0
  323. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/version_resolver.py +0 -0
  324. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/yml_editor.py +0 -0
  325. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/marketplace/yml_schema.py +0 -0
  326. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/models/__init__.py +0 -0
  327. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/models/dependency/__init__.py +0 -0
  328. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/models/dependency/lsp.py +0 -0
  329. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/models/dependency/subsets.py +0 -0
  330. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/models/dependency/types.py +0 -0
  331. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/models/format_detection.py +0 -0
  332. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/models/plugin.py +0 -0
  333. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/models/results.py +0 -0
  334. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/models/validation.py +0 -0
  335. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/output/__init__.py +0 -0
  336. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/output/formatters.py +0 -0
  337. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/output/models.py +0 -0
  338. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/output/script_formatters.py +0 -0
  339. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/policy/__init__.py +0 -0
  340. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/policy/_constraint_pinning.py +0 -0
  341. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/policy/_help_text.py +0 -0
  342. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/policy/_shared.py +0 -0
  343. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/policy/discovery.py +0 -0
  344. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/policy/inheritance.py +0 -0
  345. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/policy/install_preflight.py +0 -0
  346. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/policy/matcher.py +0 -0
  347. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/policy/models.py +0 -0
  348. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/policy/outcome_routing.py +0 -0
  349. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/policy/parser.py +0 -0
  350. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/policy/policy_checks.py +0 -0
  351. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/policy/project_config.py +0 -0
  352. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/primitives/__init__.py +0 -0
  353. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/primitives/discovery.py +0 -0
  354. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/primitives/models.py +0 -0
  355. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/primitives/parser.py +0 -0
  356. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/registry/__init__.py +0 -0
  357. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/registry/client.py +0 -0
  358. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/registry/integration.py +0 -0
  359. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/registry/operations.py +0 -0
  360. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/runtime/__init__.py +0 -0
  361. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/runtime/base.py +0 -0
  362. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/runtime/codex_runtime.py +0 -0
  363. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/runtime/copilot_runtime.py +0 -0
  364. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/runtime/factory.py +0 -0
  365. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/runtime/llm_runtime.py +0 -0
  366. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/runtime/manager.py +0 -0
  367. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/runtime/utils.py +0 -0
  368. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/security/__init__.py +0 -0
  369. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/security/audit_report.py +0 -0
  370. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/security/content_scanner.py +0 -0
  371. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/security/external/__init__.py +0 -0
  372. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/security/external/base.py +0 -0
  373. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/security/external/gate.py +0 -0
  374. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/security/external/generic_sarif.py +0 -0
  375. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/security/external/options.py +0 -0
  376. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/security/external/registry.py +0 -0
  377. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/security/external/runner.py +0 -0
  378. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/security/external/sarif_ingest.py +0 -0
  379. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/security/external/skillspector.py +0 -0
  380. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/security/file_scanner.py +0 -0
  381. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/security/gate.py +0 -0
  382. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/update_policy.py +0 -0
  383. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/__init__.py +0 -0
  384. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/atomic_io.py +0 -0
  385. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/console.py +0 -0
  386. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/content_hash.py +0 -0
  387. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/diagnostics.py +0 -0
  388. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/exclude.py +0 -0
  389. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/file_ops.py +0 -0
  390. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/git_env.py +0 -0
  391. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/git_sparse.py +0 -0
  392. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/guards.py +0 -0
  393. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/helpers.py +0 -0
  394. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/install_tui.py +0 -0
  395. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/normalization.py +0 -0
  396. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/path_security.py +0 -0
  397. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/paths.py +0 -0
  398. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/patterns.py +0 -0
  399. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/perf_stats.py +0 -0
  400. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/reflink.py +0 -0
  401. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/short_sha.py +0 -0
  402. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/subprocess_env.py +0 -0
  403. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/utils/version_checker.py +0 -0
  404. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/version.py +0 -0
  405. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/workflow/__init__.py +0 -0
  406. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/workflow/discovery.py +0 -0
  407. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/workflow/parser.py +0 -0
  408. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli/workflow/runner.py +0 -0
  409. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli.egg-info/dependency_links.txt +0 -0
  410. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli.egg-info/entry_points.txt +0 -0
  411. {apm_cli-0.23.1 → apm_cli-0.24.1}/src/apm_cli.egg-info/top_level.txt +0 -0
  412. {apm_cli-0.23.1 → apm_cli-0.24.1}/tests/test_apm_resolver.py +0 -0
  413. {apm_cli-0.23.1 → apm_cli-0.24.1}/tests/test_codex_docker_args_fix.py +0 -0
  414. {apm_cli-0.23.1 → apm_cli-0.24.1}/tests/test_codex_empty_string_and_defaults.py +0 -0
  415. {apm_cli-0.23.1 → apm_cli-0.24.1}/tests/test_collision_integration.py +0 -0
  416. {apm_cli-0.23.1 → apm_cli-0.24.1}/tests/test_console.py +0 -0
  417. {apm_cli-0.23.1 → apm_cli-0.24.1}/tests/test_distributed_compilation.py +0 -0
  418. {apm_cli-0.23.1 → apm_cli-0.24.1}/tests/test_empty_string_and_defaults.py +0 -0
  419. {apm_cli-0.23.1 → apm_cli-0.24.1}/tests/test_enhanced_discovery.py +0 -0
  420. {apm_cli-0.23.1 → apm_cli-0.24.1}/tests/test_github_downloader.py +0 -0
  421. {apm_cli-0.23.1 → apm_cli-0.24.1}/tests/test_gitlab_git_transport.py +0 -0
  422. {apm_cli-0.23.1 → apm_cli-0.24.1}/tests/test_runnable_prompts.py +0 -0
  423. {apm_cli-0.23.1 → apm_cli-0.24.1}/tests/test_runtime_manager_token_precedence.py +0 -0
  424. {apm_cli-0.23.1 → apm_cli-0.24.1}/tests/test_token_manager.py +0 -0
  425. {apm_cli-0.23.1 → apm_cli-0.24.1}/tests/test_virtual_package_multi_install.py +0 -0
@@ -703,6 +703,41 @@ THE SOFTWARE.
703
703
 
704
704
  ---
705
705
 
706
+ ## Component. tomlkit
707
+
708
+ - Version requirement: `>=0.13`
709
+ - Upstream: https://github.com/python-poetry/tomlkit
710
+ - SPDX: `MIT`
711
+
712
+ ### Open Source License/Copyright Notice.
713
+
714
+ _Copyright (c) 2018 Sébastien Eustace_
715
+
716
+ ```
717
+ Copyright (c) 2018 Sébastien Eustace
718
+
719
+ Permission is hereby granted, free of charge, to any person obtaining
720
+ a copy of this software and associated documentation files (the
721
+ "Software"), to deal in the Software without restriction, including
722
+ without limitation the rights to use, copy, modify, merge, publish,
723
+ distribute, sublicense, and/or sell copies of the Software, and to
724
+ permit persons to whom the Software is furnished to do so, subject to
725
+ the following conditions:
726
+
727
+ The above copyright notice and this permission notice shall be
728
+ included in all copies or substantial portions of the Software.
729
+
730
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
731
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
732
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
733
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
734
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
735
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
736
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
737
+ ```
738
+
739
+ ---
740
+
706
741
  ## Component. rich
707
742
 
708
743
  - Version requirement: `>=13.0.0`
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: apm-cli
3
- Version: 0.23.1
3
+ Version: 0.24.1
4
4
  Summary: MCP configuration tool
5
5
  Author-email: Daniel Meppiel <user@example.com>
6
6
  License: MIT License
@@ -46,6 +46,7 @@ Requires-Dist: llm>=0.28
46
46
  Requires-Dist: llm-github-models>=0.18.0
47
47
  Requires-Dist: tomli>=1.2.0; python_version < "3.11"
48
48
  Requires-Dist: toml>=0.10.2
49
+ Requires-Dist: tomlkit>=0.13
49
50
  Requires-Dist: rich>=13.0.0
50
51
  Requires-Dist: rich-click>=1.7.0
51
52
  Requires-Dist: watchdog>=3.0.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "apm-cli"
7
- version = "0.23.1"
7
+ version = "0.24.1"
8
8
  description = "MCP configuration tool"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -31,6 +31,7 @@ dependencies = [
31
31
  "llm-github-models>=0.18.0",
32
32
  "tomli>=1.2.0; python_version<'3.11'",
33
33
  "toml>=0.10.2",
34
+ "tomlkit>=0.13",
34
35
  "rich>=13.0.0",
35
36
  "rich-click>=1.7.0",
36
37
  "watchdog>=3.0.0",
@@ -170,4 +171,3 @@ markers = [
170
171
  "requires_inference: requires APM_RUN_INFERENCE_TESTS=1 + model API access",
171
172
  "req: binds a test to one or more OpenAPM req-XXX ids (spec-conformance suite)",
172
173
  ]
173
-
@@ -4,11 +4,11 @@ Project scope: ``.mcp.json`` at the project root with top-level ``mcpServers``
4
4
  (``--scope project`` in Claude Code). Writes are opt-in when ``.claude/`` exists,
5
5
  mirroring the Cursor/OpenCode directory-presence convention.
6
6
 
7
- User scope: top-level ``mcpServers`` in ``~/.claude.json`` (``--scope user``).
8
- Writes are atomic and create the file with ``0o600`` permissions on first
9
- write so the shared Claude Code config is not silently truncated by a
10
- concurrent writer and cannot leak any embedded OAuth state to other users
11
- on a multi-user host.
7
+ User scope: top-level ``mcpServers`` in ``$CLAUDE_CONFIG_DIR/.claude.json``
8
+ when configured, otherwise ``~/.claude.json`` (``--scope user``). Writes are
9
+ atomic and create the file with ``0o600`` permissions on first write so the
10
+ shared Claude Code config is not silently truncated by a concurrent writer
11
+ and cannot leak any embedded OAuth state to other users on a multi-user host.
12
12
 
13
13
  Local scope (Claude Code's third scope -- the default for ``claude mcp add``,
14
14
  storing per-project private config under ``~/.claude.json -> projects.<abs_path>
@@ -20,12 +20,17 @@ See https://code.claude.com/docs/en/mcp
20
20
  """
21
21
 
22
22
  import json
23
+ import logging
24
+ import os
23
25
  from pathlib import Path
24
26
 
25
27
  from ...utils.atomic_io import atomic_write_text
26
28
  from ...utils.console import _rich_error, _rich_success, _rich_warning
29
+ from ...utils.path_security import PathTraversalError
27
30
  from .copilot import CopilotClientAdapter
28
31
 
32
+ _log = logging.getLogger(__name__)
33
+
29
34
 
30
35
  class ClaudeClientAdapter(CopilotClientAdapter):
31
36
  """MCP configuration for Claude Code (``mcpServers`` schema).
@@ -141,6 +146,15 @@ class ClaudeClientAdapter(CopilotClientAdapter):
141
146
  return self.project_root / ".mcp.json"
142
147
 
143
148
  def _user_claude_json_path(self) -> Path:
149
+ config_dir = os.environ.get("CLAUDE_CONFIG_DIR", "").strip()
150
+ if config_dir:
151
+ config_path = Path(config_dir).expanduser()
152
+ if not config_path.is_absolute():
153
+ raise PathTraversalError(
154
+ "CLAUDE_CONFIG_DIR must be an absolute path for user-scope MCP "
155
+ "config; set an absolute path or unset it to use ~/.claude.json."
156
+ )
157
+ return config_path.resolve(strict=False) / ".claude.json"
144
158
  return Path.home() / ".claude.json"
145
159
 
146
160
  def _should_write_project(self) -> bool:
@@ -206,6 +220,7 @@ class ClaudeClientAdapter(CopilotClientAdapter):
206
220
  payload = json.dumps(data, indent=2) + "\n"
207
221
  path.parent.mkdir(parents=True, exist_ok=True)
208
222
  atomic_write_text(path, payload, new_file_mode=0o600)
223
+ _log.debug("Claude user-scope MCP config written to %s", path)
209
224
  return True
210
225
  except OSError:
211
226
  return False
@@ -5,10 +5,12 @@ import os
5
5
  from pathlib import Path
6
6
  from urllib.parse import urlparse
7
7
 
8
- import toml
8
+ import tomlkit
9
+ from tomlkit.exceptions import TOMLKitError
9
10
 
10
11
  from ...registry.client import SimpleRegistryClient
11
12
  from ...registry.integration import RegistryIntegration
13
+ from ...utils.atomic_io import atomic_write_text
12
14
  from ...utils.console import _rich_success, _rich_warning
13
15
  from ...utils.path_security import PathTraversalError
14
16
  from ._mcp_runtime_args import process_v01_value_hint_arg
@@ -94,9 +96,7 @@ class CodexClientAdapter(MCPClientAdapter):
94
96
  # Ensure directory exists
95
97
  config_path.parent.mkdir(parents=True, exist_ok=True)
96
98
 
97
- with open(config_path, "w", encoding="utf-8") as f:
98
- toml.dump(current_config, f)
99
- os.chmod(config_path, 0o600)
99
+ atomic_write_text(config_path, tomlkit.dumps(current_config), new_file_mode=0o600)
100
100
  _log.debug("Codex config written to %s", config_path)
101
101
  return True
102
102
 
@@ -104,8 +104,9 @@ class CodexClientAdapter(MCPClientAdapter):
104
104
  """Get the current Codex CLI MCP configuration.
105
105
 
106
106
  Returns:
107
- dict | None: Current configuration, empty dict if file doesn't
108
- exist, or None when an existing config cannot be parsed safely.
107
+ MutableMapping | None: Round-trip-preserving mapping when the file
108
+ exists, empty mapping if it does not exist, or None when an
109
+ existing config cannot be parsed safely.
109
110
  """
110
111
  config_path = self.get_config_path()
111
112
 
@@ -113,12 +114,14 @@ class CodexClientAdapter(MCPClientAdapter):
113
114
  return {}
114
115
 
115
116
  try:
116
- with open(config_path, encoding="utf-8") as f:
117
- return toml.load(f)
118
- except toml.TomlDecodeError as exc:
117
+ with open(config_path, encoding="utf-8") as config_file:
118
+ return tomlkit.load(config_file)
119
+ except (TOMLKitError, UnicodeDecodeError) as exc:
119
120
  _log.debug("Failed to parse Codex config at %s", config_path, exc_info=True)
120
121
  _rich_warning(
121
- f"Could not parse {config_path}: {exc} -- skipping config write to avoid data loss",
122
+ f"Could not read or parse {config_path}: {exc} "
123
+ "-- skipping config write to avoid data loss; inspect the file "
124
+ "or delete it to reset Codex configuration",
122
125
  symbol="warning",
123
126
  )
124
127
  return None
@@ -0,0 +1,64 @@
1
+ """Shared per-file provenance verification for the pack pipelines (#2013).
2
+
3
+ Both pack formats copy dependency files that ``apm install`` recorded in
4
+ ``apm.lock.yaml`` under ``deployed_files`` + ``deployed_file_hashes``:
5
+
6
+ * ``--format plugin`` (:mod:`apm_cli.bundle.plugin_exporter`)
7
+ * ``--format apm`` (:mod:`apm_cli.bundle.packer`)
8
+
9
+ Before a byte enters a bundle its on-disk copy is verified against the
10
+ attested SHA-256 recorded at install time. A file that was tampered or
11
+ corrupted after ``apm install`` must never enter a bundle silently. Keeping
12
+ the check in ONE place gives both pack paths identical semantics and avoids a
13
+ copy-pasted block that would trip the pylint R0801 duplication gate.
14
+
15
+ Tolerance rule (forward-compat): a file with *no* recorded hash -- either an
16
+ older lockfile with an empty ``deployed_file_hashes`` or a specific path with
17
+ no recorded entry -- is packed without verification. Absence of an attestation
18
+ is tolerated; a *mismatched* attestation is a hard error. The unverified gap
19
+ is surfaced as a debug diagnostic so ``apm audit``-minded users can see it.
20
+ """
21
+
22
+ import logging
23
+ from pathlib import Path
24
+
25
+ from ..utils.content_hash import compute_file_hash
26
+
27
+ _logger = logging.getLogger(__name__)
28
+
29
+
30
+ def verify_attested_file(
31
+ source: Path,
32
+ expected_hash: str | None,
33
+ dep_label: str,
34
+ rel_display: str,
35
+ ) -> None:
36
+ """Fail loudly when *source* diverges from its attested SHA-256.
37
+
38
+ Args:
39
+ source: On-disk file being packed.
40
+ expected_hash: The ``"sha256:<hex>"`` recorded in
41
+ ``deployed_file_hashes``, or ``None`` when no hash was recorded.
42
+ dep_label: Dependency identifier (``repo_url``) for the error message.
43
+ rel_display: Human-readable path shown in diagnostics / errors.
44
+
45
+ Raises:
46
+ ValueError: When a recorded hash exists and the on-disk content does
47
+ not match it.
48
+ """
49
+ if not expected_hash:
50
+ _logger.debug(
51
+ "no attested hash for %r from %s; packed without integrity "
52
+ "verification (older lockfile)",
53
+ rel_display,
54
+ dep_label,
55
+ )
56
+ return
57
+ actual = compute_file_hash(source)
58
+ if actual != expected_hash:
59
+ raise ValueError(
60
+ f"Cannot pack dependency {dep_label}: installed file {rel_display!r} "
61
+ "does not match the hash recorded in apm.lock.yaml. The installed "
62
+ "copy may be stale or tampered. Run 'apm install' to restore "
63
+ "attested content, then pack again."
64
+ )
@@ -13,6 +13,7 @@ from ..utils.archive import (
13
13
  write_tar_archive,
14
14
  write_zip_archive,
15
15
  )
16
+ from .attest import verify_attested_file
16
17
  from .lockfile_enrichment import _filter_files_by_target, enrich_lockfile_for_pack
17
18
 
18
19
 
@@ -158,10 +159,19 @@ def pack_bundle(
158
159
  # not portable and is bundled separately via the project's own files
159
160
  # (or rejected outright at L89-97 for manifest-declared local deps).
160
161
  all_deployed: list[str] = []
162
+ # Provenance map: deployed-path -> (attested SHA-256, dependency label).
163
+ # ``deployed_file_hashes`` is keyed by the on-disk deployed path recorded
164
+ # at install time (see install/phases/lockfile.compute_deployed_hashes), so
165
+ # verification below must look up the on-disk path, not the bundle path.
166
+ deployed_hashes: dict[str, str] = {}
167
+ hash_dep_labels: dict[str, str] = {}
161
168
  for dep in lockfile.get_all_dependencies():
162
169
  if dep.source == "local":
163
170
  continue
164
171
  all_deployed.extend(dep.deployed_files)
172
+ for _dpath, _dhash in dep.deployed_file_hashes.items():
173
+ deployed_hashes[_dpath] = _dhash
174
+ hash_dep_labels[_dpath] = dep.repo_url
165
175
 
166
176
  filtered_files, path_mappings = _filter_files_by_target(all_deployed, effective_target)
167
177
  # Deduplicate while preserving order
@@ -250,7 +260,12 @@ def pack_bundle(
250
260
  bundle_dir.mkdir(parents=True, exist_ok=True)
251
261
  bundle_dir_resolved = bundle_dir.resolve()
252
262
 
253
- # 7. Copy files preserving directory structure
263
+ # 7. Copy files preserving directory structure.
264
+ # Provenance gate (#2013): each dependency file recorded in the lockfile
265
+ # is verified against its attested SHA-256 before it enters the bundle --
266
+ # the same integrity guarantee the plugin format enforces, applied to the
267
+ # default/most-used ``apm`` format. Files with no recorded hash (older
268
+ # lockfiles) pack without verification; a mismatch fails loud.
254
269
  for rel_path in unique_files:
255
270
  # For cross-target mapped files, read from the original disk path
256
271
  disk_path = path_mappings.get(rel_path, rel_path)
@@ -264,8 +279,35 @@ def pack_bundle(
264
279
  if src.is_dir():
265
280
  from ..security.gate import ignore_non_content
266
281
 
282
+ # Verify each contained file's attested hash and re-assert
283
+ # containment per child. copytree already drops symlinks via
284
+ # ignore_non_content, but the walk guards against a directory
285
+ # symlink whose target escapes the project root regardless of the
286
+ # walker's version-specific symlink-following behaviour.
287
+ disk_base = disk_path.rstrip("/")
288
+ for child in sorted(src.rglob("*")):
289
+ if not child.is_file() or child.is_symlink():
290
+ continue
291
+ if not child.resolve().is_relative_to(project_root_resolved):
292
+ raise ValueError(
293
+ f"Refusing to pack path that escapes project root: "
294
+ f"{child.relative_to(project_root)!r}"
295
+ )
296
+ child_key = f"{disk_base}/{child.relative_to(src).as_posix()}"
297
+ verify_attested_file(
298
+ child,
299
+ deployed_hashes.get(child_key),
300
+ hash_dep_labels.get(child_key, "dependency"),
301
+ child_key,
302
+ )
267
303
  shutil.copytree(src, dest, dirs_exist_ok=True, ignore=ignore_non_content)
268
304
  else:
305
+ verify_attested_file(
306
+ src,
307
+ deployed_hashes.get(disk_path),
308
+ hash_dep_labels.get(disk_path, "dependency"),
309
+ disk_path,
310
+ )
269
311
  dest.parent.mkdir(parents=True, exist_ok=True)
270
312
  shutil.copy2(src, dest, follow_symlinks=False)
271
313
 
@@ -11,7 +11,7 @@ import hashlib
11
11
  import json
12
12
  import re
13
13
  import shutil
14
- from pathlib import Path, PurePosixPath
14
+ from pathlib import Path, PurePosixPath, PureWindowsPath
15
15
 
16
16
  import yaml
17
17
 
@@ -30,6 +30,7 @@ from ..utils.archive import (
30
30
  )
31
31
  from ..utils.console import _rich_warning
32
32
  from ..utils.path_security import PathTraversalError, ensure_path_within, safe_rmtree
33
+ from .attest import verify_attested_file
33
34
  from .packer import PackResult
34
35
 
35
36
  # ---------------------------------------------------------------------------
@@ -417,6 +418,217 @@ def _dep_install_path(dep: LockedDependency, apm_modules_dir: Path) -> Path:
417
418
  return dep_ref.get_install_path(apm_modules_dir)
418
419
 
419
420
 
421
+ def _deployed_path_parts(rel_path: str) -> tuple[str, ...]:
422
+ """Return safe POSIX path parts for a lockfile deployed_files entry."""
423
+ rel = rel_path.replace("\\", "/")
424
+ pure = PurePosixPath(rel)
425
+ if pure.is_absolute() or PureWindowsPath(rel).is_absolute():
426
+ raise ValueError(f"Refusing to pack absolute deployed file path: {rel_path!r}")
427
+ parts = pure.parts
428
+ if any(part in ("", ".", "..") for part in parts):
429
+ raise ValueError(f"Refusing to pack unsafe deployed file path: {rel_path!r}")
430
+ return parts
431
+
432
+
433
+ def _skill_name_from_deployed_parts(parts: tuple[str, ...]) -> str | None:
434
+ """Return the deployed skill name when *parts* point inside a skills dir."""
435
+ if len(parts) >= 3 and parts[0].startswith(".") and parts[1] == "skills":
436
+ return parts[2]
437
+ if len(parts) >= 2 and parts[0] == "skills":
438
+ return parts[1]
439
+ return None
440
+
441
+
442
+ def _plugin_rel_for_deployed_path(
443
+ rel_path: str,
444
+ skill_subset: set[str] | None,
445
+ ) -> str | None:
446
+ """Map an installed deployed_files path back to plugin-native output layout."""
447
+ parts = _deployed_path_parts(rel_path)
448
+ if not parts:
449
+ return None
450
+
451
+ if parts[0] == "skills":
452
+ skill_name = _skill_name_from_deployed_parts(parts)
453
+ if skill_subset and (skill_name is None or skill_name not in skill_subset):
454
+ return None
455
+ plugin_parts = list(parts)
456
+ elif parts[0] in {"agents", "commands", "instructions", "extensions"}:
457
+ plugin_parts = list(parts)
458
+ elif len(parts) >= 3 and parts[0].startswith("."):
459
+ skill_name = _skill_name_from_deployed_parts(parts)
460
+ if skill_name is not None:
461
+ if skill_subset and skill_name not in skill_subset:
462
+ return None
463
+ plugin_parts = ["skills", *parts[2:]]
464
+ elif parts[1] == "agents":
465
+ plugin_parts = ["agents", *parts[2:]]
466
+ elif parts[1] in {"commands", "prompts"}:
467
+ plugin_parts = ["commands", *parts[2:]]
468
+ elif parts[1] in {"instructions", "rules", "steering"}:
469
+ plugin_parts = ["instructions", *parts[2:]]
470
+ elif parts[1] == "extensions":
471
+ plugin_parts = ["extensions", *parts[2:]]
472
+ elif parts[1] == "hooks":
473
+ plugin_parts = ["hooks", *parts[2:]]
474
+ else:
475
+ return None
476
+ elif len(parts) >= 2 and parts[0].startswith(".") and parts[1] == "hooks.json":
477
+ plugin_parts = ["hooks.json"]
478
+ else:
479
+ return None
480
+
481
+ if plugin_parts[0] == "commands" and plugin_parts[-1].endswith(".prompt.md"):
482
+ plugin_parts[-1] = _rename_prompt(plugin_parts[-1])
483
+ return PurePosixPath(*plugin_parts).as_posix()
484
+
485
+
486
+ def _verify_attested_hash(
487
+ source: Path,
488
+ project_root: Path,
489
+ dep: LockedDependency,
490
+ ) -> None:
491
+ """Fail loudly when a packed deployed file diverges from its attested hash.
492
+
493
+ ``deployed_file_hashes`` records the SHA-256 (``"sha256:<hex>"``) of each
494
+ file at install time. Verifying the on-disk copy before packing closes the
495
+ integrity half of the provenance hole: a deployed file that was tampered
496
+ or corrupted after ``apm install`` must never enter the bundle silently.
497
+
498
+ Files with no recorded hash (older lockfiles predating
499
+ ``deployed_file_hashes``) are packed without verification -- absence of an
500
+ attestation is forward-compat tolerated, presence of a *mismatched* one is
501
+ a hard error. Delegates to the shared :func:`verify_attested_file` helper so
502
+ the plugin and archive pack paths share one implementation.
503
+ """
504
+ rel = source.relative_to(project_root).as_posix()
505
+ expected = dep.deployed_file_hashes.get(rel) if dep.deployed_file_hashes else None
506
+ verify_attested_file(source, expected, dep.repo_url, rel)
507
+
508
+
509
+ def _append_deployed_component(
510
+ components: list[tuple[Path, str]],
511
+ source: Path,
512
+ output_rel: str,
513
+ seen_outputs: set[str],
514
+ project_root: Path,
515
+ dep: LockedDependency,
516
+ ) -> None:
517
+ """Append one deployed component unless it is unsafe or already mapped."""
518
+ if output_rel in seen_outputs or not _validate_output_rel(output_rel):
519
+ return
520
+ if source.is_file() and not source.is_symlink():
521
+ _verify_attested_hash(source, project_root, dep)
522
+ components.append((source, output_rel))
523
+ seen_outputs.add(output_rel)
524
+
525
+
526
+ def _collect_deployed_components(
527
+ project_root: Path,
528
+ dep: LockedDependency,
529
+ ) -> list[tuple[Path, str]]:
530
+ """Collect dependency components from lockfile deployed_files entries."""
531
+ components: list[tuple[Path, str]] = []
532
+ missing: list[str] = []
533
+ seen_outputs: set[str] = set()
534
+ skill_subset = set(dep.skill_subset) if dep.skill_subset else None
535
+
536
+ for rel_path in dep.deployed_files:
537
+ try:
538
+ plugin_rel = _plugin_rel_for_deployed_path(rel_path, skill_subset)
539
+ except ValueError as exc:
540
+ raise ValueError(f"Cannot pack dependency {dep.repo_url}: {exc}") from exc
541
+ if plugin_rel is None:
542
+ continue
543
+ source = project_root / rel_path
544
+ try:
545
+ source = ensure_path_within(source, project_root)
546
+ except PathTraversalError as exc:
547
+ raise ValueError(
548
+ f"Cannot pack dependency {dep.repo_url}: deployed file path "
549
+ f"escapes the project root: {rel_path!r}"
550
+ ) from exc
551
+ if not source.exists():
552
+ missing.append(rel_path)
553
+ continue
554
+ if source.is_symlink():
555
+ continue
556
+ if source.is_dir():
557
+ for child in sorted(source.rglob("*")):
558
+ if not child.is_file() or child.is_symlink():
559
+ continue
560
+ # Defense-in-depth: rglob's symlink-following behaviour is
561
+ # Python-version dependent, so re-assert containment on every
562
+ # expanded child rather than trusting the walk. A planted
563
+ # directory symlink whose target escapes ``project_root`` is
564
+ # rejected here even if an intermediate component was a symlink.
565
+ try:
566
+ ensure_path_within(child, project_root)
567
+ except PathTraversalError:
568
+ continue
569
+ child_rel = child.relative_to(source).as_posix()
570
+ child_output = (PurePosixPath(plugin_rel) / child_rel).as_posix()
571
+ _append_deployed_component(
572
+ components, child, child_output, seen_outputs, project_root, dep
573
+ )
574
+ else:
575
+ _append_deployed_component(
576
+ components, source, plugin_rel, seen_outputs, project_root, dep
577
+ )
578
+
579
+ if missing:
580
+ shown_missing = missing[:10]
581
+ remaining = len(missing) - len(shown_missing)
582
+ suffix = f"\n ... and {remaining} more" if remaining else ""
583
+ raise ValueError(
584
+ f"Cannot pack dependency {dep.repo_url}: installed files recorded "
585
+ "in apm.lock.yaml are missing on disk. Run 'apm install' to "
586
+ "restore them, then pack again:\n"
587
+ + "\n".join(f" - {path}" for path in shown_missing)
588
+ + suffix
589
+ )
590
+ return components
591
+
592
+
593
+ def _cache_would_contribute_primitives(install_path: Path, dep: LockedDependency) -> bool:
594
+ """Return True if the unattested apm_modules cache holds packable primitives.
595
+
596
+ Used ONLY to decide whether to fail loudly when a locked dependency records
597
+ no ``deployed_files``. This reads the cache to DETECT a provenance gap; it
598
+ never copies cache bytes into the bundle. A dependency that installed
599
+ real components but recorded none of them in the lockfile is a stale or
600
+ partial install -- packing its cache would leak unattested content, so we
601
+ refuse rather than silently pack it.
602
+ """
603
+ if not install_path.is_dir():
604
+ return False
605
+ probe = _collect_apm_components(install_path / ".apm")
606
+ probe.extend(_collect_root_plugin_components(install_path))
607
+ _collect_bare_skill(install_path, dep, probe)
608
+ return bool(probe)
609
+
610
+
611
+ def _cache_would_contribute_hooks_or_mcp(install_path: Path) -> bool:
612
+ """Return True if the unattested cache holds hooks-config or MCP-config.
613
+
614
+ Hooks/MCP *configuration* (``.apm/hooks/*.json``, root ``hooks.json`` /
615
+ ``hooks/``, ``.mcp.json``) is merged into shared host settings by
616
+ ``apm install`` and is never recorded in the lockfile ``deployed_files``.
617
+ Because plugin pack now emits only lockfile-attested content, such config
618
+ is dropped from the bundle. This probe drives a transition warning that
619
+ names the dependency whose cached config will NOT be packed; it never
620
+ copies cache bytes. Hook *scripts* recorded in ``deployed_files`` are
621
+ unaffected and still pack.
622
+ """
623
+ if not install_path.is_dir():
624
+ return False
625
+ if _collect_mcp(install_path):
626
+ return True
627
+ if _collect_hooks_from_apm(install_path / ".apm"):
628
+ return True
629
+ return bool(_collect_hooks_from_root(install_path))
630
+
631
+
420
632
  # ---------------------------------------------------------------------------
421
633
  # Main exporter
422
634
  # ---------------------------------------------------------------------------
@@ -500,34 +712,59 @@ def export_plugin_bundle(
500
712
  ):
501
713
  continue
502
714
 
503
- install_path = _dep_install_path(dep, apm_modules_dir)
504
- if not install_path.is_dir():
505
- continue
506
-
507
715
  dep_name = dep.repo_url
508
716
 
509
- # Collect from .apm/
510
- dep_apm_dir = install_path / ".apm"
511
- dep_components = _collect_apm_components(dep_apm_dir)
512
-
513
- # Also collect root-level plugin-native dirs from the dep
514
- dep_components.extend(_collect_root_plugin_components(install_path))
515
-
516
- # Bare Claude skills: SKILL.md at dep root with no skills/ subdir
517
- _collect_bare_skill(install_path, dep, dep_components)
717
+ # Provenance rule (issue #1999 follow-up): a dependency's content
718
+ # is packed EXCLUSIVELY from what the lockfile attests via
719
+ # ``deployed_files`` (+ per-file ``deployed_file_hashes``).
720
+ # ``apm_modules`` is an unattested cache -- it carries no integrity
721
+ # or provenance guarantee, so no bytes from it may reach the bundle.
722
+ install_path = _dep_install_path(dep, apm_modules_dir)
723
+ if dep.deployed_files:
724
+ dep_components = _collect_deployed_components(project_root, dep)
725
+ if dep.skill_subset and not dep_components:
726
+ declared_skills = ", ".join(dep.skill_subset)
727
+ raise ValueError(
728
+ f"Cannot pack dependency {dep.repo_url}: the skills "
729
+ f"recorded in apm.lock.yaml (skill_subset: {declared_skills}) "
730
+ "were not found among its installed files. Run 'apm install' "
731
+ "to re-deploy the expected skills, then pack again."
732
+ )
733
+ elif _cache_would_contribute_primitives(install_path, dep):
734
+ # Unattested primitives sit in the cache but the lockfile
735
+ # recorded none of them: a stale or partial install. Refuse
736
+ # to pack the cache -- fail loudly with a fix.
737
+ raise ValueError(
738
+ f"Cannot pack dependency {dep.repo_url}: the lockfile records "
739
+ "no deployed files for it, but installed content that cannot "
740
+ "be verified exists in the apm_modules cache (a stale or "
741
+ "partial install). Run 'apm install' to record provenance in "
742
+ "apm.lock.yaml, then pack again."
743
+ )
744
+ else:
745
+ # No attested content and nothing packable in the cache: the
746
+ # dependency contributes no plugin primitives (e.g. an
747
+ # MCP-only or hooks-config-only package). Skip it cleanly.
748
+ dep_components = []
749
+
750
+ # Transition warning (#2013): dependency hooks/MCP *config* lives in
751
+ # the unattested cache and is never packed. Name the dependency so
752
+ # an author who relied on it merging into shared settings is not
753
+ # surprised by the silent exclusion. Attested primitives are packed
754
+ # regardless of this warning.
755
+ if _cache_would_contribute_hooks_or_mcp(install_path):
756
+ _warn = (
757
+ f"dependency {dep.repo_url} contributed hooks/MCP config that "
758
+ "is not attested in apm.lock.yaml; it will NOT be packed. "
759
+ "Attested primitives (skills/agents/etc.) are unaffected."
760
+ )
761
+ if logger:
762
+ logger.warning(_warn)
763
+ else:
764
+ _rich_warning(_warn, symbol="warning")
518
765
 
519
766
  _merge_file_map(file_map, dep_components, dep_name, force, collisions)
520
767
 
521
- # Hooks -- deps merge (first wins among deps)
522
- dep_hooks = _collect_hooks_from_apm(dep_apm_dir)
523
- dep_hooks_root = _collect_hooks_from_root(install_path)
524
- _deep_merge(dep_hooks, dep_hooks_root, overwrite=False)
525
- _deep_merge(merged_hooks, dep_hooks, overwrite=False)
526
-
527
- # MCP -- deps merge (first wins among deps)
528
- dep_mcp = _collect_mcp(install_path)
529
- _deep_merge(merged_mcp, dep_mcp, overwrite=False)
530
-
531
768
  # 6. Collect own components (.apm/ and root-level)
532
769
  own_apm_dir = project_root / ".apm"
533
770
  own_components = _collect_apm_components(own_apm_dir)