apm-cli 0.9.3__tar.gz → 0.10.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 (252) hide show
  1. {apm_cli-0.9.3/src/apm_cli.egg-info → apm_cli-0.10.0}/PKG-INFO +11 -1
  2. {apm_cli-0.9.3 → apm_cli-0.10.0}/README.md +9 -0
  3. {apm_cli-0.9.3 → apm_cli-0.10.0}/pyproject.toml +3 -1
  4. apm_cli-0.10.0/src/apm_cli/commands/_apm_yml_writer.py +81 -0
  5. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/_helpers.py +12 -0
  6. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/config.py +99 -1
  7. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/experimental.py +0 -1
  8. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/install.py +50 -22
  9. apm_cli-0.10.0/src/apm_cli/commands/marketplace.py +2064 -0
  10. apm_cli-0.10.0/src/apm_cli/commands/marketplace_plugin.py +395 -0
  11. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/mcp.py +14 -3
  12. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/outdated.py +1 -1
  13. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/pack.py +7 -7
  14. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/runtime.py +1 -1
  15. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/uninstall/engine.py +34 -2
  16. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/config.py +63 -0
  17. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/experimental.py +15 -0
  18. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/target_detection.py +7 -1
  19. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/lockfile.py +5 -0
  20. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/context.py +7 -0
  21. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/finalize.py +1 -1
  22. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/integrate.py +74 -0
  23. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/lockfile.py +16 -0
  24. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/targets.py +77 -5
  25. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/pipeline.py +9 -0
  26. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/request.py +2 -0
  27. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/service.py +2 -0
  28. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/services.py +85 -6
  29. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/sources.py +1 -0
  30. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/template.py +13 -0
  31. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/validation.py +149 -58
  32. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/base_integrator.py +73 -2
  33. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/cleanup.py +84 -7
  34. apm_cli-0.10.0/src/apm_cli/integration/copilot_cowork_paths.py +241 -0
  35. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/skill_integrator.py +201 -18
  36. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/targets.py +147 -11
  37. apm_cli-0.10.0/src/apm_cli/marketplace/__init__.py +90 -0
  38. apm_cli-0.10.0/src/apm_cli/marketplace/_git_utils.py +19 -0
  39. apm_cli-0.10.0/src/apm_cli/marketplace/_io.py +30 -0
  40. apm_cli-0.10.0/src/apm_cli/marketplace/builder.py +730 -0
  41. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/marketplace/client.py +2 -1
  42. apm_cli-0.10.0/src/apm_cli/marketplace/errors.py +128 -0
  43. apm_cli-0.10.0/src/apm_cli/marketplace/git_stderr.py +178 -0
  44. apm_cli-0.10.0/src/apm_cli/marketplace/init_template.py +82 -0
  45. apm_cli-0.10.0/src/apm_cli/marketplace/pr_integration.py +482 -0
  46. apm_cli-0.10.0/src/apm_cli/marketplace/publisher.py +895 -0
  47. apm_cli-0.10.0/src/apm_cli/marketplace/ref_resolver.py +332 -0
  48. apm_cli-0.10.0/src/apm_cli/marketplace/semver.py +242 -0
  49. apm_cli-0.10.0/src/apm_cli/marketplace/tag_pattern.py +103 -0
  50. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/marketplace/version_pins.py +17 -1
  51. apm_cli-0.10.0/src/apm_cli/marketplace/yml_editor.py +268 -0
  52. apm_cli-0.10.0/src/apm_cli/marketplace/yml_schema.py +473 -0
  53. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/dependency/reference.py +42 -1
  54. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/results.py +3 -1
  55. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/validation.py +220 -47
  56. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/output/script_formatters.py +3 -5
  57. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/ci_checks.py +43 -0
  58. {apm_cli-0.9.3 → apm_cli-0.10.0/src/apm_cli.egg-info}/PKG-INFO +11 -1
  59. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli.egg-info/SOURCES.txt +15 -0
  60. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli.egg-info/requires.txt +1 -0
  61. {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_apm_package_models.py +62 -12
  62. apm_cli-0.9.3/src/apm_cli/commands/marketplace.py +0 -556
  63. apm_cli-0.9.3/src/apm_cli/marketplace/__init__.py +0 -28
  64. apm_cli-0.9.3/src/apm_cli/marketplace/errors.py +0 -44
  65. {apm_cli-0.9.3 → apm_cli-0.10.0}/AUTHORS +0 -0
  66. {apm_cli-0.9.3 → apm_cli-0.10.0}/LICENSE +0 -0
  67. {apm_cli-0.9.3 → apm_cli-0.10.0}/setup.cfg +0 -0
  68. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/__init__.py +0 -0
  69. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/__init__.py +0 -0
  70. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/client/__init__.py +0 -0
  71. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/client/base.py +0 -0
  72. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/client/codex.py +0 -0
  73. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/client/copilot.py +0 -0
  74. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/client/cursor.py +0 -0
  75. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/client/gemini.py +0 -0
  76. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/client/opencode.py +0 -0
  77. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/client/vscode.py +0 -0
  78. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/package_manager/__init__.py +0 -0
  79. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/package_manager/base.py +0 -0
  80. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/package_manager/default_manager.py +0 -0
  81. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/bundle/__init__.py +0 -0
  82. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/bundle/lockfile_enrichment.py +0 -0
  83. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/bundle/packer.py +0 -0
  84. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/bundle/plugin_exporter.py +0 -0
  85. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/bundle/unpacker.py +0 -0
  86. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/cli.py +0 -0
  87. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/__init__.py +0 -0
  88. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/audit.py +0 -0
  89. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/compile/__init__.py +0 -0
  90. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/compile/cli.py +0 -0
  91. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/compile/watcher.py +0 -0
  92. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/deps/__init__.py +0 -0
  93. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/deps/_utils.py +0 -0
  94. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/deps/cli.py +0 -0
  95. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/init.py +0 -0
  96. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/list_cmd.py +0 -0
  97. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/policy.py +0 -0
  98. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/prune.py +0 -0
  99. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/run.py +0 -0
  100. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/uninstall/__init__.py +0 -0
  101. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/uninstall/cli.py +0 -0
  102. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/update.py +0 -0
  103. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/view.py +0 -0
  104. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/__init__.py +0 -0
  105. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/agents_compiler.py +0 -0
  106. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/claude_formatter.py +0 -0
  107. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/constants.py +0 -0
  108. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/constitution.py +0 -0
  109. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/constitution_block.py +0 -0
  110. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/context_optimizer.py +0 -0
  111. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/distributed_compiler.py +0 -0
  112. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/gemini_formatter.py +0 -0
  113. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/injector.py +0 -0
  114. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/link_resolver.py +0 -0
  115. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/template_builder.py +0 -0
  116. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/constants.py +0 -0
  117. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/__init__.py +0 -0
  118. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/auth.py +0 -0
  119. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/azure_cli.py +0 -0
  120. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/command_logger.py +0 -0
  121. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/conflict_detector.py +0 -0
  122. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/docker_args.py +0 -0
  123. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/operations.py +0 -0
  124. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/safe_installer.py +0 -0
  125. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/scope.py +0 -0
  126. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/script_runner.py +0 -0
  127. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/token_manager.py +0 -0
  128. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/__init__.py +0 -0
  129. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/aggregator.py +0 -0
  130. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/apm_resolver.py +0 -0
  131. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/artifactory_entry.py +0 -0
  132. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/collection_parser.py +0 -0
  133. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/dependency_graph.py +0 -0
  134. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/github_downloader.py +0 -0
  135. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/installed_package.py +0 -0
  136. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/package_validator.py +0 -0
  137. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/plugin_parser.py +0 -0
  138. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/registry_proxy.py +0 -0
  139. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/transport_selection.py +0 -0
  140. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/verifier.py +0 -0
  141. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/drift.py +0 -0
  142. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/factory.py +0 -0
  143. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/__init__.py +0 -0
  144. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/errors.py +0 -0
  145. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/helpers/__init__.py +0 -0
  146. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/helpers/security_scan.py +0 -0
  147. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/insecure_policy.py +0 -0
  148. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/mcp_registry.py +0 -0
  149. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/mcp_warnings.py +0 -0
  150. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/__init__.py +0 -0
  151. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/cleanup.py +0 -0
  152. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/download.py +0 -0
  153. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/local_content.py +0 -0
  154. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/policy_gate.py +0 -0
  155. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/policy_target_check.py +0 -0
  156. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/post_deps_local.py +0 -0
  157. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/resolve.py +0 -0
  158. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/presentation/__init__.py +0 -0
  159. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/presentation/dry_run.py +0 -0
  160. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/__init__.py +0 -0
  161. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/agent_integrator.py +0 -0
  162. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/command_integrator.py +0 -0
  163. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/coverage.py +0 -0
  164. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/dispatch.py +0 -0
  165. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/hook_integrator.py +0 -0
  166. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/instruction_integrator.py +0 -0
  167. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/mcp_integrator.py +0 -0
  168. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/prompt_integrator.py +0 -0
  169. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/skill_transformer.py +0 -0
  170. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/utils.py +0 -0
  171. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/marketplace/models.py +0 -0
  172. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/marketplace/registry.py +0 -0
  173. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/marketplace/resolver.py +0 -0
  174. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/marketplace/shadow_detector.py +0 -0
  175. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/marketplace/validator.py +0 -0
  176. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/__init__.py +0 -0
  177. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/apm_package.py +0 -0
  178. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/dependency/__init__.py +0 -0
  179. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/dependency/mcp.py +0 -0
  180. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/dependency/types.py +0 -0
  181. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/plugin.py +0 -0
  182. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/output/__init__.py +0 -0
  183. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/output/formatters.py +0 -0
  184. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/output/models.py +0 -0
  185. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/__init__.py +0 -0
  186. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/discovery.py +0 -0
  187. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/inheritance.py +0 -0
  188. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/install_preflight.py +0 -0
  189. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/matcher.py +0 -0
  190. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/models.py +0 -0
  191. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/outcome_routing.py +0 -0
  192. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/parser.py +0 -0
  193. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/policy_checks.py +0 -0
  194. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/project_config.py +0 -0
  195. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/schema.py +0 -0
  196. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/primitives/__init__.py +0 -0
  197. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/primitives/discovery.py +0 -0
  198. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/primitives/models.py +0 -0
  199. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/primitives/parser.py +0 -0
  200. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/registry/__init__.py +0 -0
  201. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/registry/client.py +0 -0
  202. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/registry/integration.py +0 -0
  203. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/registry/operations.py +0 -0
  204. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/runtime/__init__.py +0 -0
  205. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/runtime/base.py +0 -0
  206. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/runtime/codex_runtime.py +0 -0
  207. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/runtime/copilot_runtime.py +0 -0
  208. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/runtime/factory.py +0 -0
  209. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/runtime/llm_runtime.py +0 -0
  210. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/runtime/manager.py +0 -0
  211. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/security/__init__.py +0 -0
  212. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/security/audit_report.py +0 -0
  213. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/security/content_scanner.py +0 -0
  214. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/security/file_scanner.py +0 -0
  215. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/security/gate.py +0 -0
  216. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/update_policy.py +0 -0
  217. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/__init__.py +0 -0
  218. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/console.py +0 -0
  219. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/content_hash.py +0 -0
  220. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/diagnostics.py +0 -0
  221. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/exclude.py +0 -0
  222. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/file_ops.py +0 -0
  223. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/github_host.py +0 -0
  224. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/helpers.py +0 -0
  225. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/path_security.py +0 -0
  226. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/paths.py +0 -0
  227. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/subprocess_env.py +0 -0
  228. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/version_checker.py +0 -0
  229. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/yaml_io.py +0 -0
  230. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/version.py +0 -0
  231. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/workflow/__init__.py +0 -0
  232. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/workflow/discovery.py +0 -0
  233. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/workflow/parser.py +0 -0
  234. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/workflow/runner.py +0 -0
  235. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli.egg-info/dependency_links.txt +0 -0
  236. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli.egg-info/entry_points.txt +0 -0
  237. {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli.egg-info/top_level.txt +0 -0
  238. {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_apm_resolver.py +0 -0
  239. {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_codex_docker_args_fix.py +0 -0
  240. {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_codex_empty_string_and_defaults.py +0 -0
  241. {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_collision_integration.py +0 -0
  242. {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_console.py +0 -0
  243. {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_distributed_compilation.py +0 -0
  244. {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_empty_string_and_defaults.py +0 -0
  245. {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_enhanced_discovery.py +0 -0
  246. {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_github_downloader.py +0 -0
  247. {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_github_downloader_token_precedence.py +0 -0
  248. {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_lockfile.py +0 -0
  249. {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_runnable_prompts.py +0 -0
  250. {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_runtime_manager_token_precedence.py +0 -0
  251. {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_token_manager.py +0 -0
  252. {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_virtual_package_multi_install.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: apm-cli
3
- Version: 0.9.3
3
+ Version: 0.10.0
4
4
  Summary: MCP configuration tool
5
5
  Author-email: Daniel Meppiel <user@example.com>
6
6
  License: MIT License
@@ -49,6 +49,7 @@ Requires-Dist: rich>=13.0.0
49
49
  Requires-Dist: rich-click>=1.7.0
50
50
  Requires-Dist: watchdog>=3.0.0
51
51
  Requires-Dist: GitPython>=3.1.0
52
+ Requires-Dist: ruamel.yaml>=0.18.0
52
53
  Provides-Extra: dev
53
54
  Requires-Dist: pytest>=7.0.0; extra == "dev"
54
55
  Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
@@ -106,6 +107,15 @@ git clone <org/repo> && cd <repo>
106
107
  apm install # every agent is configured
107
108
  ```
108
109
 
110
+ **Coming from `npx skills add`?** Drop-in:
111
+
112
+ ```bash
113
+ apm install vercel-labs/agent-skills # whole bundle, like npx skills add
114
+ apm install vercel-labs/agent-skills --skill deploy-to-vercel # one skill, persisted to apm.yml
115
+ ```
116
+
117
+ Same install gesture. You also get a [manifest, lockfile, and reproducibility](https://microsoft.github.io/apm/reference/package-types/#skill-collection-skillsnameskillmd).
118
+
109
119
  ## The three promises
110
120
 
111
121
  ### 1. Portable by manifest
@@ -44,6 +44,15 @@ git clone <org/repo> && cd <repo>
44
44
  apm install # every agent is configured
45
45
  ```
46
46
 
47
+ **Coming from `npx skills add`?** Drop-in:
48
+
49
+ ```bash
50
+ apm install vercel-labs/agent-skills # whole bundle, like npx skills add
51
+ apm install vercel-labs/agent-skills --skill deploy-to-vercel # one skill, persisted to apm.yml
52
+ ```
53
+
54
+ Same install gesture. You also get a [manifest, lockfile, and reproducibility](https://microsoft.github.io/apm/reference/package-types/#skill-collection-skillsnameskillmd).
55
+
47
56
  ## The three promises
48
57
 
49
58
  ### 1. Portable by manifest
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "apm-cli"
7
- version = "0.9.3"
7
+ version = "0.10.0"
8
8
  description = "MCP configuration tool"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -35,6 +35,7 @@ dependencies = [
35
35
  "rich-click>=1.7.0",
36
36
  "watchdog>=3.0.0",
37
37
  "GitPython>=3.1.0",
38
+ "ruamel.yaml>=0.18.0",
38
39
  ]
39
40
 
40
41
  [project.optional-dependencies]
@@ -74,6 +75,7 @@ warn_unused_configs = true
74
75
  addopts = "-m 'not benchmark'"
75
76
  markers = [
76
77
  "integration: marks tests as integration tests that may require network access",
78
+ "live: marks tests that hit real GitHub repos (requires network + optional GITHUB_TOKEN)",
77
79
  "slow: marks tests as slow running tests",
78
80
  "benchmark: marks performance benchmark tests (deselected by default, run with -m benchmark)",
79
81
  ]
@@ -0,0 +1,81 @@
1
+ """Write-back helper for persisting skill subset selection in apm.yml.
2
+
3
+ Single helper ``set_skill_subset_for_entry`` is the one source of truth
4
+ for promoting entries to dict form and setting/clearing the ``skills:``
5
+ field. Keeps write-back logic isolated and unit-testable.
6
+ """
7
+
8
+ from pathlib import Path
9
+ from typing import List, Optional
10
+
11
+ from ..models.dependency.reference import DependencyReference
12
+ from ..utils.yaml_io import dump_yaml, load_yaml
13
+
14
+
15
+ def set_skill_subset_for_entry(
16
+ manifest_path: Path,
17
+ repo_url: str,
18
+ subset: Optional[List[str]],
19
+ ) -> bool:
20
+ """Promote entry to dict form and set/clear skills: field.
21
+
22
+ subset=None or empty list -> remove skills: from entry (reset to all).
23
+ subset=[...] -> set skills: to sorted+deduped list.
24
+
25
+ Returns True if file was modified.
26
+ """
27
+ data = load_yaml(manifest_path) or {}
28
+ deps_section = data.get("dependencies", {})
29
+ apm_deps = deps_section.get("apm", [])
30
+ if not apm_deps:
31
+ return False
32
+
33
+ modified = False
34
+ new_deps = []
35
+
36
+ for entry in apm_deps:
37
+ if _entry_matches(entry, repo_url):
38
+ entry = _apply_subset(entry, subset)
39
+ modified = True
40
+ new_deps.append(entry)
41
+
42
+ if not modified:
43
+ return False
44
+
45
+ deps_section["apm"] = new_deps
46
+ data["dependencies"] = deps_section
47
+ dump_yaml(data, manifest_path)
48
+ return True
49
+
50
+
51
+ def _entry_matches(entry, repo_url: str) -> bool:
52
+ """Check if an apm.yml entry matches the given repo_url."""
53
+ try:
54
+ if isinstance(entry, str):
55
+ ref = DependencyReference.parse(entry)
56
+ elif isinstance(entry, dict):
57
+ ref = DependencyReference.parse_from_dict(entry)
58
+ else:
59
+ return False
60
+ return ref.repo_url == repo_url
61
+ except (ValueError, TypeError, AttributeError, KeyError):
62
+ return False
63
+
64
+
65
+ def _apply_subset(entry, subset: Optional[List[str]]):
66
+ """Apply skill subset to an entry, promoting to dict form if needed."""
67
+ # Parse current entry to get canonical info
68
+ if isinstance(entry, str):
69
+ ref = DependencyReference.parse(entry)
70
+ elif isinstance(entry, dict):
71
+ ref = DependencyReference.parse_from_dict(entry)
72
+ else:
73
+ return entry
74
+
75
+ # Determine if we should set or clear
76
+ if subset:
77
+ ref.skill_subset = sorted(set(subset))
78
+ else:
79
+ ref.skill_subset = None
80
+
81
+ return ref.to_apm_yml_entry()
@@ -5,6 +5,7 @@ This module must NOT import from any command module.
5
5
 
6
6
  import builtins
7
7
  import os
8
+ import sys
8
9
  import tempfile
9
10
  from pathlib import Path
10
11
 
@@ -44,6 +45,17 @@ WARNING = f"{Fore.YELLOW}"
44
45
  HIGHLIGHT = f"{Fore.MAGENTA}{Style.BRIGHT}"
45
46
  RESET = Style.RESET_ALL
46
47
 
48
+
49
+ # -------------------------------------------------------------------
50
+ # TTY detection
51
+ # -------------------------------------------------------------------
52
+
53
+
54
+ def _is_interactive():
55
+ """Return True when both stdin and stdout are attached to a TTY."""
56
+ return sys.stdin.isatty() and sys.stdout.isatty()
57
+
58
+
47
59
  # Lazy loading for Rich components to improve startup performance
48
60
  _console = None
49
61
 
@@ -19,6 +19,7 @@ _BOOLEAN_FALSE_VALUES = {"false", "0", "no"}
19
19
  _CONFIG_KEY_DISPLAY_NAMES = {
20
20
  "auto_integrate": "auto-integrate",
21
21
  "temp_dir": "temp-dir",
22
+ "copilot_cowork_skills_dir": "copilot-cowork-skills-dir",
22
23
  }
23
24
 
24
25
 
@@ -52,7 +53,7 @@ def _get_config_getters():
52
53
 
53
54
  def _valid_config_keys() -> str:
54
55
  """Return valid config keys for messages."""
55
- return ", ".join(["auto-integrate", "temp-dir"])
56
+ return ", ".join(["auto-integrate", "temp-dir", "copilot-cowork-skills-dir"])
56
57
 
57
58
 
58
59
  @click.group(help="Configure APM CLI", invoke_without_command=True)
@@ -130,6 +131,18 @@ def config(ctx):
130
131
  if _temp_dir_val:
131
132
  config_table.add_row("", "Temp Directory", _temp_dir_val)
132
133
 
134
+ from ..core.experimental import is_enabled as _is_enabled
135
+
136
+ if _is_enabled("copilot_cowork"):
137
+ from ..config import get_copilot_cowork_skills_dir as _get_csd
138
+
139
+ _csd_val = _get_csd()
140
+ config_table.add_row(
141
+ "",
142
+ "Cowork Skills Dir",
143
+ _csd_val if _csd_val else "Not set (using auto-detection)",
144
+ )
145
+
133
146
  console.print(config_table)
134
147
 
135
148
  except (ImportError, NameError):
@@ -157,6 +170,17 @@ def config(ctx):
157
170
  if _temp_dir_fb:
158
171
  click.echo(f" Temp Directory: {_temp_dir_fb}")
159
172
 
173
+ from ..core.experimental import is_enabled as _is_enabled_fb
174
+
175
+ if _is_enabled_fb("copilot_cowork"):
176
+ from ..config import get_copilot_cowork_skills_dir as _get_csd_fb
177
+
178
+ _csd_fb = _get_csd_fb()
179
+ click.echo(
180
+ f" Cowork Skills Dir: "
181
+ f"{_csd_fb if _csd_fb else 'Not set (using auto-detection)'}"
182
+ )
183
+
160
184
 
161
185
  @config.command(help="Set a configuration value")
162
186
  @click.argument("key")
@@ -171,6 +195,27 @@ def set(key, value):
171
195
  from ..config import get_temp_dir, set_temp_dir
172
196
 
173
197
  logger = CommandLogger("config set")
198
+ if key == "copilot-cowork-skills-dir":
199
+ from ..core.experimental import is_enabled
200
+
201
+ if not is_enabled("copilot_cowork"):
202
+ logger.error(
203
+ "copilot-cowork-skills-dir requires the copilot-cowork experimental flag. "
204
+ "Run: apm experimental enable copilot-cowork"
205
+ )
206
+ sys.exit(1)
207
+ from ..config import get_copilot_cowork_skills_dir, set_copilot_cowork_skills_dir
208
+
209
+ try:
210
+ set_copilot_cowork_skills_dir(value)
211
+ logger.success(
212
+ f"Cowork skills directory set to: {get_copilot_cowork_skills_dir()}"
213
+ )
214
+ except ValueError as exc:
215
+ logger.error(str(exc))
216
+ sys.exit(1)
217
+ return
218
+
174
219
  if key == "temp-dir":
175
220
  try:
176
221
  set_temp_dir(value)
@@ -218,6 +263,18 @@ def get(key):
218
263
  logger = CommandLogger("config get")
219
264
  getters = _get_config_getters()
220
265
  if key:
266
+ if key == "copilot-cowork-skills-dir":
267
+ from ..config import get_copilot_cowork_skills_dir
268
+
269
+ value = get_copilot_cowork_skills_dir()
270
+ if value is None:
271
+ click.echo(
272
+ "copilot-cowork-skills-dir: Not set (using auto-detection)"
273
+ )
274
+ else:
275
+ click.echo(f"copilot-cowork-skills-dir: {value}")
276
+ return
277
+
221
278
  if key == "temp-dir":
222
279
  value = get_temp_dir()
223
280
  if value is None:
@@ -244,3 +301,44 @@ def get(key):
244
301
  click.echo(f" auto-integrate: {get_auto_integrate()}")
245
302
  temp_dir = get_temp_dir()
246
303
  click.echo(f" temp-dir: {temp_dir if temp_dir is not None else 'Not set (using system default)'}")
304
+
305
+ from ..core.experimental import is_enabled as _is_enabled_get
306
+
307
+ if _is_enabled_get("copilot_cowork"):
308
+ from ..config import get_copilot_cowork_skills_dir as _get_csd_get
309
+
310
+ csd = _get_csd_get()
311
+ click.echo(
312
+ f" copilot-cowork-skills-dir: "
313
+ f"{csd if csd is not None else 'Not set (using auto-detection)'}"
314
+ )
315
+
316
+
317
+ @config.command(help="Unset a configuration value")
318
+ @click.argument("key")
319
+ def unset(key):
320
+ """Unset (remove) a configuration value.
321
+
322
+ Examples:
323
+ apm config unset temp-dir
324
+ apm config unset copilot-cowork-skills-dir
325
+ """
326
+ logger = CommandLogger("config unset")
327
+
328
+ if key == "temp-dir":
329
+ from ..config import unset_temp_dir
330
+
331
+ unset_temp_dir()
332
+ logger.success("Temporary directory configuration removed")
333
+ return
334
+
335
+ if key == "copilot-cowork-skills-dir":
336
+ from ..config import unset_copilot_cowork_skills_dir
337
+
338
+ unset_copilot_cowork_skills_dir()
339
+ logger.success("Cowork skills directory configuration removed")
340
+ return
341
+
342
+ logger.error(f"Unknown configuration key: '{key}'")
343
+ logger.progress(f"Valid keys: {_valid_config_keys()}")
344
+ sys.exit(1)
@@ -140,7 +140,6 @@ def _handle_unknown_flag(name: str, logger: CommandLogger) -> None:
140
140
  @click.group(
141
141
  help="Manage experimental feature flags",
142
142
  invoke_without_command=True,
143
- context_settings={"allow_interspersed_args": True, "ignore_unknown_options": True},
144
143
  )
145
144
  @click.option("--verbose", "-v", is_flag=True, default=False, help="Show verbose output")
146
145
  @click.pass_context
@@ -1050,43 +1050,29 @@ def _run_mcp_install(
1050
1050
  "or a stdio command (self-defined entries)."
1051
1051
  ),
1052
1052
  )
1053
- @click.option(
1054
- "--no-policy",
1055
- "no_policy",
1056
- is_flag=True,
1057
- default=False,
1058
- help="Skip org policy enforcement for this invocation. Loudly logged. Does NOT bypass apm audit --ci.",
1059
- )
1053
+ @click.option("--skill", "skill_names", multiple=True, metavar="NAME", help="Install only named skill(s) from a SKILL_BUNDLE. Repeatable. Persisted in apm.yml and apm.lock so bare 'apm install' is deterministic. Use --skill '*' to reset to all skills.")
1054
+ @click.option("--no-policy", "no_policy", is_flag=True, default=False, help="Skip org policy enforcement for this invocation. Does NOT bypass apm audit --ci.")
1060
1055
  @click.pass_context
1061
- def install(ctx, packages, runtime, exclude, only, update, dry_run, force, verbose, trust_transitive_mcp, parallel_downloads, dev, target, allow_insecure, allow_insecure_hosts, global_, use_ssh, use_https, allow_protocol_fallback, mcp_name, transport, url, env_pairs, header_pairs, mcp_version, registry_url, no_policy):
1056
+ def install(ctx, packages, runtime, exclude, only, update, dry_run, force, verbose, trust_transitive_mcp, parallel_downloads, dev, target, allow_insecure, allow_insecure_hosts, global_, use_ssh, use_https, allow_protocol_fallback, mcp_name, transport, url, env_pairs, header_pairs, mcp_version, registry_url, skill_names, no_policy):
1062
1057
  """Install APM and MCP dependencies from apm.yml (like npm install).
1063
1058
 
1064
1059
  Detects AI runtimes from your apm.yml scripts and installs MCP servers for
1065
1060
  all detected runtimes; also installs APM package dependencies from GitHub.
1066
1061
  --only filters by type (apm or mcp).
1067
1062
 
1068
- HTTP dependencies require `allow_insecure: true` in apm.yml and
1069
- `--allow-insecure` on the install command. Transitive HTTP dependencies are
1070
- allowed automatically when they stay on the same host as a direct HTTP
1071
- dependency, or explicitly with `--allow-insecure-host <hostname>`.
1072
-
1073
1063
  Examples:
1074
1064
  apm install # Install existing deps from apm.yml
1075
1065
  apm install org/pkg1 # Add package to apm.yml and install
1076
- apm install org/pkg1 org/pkg2 # Add multiple packages and install
1077
1066
  apm install --exclude codex # Install for all except Codex CLI
1078
1067
  apm install --only=apm # Install only APM dependencies
1079
- apm install --only=mcp # Install only MCP dependencies
1080
1068
  apm install --update # Update dependencies to latest Git refs
1081
1069
  apm install --dry-run # Show what would be installed
1082
1070
  apm install -g org/pkg1 # Install to user scope (~/.apm/)
1083
- apm install --allow-insecure http://my-server.example.com/owner/repo # Install from HTTP URL with allow_insecure
1084
- apm install --allow-insecure-host mirror.example.com # Allow transitive HTTP dependencies from mirror.example.com
1085
-
1086
- MCP servers (also: 'apm mcp install'):
1087
- apm install --mcp io.github.github/github-mcp-server # registry shorthand
1088
- apm install --mcp api --url https://example.com/mcp # remote http/sse
1089
- apm install --mcp fetch -- npx -y @modelcontextprotocol/server-fetch # stdio (post-- argv)
1071
+ apm install --allow-insecure http://... # HTTP URL (needs allow_insecure)
1072
+ apm install --skill my-skill org/bundle # Install one skill from bundle
1073
+ apm install --mcp io.github.github/github-mcp-server # MCP registry
1074
+ apm install --mcp api --url https://example.com/mcp # MCP remote
1075
+ apm install --mcp fetch -- npx -y @mcp/server-fetch # MCP stdio
1090
1076
  """
1091
1077
  # C1 #856: defaults BEFORE try so the finally clause never sees an
1092
1078
  # UnboundLocalError if InstallLogger(...) raises during construction.
@@ -1149,6 +1135,14 @@ def install(ctx, packages, runtime, exclude, only, update, dry_run, force, verbo
1149
1135
  registry_url=validated_registry_url,
1150
1136
  )
1151
1137
 
1138
+ # Normalize --skill: '*' means all (same as absent). Reject with --mcp.
1139
+ _skill_subset = None
1140
+ if skill_names:
1141
+ if mcp_name is not None:
1142
+ raise click.UsageError("--skill cannot be combined with --mcp.")
1143
+ if not any(s == "*" for s in skill_names):
1144
+ _skill_subset = builtins.tuple(skill_names)
1145
+
1152
1146
  if mcp_name is not None:
1153
1147
  # MCP install routing block. This branch has accreted
1154
1148
  # significantly (--mcp / --registry / --transport / --env /
@@ -1463,11 +1457,41 @@ def install(ctx, packages, runtime, exclude, only, update, dry_run, force, verbo
1463
1457
  protocol_pref=protocol_pref,
1464
1458
  allow_protocol_fallback=allow_protocol_fallback,
1465
1459
  no_policy=no_policy,
1460
+ skill_subset=_skill_subset,
1461
+ skill_subset_from_cli=bool(skill_names),
1466
1462
  )
1467
1463
  apm_count = install_result.installed_count
1468
1464
  prompt_count = install_result.prompts_integrated
1469
1465
  agent_count = install_result.agents_integrated
1470
1466
  apm_diagnostics = install_result.diagnostics
1467
+
1468
+ # -- Skill subset write-back (Phase 11) --
1469
+ # When CLI provided --skill on a SKILL_BUNDLE package, persist
1470
+ # the subset selection in apm.yml so bare `apm install` is
1471
+ # deterministic.
1472
+ if skill_names and packages:
1473
+ from ._apm_yml_writer import set_skill_subset_for_entry
1474
+
1475
+ _star_sentinel = any(s == "*" for s in skill_names)
1476
+ for dep_key, pkg_type in install_result.package_types.items():
1477
+ if pkg_type == "skill_bundle":
1478
+ if _star_sentinel:
1479
+ # Explicit-all: REMOVE any persisted skills:
1480
+ if set_skill_subset_for_entry(manifest_path, dep_key, None):
1481
+ logger.success(f"Cleared skill subset for {dep_key}")
1482
+ else:
1483
+ subset_list = sorted(builtins.set(_skill_subset))
1484
+ if set_skill_subset_for_entry(manifest_path, dep_key, subset_list):
1485
+ logger.success(
1486
+ f"Persisted skill subset for {dep_key}: "
1487
+ f"[{', '.join(subset_list)}]"
1488
+ )
1489
+ elif pkg_type != "skill_bundle" and not _star_sentinel:
1490
+ # Non-bundle: warn but do NOT persist
1491
+ logger.warning(
1492
+ f"--skill ignored for {dep_key} "
1493
+ f"(package type: {pkg_type}, not a skill bundle)"
1494
+ )
1471
1495
  except InsecureDependencyPolicyError:
1472
1496
  _maybe_rollback_manifest(_snapshot_manifest_path, _manifest_snapshot, logger)
1473
1497
  sys.exit(1)
@@ -1664,6 +1688,8 @@ def _install_apm_dependencies(
1664
1688
  protocol_pref=None,
1665
1689
  allow_protocol_fallback: "Optional[bool]" = None,
1666
1690
  no_policy: bool = False,
1691
+ skill_subset: "Optional[builtins.tuple]" = None,
1692
+ skill_subset_from_cli: bool = False,
1667
1693
  ):
1668
1694
  """Thin wrapper -- builds an :class:`InstallRequest` and delegates to
1669
1695
  :class:`apm_cli.install.service.InstallService`.
@@ -1696,5 +1722,7 @@ def _install_apm_dependencies(
1696
1722
  protocol_pref=protocol_pref,
1697
1723
  allow_protocol_fallback=allow_protocol_fallback,
1698
1724
  no_policy=no_policy,
1725
+ skill_subset=skill_subset,
1726
+ skill_subset_from_cli=skill_subset_from_cli,
1699
1727
  )
1700
1728
  return InstallService().run(request)