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.
- {apm_cli-0.9.3/src/apm_cli.egg-info → apm_cli-0.10.0}/PKG-INFO +11 -1
- {apm_cli-0.9.3 → apm_cli-0.10.0}/README.md +9 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/pyproject.toml +3 -1
- apm_cli-0.10.0/src/apm_cli/commands/_apm_yml_writer.py +81 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/_helpers.py +12 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/config.py +99 -1
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/experimental.py +0 -1
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/install.py +50 -22
- apm_cli-0.10.0/src/apm_cli/commands/marketplace.py +2064 -0
- apm_cli-0.10.0/src/apm_cli/commands/marketplace_plugin.py +395 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/mcp.py +14 -3
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/outdated.py +1 -1
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/pack.py +7 -7
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/runtime.py +1 -1
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/uninstall/engine.py +34 -2
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/config.py +63 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/experimental.py +15 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/target_detection.py +7 -1
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/lockfile.py +5 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/context.py +7 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/finalize.py +1 -1
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/integrate.py +74 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/lockfile.py +16 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/targets.py +77 -5
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/pipeline.py +9 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/request.py +2 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/service.py +2 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/services.py +85 -6
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/sources.py +1 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/template.py +13 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/validation.py +149 -58
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/base_integrator.py +73 -2
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/cleanup.py +84 -7
- apm_cli-0.10.0/src/apm_cli/integration/copilot_cowork_paths.py +241 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/skill_integrator.py +201 -18
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/targets.py +147 -11
- apm_cli-0.10.0/src/apm_cli/marketplace/__init__.py +90 -0
- apm_cli-0.10.0/src/apm_cli/marketplace/_git_utils.py +19 -0
- apm_cli-0.10.0/src/apm_cli/marketplace/_io.py +30 -0
- apm_cli-0.10.0/src/apm_cli/marketplace/builder.py +730 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/marketplace/client.py +2 -1
- apm_cli-0.10.0/src/apm_cli/marketplace/errors.py +128 -0
- apm_cli-0.10.0/src/apm_cli/marketplace/git_stderr.py +178 -0
- apm_cli-0.10.0/src/apm_cli/marketplace/init_template.py +82 -0
- apm_cli-0.10.0/src/apm_cli/marketplace/pr_integration.py +482 -0
- apm_cli-0.10.0/src/apm_cli/marketplace/publisher.py +895 -0
- apm_cli-0.10.0/src/apm_cli/marketplace/ref_resolver.py +332 -0
- apm_cli-0.10.0/src/apm_cli/marketplace/semver.py +242 -0
- apm_cli-0.10.0/src/apm_cli/marketplace/tag_pattern.py +103 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/marketplace/version_pins.py +17 -1
- apm_cli-0.10.0/src/apm_cli/marketplace/yml_editor.py +268 -0
- apm_cli-0.10.0/src/apm_cli/marketplace/yml_schema.py +473 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/dependency/reference.py +42 -1
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/results.py +3 -1
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/validation.py +220 -47
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/output/script_formatters.py +3 -5
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/ci_checks.py +43 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0/src/apm_cli.egg-info}/PKG-INFO +11 -1
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli.egg-info/SOURCES.txt +15 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli.egg-info/requires.txt +1 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_apm_package_models.py +62 -12
- apm_cli-0.9.3/src/apm_cli/commands/marketplace.py +0 -556
- apm_cli-0.9.3/src/apm_cli/marketplace/__init__.py +0 -28
- apm_cli-0.9.3/src/apm_cli/marketplace/errors.py +0 -44
- {apm_cli-0.9.3 → apm_cli-0.10.0}/AUTHORS +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/LICENSE +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/setup.cfg +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/client/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/client/base.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/client/codex.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/client/copilot.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/client/cursor.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/client/gemini.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/client/opencode.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/client/vscode.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/package_manager/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/package_manager/base.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/adapters/package_manager/default_manager.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/bundle/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/bundle/lockfile_enrichment.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/bundle/packer.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/bundle/plugin_exporter.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/bundle/unpacker.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/cli.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/audit.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/compile/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/compile/cli.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/compile/watcher.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/deps/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/deps/_utils.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/deps/cli.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/init.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/list_cmd.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/policy.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/prune.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/run.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/uninstall/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/uninstall/cli.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/update.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/commands/view.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/agents_compiler.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/claude_formatter.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/constants.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/constitution.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/constitution_block.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/context_optimizer.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/distributed_compiler.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/gemini_formatter.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/injector.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/link_resolver.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/compilation/template_builder.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/constants.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/auth.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/azure_cli.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/command_logger.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/conflict_detector.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/docker_args.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/operations.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/safe_installer.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/scope.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/script_runner.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/core/token_manager.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/aggregator.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/apm_resolver.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/artifactory_entry.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/collection_parser.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/dependency_graph.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/github_downloader.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/installed_package.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/package_validator.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/plugin_parser.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/registry_proxy.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/transport_selection.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/deps/verifier.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/drift.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/factory.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/errors.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/helpers/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/helpers/security_scan.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/insecure_policy.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/mcp_registry.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/mcp_warnings.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/cleanup.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/download.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/local_content.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/policy_gate.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/policy_target_check.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/post_deps_local.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/phases/resolve.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/presentation/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/install/presentation/dry_run.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/agent_integrator.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/command_integrator.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/coverage.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/dispatch.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/hook_integrator.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/instruction_integrator.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/mcp_integrator.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/prompt_integrator.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/skill_transformer.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/integration/utils.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/marketplace/models.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/marketplace/registry.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/marketplace/resolver.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/marketplace/shadow_detector.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/marketplace/validator.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/apm_package.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/dependency/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/dependency/mcp.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/dependency/types.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/models/plugin.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/output/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/output/formatters.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/output/models.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/discovery.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/inheritance.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/install_preflight.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/matcher.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/models.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/outcome_routing.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/parser.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/policy_checks.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/project_config.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/policy/schema.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/primitives/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/primitives/discovery.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/primitives/models.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/primitives/parser.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/registry/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/registry/client.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/registry/integration.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/registry/operations.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/runtime/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/runtime/base.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/runtime/codex_runtime.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/runtime/copilot_runtime.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/runtime/factory.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/runtime/llm_runtime.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/runtime/manager.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/security/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/security/audit_report.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/security/content_scanner.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/security/file_scanner.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/security/gate.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/update_policy.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/console.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/content_hash.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/diagnostics.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/exclude.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/file_ops.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/github_host.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/helpers.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/path_security.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/paths.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/subprocess_env.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/version_checker.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/utils/yaml_io.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/version.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/workflow/__init__.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/workflow/discovery.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/workflow/parser.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli/workflow/runner.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli.egg-info/dependency_links.txt +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli.egg-info/entry_points.txt +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/src/apm_cli.egg-info/top_level.txt +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_apm_resolver.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_codex_docker_args_fix.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_codex_empty_string_and_defaults.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_collision_integration.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_console.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_distributed_compilation.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_empty_string_and_defaults.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_enhanced_discovery.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_github_downloader.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_github_downloader_token_precedence.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_lockfile.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_runnable_prompts.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_runtime_manager_token_precedence.py +0 -0
- {apm_cli-0.9.3 → apm_cli-0.10.0}/tests/test_token_manager.py +0 -0
- {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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
1084
|
-
apm install --
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
apm install --mcp
|
|
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)
|