apm-cli 0.8.7__tar.gz → 0.8.9__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.8.7/src/apm_cli.egg-info → apm_cli-0.8.9}/PKG-INFO +2 -2
- {apm_cli-0.8.7 → apm_cli-0.8.9}/README.md +1 -1
- {apm_cli-0.8.7 → apm_cli-0.8.9}/pyproject.toml +1 -1
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/bundle/lockfile_enrichment.py +6 -1
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/cli.py +3 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/_helpers.py +4 -2
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/compile/cli.py +1 -1
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/deps/cli.py +227 -191
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/install.py +438 -78
- apm_cli-0.8.9/src/apm_cli/commands/marketplace.py +436 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/pack.py +1 -1
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/uninstall/cli.py +41 -17
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/uninstall/engine.py +15 -9
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/core/command_logger.py +1 -0
- apm_cli-0.8.9/src/apm_cli/core/scope.py +179 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/core/target_detection.py +31 -8
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/deps/github_downloader.py +32 -9
- apm_cli-0.8.9/src/apm_cli/deps/installed_package.py +54 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/deps/lockfile.py +60 -12
- apm_cli-0.8.9/src/apm_cli/deps/registry_proxy.py +231 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/drift.py +26 -3
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/integration/agent_integrator.py +57 -5
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/integration/base_integrator.py +17 -12
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/integration/command_integrator.py +6 -4
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/integration/hook_integrator.py +97 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/integration/instruction_integrator.py +6 -4
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/integration/prompt_integrator.py +4 -4
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/integration/skill_integrator.py +21 -4
- apm_cli-0.8.9/src/apm_cli/integration/targets.py +364 -0
- apm_cli-0.8.9/src/apm_cli/marketplace/__init__.py +28 -0
- apm_cli-0.8.9/src/apm_cli/marketplace/client.py +302 -0
- apm_cli-0.8.9/src/apm_cli/marketplace/errors.py +44 -0
- apm_cli-0.8.9/src/apm_cli/marketplace/models.py +229 -0
- apm_cli-0.8.9/src/apm_cli/marketplace/registry.py +130 -0
- apm_cli-0.8.9/src/apm_cli/marketplace/resolver.py +251 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9/src/apm_cli.egg-info}/PKG-INFO +2 -2
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli.egg-info/SOURCES.txt +10 -0
- apm_cli-0.8.7/src/apm_cli/integration/targets.py +0 -207
- {apm_cli-0.8.7 → apm_cli-0.8.9}/AUTHORS +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/LICENSE +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/setup.cfg +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/adapters/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/adapters/client/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/adapters/client/base.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/adapters/client/codex.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/adapters/client/copilot.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/adapters/client/cursor.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/adapters/client/opencode.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/adapters/client/vscode.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/adapters/package_manager/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/adapters/package_manager/base.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/adapters/package_manager/default_manager.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/bundle/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/bundle/packer.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/bundle/plugin_exporter.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/bundle/unpacker.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/audit.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/compile/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/compile/watcher.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/config.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/deps/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/deps/_utils.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/init.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/list_cmd.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/mcp.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/prune.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/run.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/runtime.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/uninstall/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/commands/update.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/compilation/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/compilation/agents_compiler.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/compilation/claude_formatter.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/compilation/constants.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/compilation/constitution.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/compilation/constitution_block.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/compilation/context_optimizer.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/compilation/distributed_compiler.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/compilation/injector.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/compilation/link_resolver.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/compilation/template_builder.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/config.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/constants.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/core/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/core/auth.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/core/conflict_detector.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/core/docker_args.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/core/operations.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/core/safe_installer.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/core/script_runner.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/core/token_manager.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/deps/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/deps/aggregator.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/deps/apm_resolver.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/deps/collection_parser.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/deps/dependency_graph.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/deps/package_validator.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/deps/plugin_parser.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/deps/verifier.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/factory.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/integration/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/integration/mcp_integrator.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/integration/skill_transformer.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/integration/utils.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/models/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/models/apm_package.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/models/dependency/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/models/dependency/mcp.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/models/dependency/reference.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/models/dependency/types.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/models/plugin.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/models/results.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/models/validation.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/output/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/output/formatters.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/output/models.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/output/script_formatters.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/policy/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/policy/ci_checks.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/policy/discovery.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/policy/inheritance.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/policy/matcher.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/policy/models.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/policy/parser.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/policy/policy_checks.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/policy/schema.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/primitives/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/primitives/discovery.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/primitives/models.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/primitives/parser.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/registry/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/registry/client.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/registry/integration.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/registry/operations.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/runtime/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/runtime/base.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/runtime/codex_runtime.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/runtime/copilot_runtime.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/runtime/factory.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/runtime/llm_runtime.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/runtime/manager.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/security/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/security/audit_report.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/security/content_scanner.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/security/file_scanner.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/security/gate.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/utils/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/utils/console.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/utils/content_hash.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/utils/diagnostics.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/utils/file_ops.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/utils/github_host.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/utils/helpers.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/utils/path_security.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/utils/paths.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/utils/version_checker.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/utils/yaml_io.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/version.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/workflow/__init__.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/workflow/discovery.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/workflow/parser.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli/workflow/runner.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli.egg-info/dependency_links.txt +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli.egg-info/entry_points.txt +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli.egg-info/requires.txt +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/src/apm_cli.egg-info/top_level.txt +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/tests/test_apm_package_models.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/tests/test_apm_resolver.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/tests/test_codex_docker_args_fix.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/tests/test_codex_empty_string_and_defaults.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/tests/test_collision_integration.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/tests/test_console.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/tests/test_distributed_compilation.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/tests/test_empty_string_and_defaults.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/tests/test_enhanced_discovery.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/tests/test_github_downloader.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/tests/test_github_downloader_token_precedence.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/tests/test_lockfile.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/tests/test_runnable_prompts.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/tests/test_runtime_manager_token_precedence.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/tests/test_token_manager.py +0 -0
- {apm_cli-0.8.7 → apm_cli-0.8.9}/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.8.
|
|
3
|
+
Version: 0.8.9
|
|
4
4
|
Summary: MCP configuration tool
|
|
5
5
|
Author-email: Daniel Meppiel <user@example.com>
|
|
6
6
|
License: MIT License
|
|
@@ -66,7 +66,7 @@ Dynamic: license-file
|
|
|
66
66
|
|
|
67
67
|
Think `package.json`, `requirements.txt`, or `Cargo.toml` — but for AI agent configuration.
|
|
68
68
|
|
|
69
|
-
GitHub Copilot · Claude Code · Cursor · OpenCode
|
|
69
|
+
GitHub Copilot · Claude Code · Cursor · OpenCode · Codex
|
|
70
70
|
|
|
71
71
|
**[Documentation](https://microsoft.github.io/apm/)** · **[Quick Start](https://microsoft.github.io/apm/getting-started/quick-start/)** · **[CLI Reference](https://microsoft.github.io/apm/reference/cli-commands/)**
|
|
72
72
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Think `package.json`, `requirements.txt`, or `Cargo.toml` — but for AI agent configuration.
|
|
6
6
|
|
|
7
|
-
GitHub Copilot · Claude Code · Cursor · OpenCode
|
|
7
|
+
GitHub Copilot · Claude Code · Cursor · OpenCode · Codex
|
|
8
8
|
|
|
9
9
|
**[Documentation](https://microsoft.github.io/apm/)** · **[Quick Start](https://microsoft.github.io/apm/getting-started/quick-start/)** · **[CLI Reference](https://microsoft.github.io/apm/reference/cli-commands/)**
|
|
10
10
|
|
|
@@ -13,7 +13,8 @@ _TARGET_PREFIXES = {
|
|
|
13
13
|
"claude": [".claude/"],
|
|
14
14
|
"cursor": [".cursor/"],
|
|
15
15
|
"opencode": [".opencode/"],
|
|
16
|
-
"
|
|
16
|
+
"codex": [".codex/", ".agents/"],
|
|
17
|
+
"all": [".github/", ".claude/", ".cursor/", ".opencode/", ".codex/", ".agents/"],
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
# Cross-target path equivalences for skills/ and agents/ directories.
|
|
@@ -46,6 +47,10 @@ _CROSS_TARGET_MAPS: Dict[str, Dict[str, str]] = {
|
|
|
46
47
|
".github/skills/": ".opencode/skills/",
|
|
47
48
|
".github/agents/": ".opencode/agents/",
|
|
48
49
|
},
|
|
50
|
+
"codex": {
|
|
51
|
+
".github/skills/": ".agents/skills/",
|
|
52
|
+
".github/agents/": ".codex/agents/",
|
|
53
|
+
},
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
|
|
@@ -22,6 +22,7 @@ from apm_cli.commands.deps import deps
|
|
|
22
22
|
from apm_cli.commands.init import init
|
|
23
23
|
from apm_cli.commands.install import install
|
|
24
24
|
from apm_cli.commands.list_cmd import list as list_cmd
|
|
25
|
+
from apm_cli.commands.marketplace import marketplace, search as marketplace_search
|
|
25
26
|
from apm_cli.commands.mcp import mcp
|
|
26
27
|
from apm_cli.commands.pack import pack_cmd, unpack_cmd
|
|
27
28
|
from apm_cli.commands.prune import prune
|
|
@@ -69,6 +70,8 @@ cli.add_command(list_cmd, name="list")
|
|
|
69
70
|
cli.add_command(config)
|
|
70
71
|
cli.add_command(runtime)
|
|
71
72
|
cli.add_command(mcp)
|
|
73
|
+
cli.add_command(marketplace)
|
|
74
|
+
cli.add_command(marketplace_search, name="search")
|
|
72
75
|
|
|
73
76
|
|
|
74
77
|
def _configure_encoding() -> None:
|
|
@@ -432,12 +432,13 @@ def _create_plugin_json(config):
|
|
|
432
432
|
f.write(json.dumps(plugin_data, indent=2) + "\n")
|
|
433
433
|
|
|
434
434
|
|
|
435
|
-
def _create_minimal_apm_yml(config, plugin=False):
|
|
435
|
+
def _create_minimal_apm_yml(config, plugin=False, target_path=None):
|
|
436
436
|
"""Create minimal apm.yml file with auto-detected metadata.
|
|
437
437
|
|
|
438
438
|
Args:
|
|
439
439
|
config: dict with name, version, description, author keys.
|
|
440
440
|
plugin: if True, include a devDependencies section.
|
|
441
|
+
target_path: explicit file path to write (defaults to cwd/apm.yml).
|
|
441
442
|
"""
|
|
442
443
|
# Create minimal apm.yml structure
|
|
443
444
|
apm_yml_data = {
|
|
@@ -455,4 +456,5 @@ def _create_minimal_apm_yml(config, plugin=False):
|
|
|
455
456
|
|
|
456
457
|
# Write apm.yml
|
|
457
458
|
from ..utils.yaml_io import dump_yaml
|
|
458
|
-
|
|
459
|
+
out_path = target_path or APM_YML_FILENAME
|
|
460
|
+
dump_yaml(apm_yml_data, out_path)
|
|
@@ -172,7 +172,7 @@ def _get_validation_suggestion(error_msg):
|
|
|
172
172
|
@click.option(
|
|
173
173
|
"--target",
|
|
174
174
|
"-t",
|
|
175
|
-
type=click.Choice(["copilot", "vscode", "agents", "claude", "cursor", "opencode", "all"]),
|
|
175
|
+
type=click.Choice(["copilot", "vscode", "agents", "claude", "cursor", "opencode", "codex", "all"]),
|
|
176
176
|
default=None,
|
|
177
177
|
help="Target platform: copilot (AGENTS.md), claude (CLAUDE.md), cursor, opencode, or all. 'vscode' and 'agents' are deprecated aliases for 'copilot'. Auto-detects if not specified.",
|
|
178
178
|
)
|
|
@@ -28,14 +28,205 @@ def deps():
|
|
|
28
28
|
pass
|
|
29
29
|
|
|
30
30
|
|
|
31
|
+
def _show_scope_deps(scope_label, apm_dir, logger, console, has_rich):
|
|
32
|
+
"""Display dependencies for a single scope (Project or Global)."""
|
|
33
|
+
from ...deps.lockfile import LockFile, get_lockfile_path
|
|
34
|
+
|
|
35
|
+
apm_modules_path = apm_dir / APM_MODULES_DIR
|
|
36
|
+
|
|
37
|
+
# Check if apm_modules exists
|
|
38
|
+
if not apm_modules_path.exists():
|
|
39
|
+
logger.progress(f"No APM dependencies installed ({scope_label} scope)")
|
|
40
|
+
logger.verbose_detail("Run 'apm install' to install dependencies from apm.yml")
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
# Load project dependencies to check for orphaned packages
|
|
44
|
+
# GitHub: owner/repo or owner/virtual-pkg-name (2 levels)
|
|
45
|
+
# Azure DevOps: org/project/repo or org/project/virtual-pkg-name (3 levels)
|
|
46
|
+
declared_sources = {} # dep_path -> 'github' | 'azure-devops'
|
|
47
|
+
try:
|
|
48
|
+
apm_yml_path = apm_dir / APM_YML_FILENAME
|
|
49
|
+
if apm_yml_path.exists():
|
|
50
|
+
project_package = APMPackage.from_apm_yml(apm_yml_path)
|
|
51
|
+
for dep in project_package.get_apm_dependencies():
|
|
52
|
+
# Build the expected installed package name
|
|
53
|
+
repo_parts = dep.repo_url.split('/')
|
|
54
|
+
source = 'azure-devops' if dep.is_azure_devops() else 'github'
|
|
55
|
+
is_ado = dep.is_azure_devops() and len(repo_parts) >= 3
|
|
56
|
+
is_gh = len(repo_parts) >= 2
|
|
57
|
+
|
|
58
|
+
if not dep.is_virtual:
|
|
59
|
+
# Regular package: use full repo_url path
|
|
60
|
+
if is_ado:
|
|
61
|
+
declared_sources[f"{repo_parts[0]}/{repo_parts[1]}/{repo_parts[2]}"] = source
|
|
62
|
+
elif is_gh:
|
|
63
|
+
declared_sources[f"{repo_parts[0]}/{repo_parts[1]}"] = source
|
|
64
|
+
continue
|
|
65
|
+
|
|
66
|
+
if dep.is_virtual_subdirectory() and dep.virtual_path:
|
|
67
|
+
# Virtual subdirectory packages keep natural path structure.
|
|
68
|
+
if is_ado:
|
|
69
|
+
declared_sources[
|
|
70
|
+
f"{repo_parts[0]}/{repo_parts[1]}/{repo_parts[2]}/{dep.virtual_path}"
|
|
71
|
+
] = source
|
|
72
|
+
elif is_gh:
|
|
73
|
+
declared_sources[
|
|
74
|
+
f"{repo_parts[0]}/{repo_parts[1]}/{dep.virtual_path}"
|
|
75
|
+
] = source
|
|
76
|
+
continue
|
|
77
|
+
|
|
78
|
+
# Virtual file/collection packages are flattened.
|
|
79
|
+
package_name = dep.get_virtual_package_name()
|
|
80
|
+
if is_ado:
|
|
81
|
+
declared_sources[f"{repo_parts[0]}/{repo_parts[1]}/{package_name}"] = source
|
|
82
|
+
elif is_gh:
|
|
83
|
+
declared_sources[f"{repo_parts[0]}/{package_name}"] = source
|
|
84
|
+
except Exception:
|
|
85
|
+
pass # Continue without orphan detection if apm.yml parsing fails
|
|
86
|
+
|
|
87
|
+
# Also load lockfile deps to avoid false orphan flags on transitive deps
|
|
88
|
+
try:
|
|
89
|
+
lockfile_path = get_lockfile_path(apm_dir)
|
|
90
|
+
if lockfile_path.exists():
|
|
91
|
+
lockfile = LockFile.read(lockfile_path)
|
|
92
|
+
for dep in lockfile.dependencies.values():
|
|
93
|
+
# Lockfile keys match declared_sources format (owner/repo)
|
|
94
|
+
dep_key = dep.get_unique_key()
|
|
95
|
+
if dep_key and dep_key not in declared_sources:
|
|
96
|
+
declared_sources[dep_key] = 'github'
|
|
97
|
+
except Exception:
|
|
98
|
+
pass # Continue without lockfile if it can't be read
|
|
99
|
+
|
|
100
|
+
# Scan for installed packages in org-namespaced structure
|
|
101
|
+
# Walks the tree to find directories containing apm.yml or SKILL.md,
|
|
102
|
+
# handling GitHub (2-level), ADO (3-level), and subdirectory (4+ level) packages.
|
|
103
|
+
installed_packages = []
|
|
104
|
+
orphaned_packages = []
|
|
105
|
+
for candidate in apm_modules_path.rglob("*"):
|
|
106
|
+
if not candidate.is_dir() or candidate.name.startswith('.'):
|
|
107
|
+
continue
|
|
108
|
+
has_apm_yml = (candidate / APM_YML_FILENAME).exists()
|
|
109
|
+
has_skill_md = (candidate / SKILL_MD_FILENAME).exists()
|
|
110
|
+
if not has_apm_yml and not has_skill_md:
|
|
111
|
+
continue
|
|
112
|
+
rel_parts = candidate.relative_to(apm_modules_path).parts
|
|
113
|
+
if len(rel_parts) < 2:
|
|
114
|
+
continue
|
|
115
|
+
org_repo_name = "/".join(rel_parts)
|
|
116
|
+
|
|
117
|
+
# Skip sub-skills inside .apm/ directories -- they belong to the parent package
|
|
118
|
+
if '.apm' in rel_parts:
|
|
119
|
+
continue
|
|
120
|
+
|
|
121
|
+
# Skip skill sub-dirs nested inside another package (e.g. plugin
|
|
122
|
+
# skills/ directories that are deployment artifacts, not packages).
|
|
123
|
+
if has_skill_md and not has_apm_yml and _is_nested_under_package(candidate, apm_modules_path):
|
|
124
|
+
continue
|
|
125
|
+
|
|
126
|
+
try:
|
|
127
|
+
version = 'unknown'
|
|
128
|
+
if has_apm_yml:
|
|
129
|
+
package = APMPackage.from_apm_yml(candidate / APM_YML_FILENAME)
|
|
130
|
+
version = package.version or 'unknown'
|
|
131
|
+
primitives = _count_primitives(candidate)
|
|
132
|
+
|
|
133
|
+
is_orphaned = org_repo_name not in declared_sources
|
|
134
|
+
if is_orphaned:
|
|
135
|
+
orphaned_packages.append(org_repo_name)
|
|
136
|
+
|
|
137
|
+
installed_packages.append({
|
|
138
|
+
'name': org_repo_name,
|
|
139
|
+
'version': version,
|
|
140
|
+
'source': 'orphaned' if is_orphaned else declared_sources.get(org_repo_name, 'github'),
|
|
141
|
+
'primitives': primitives,
|
|
142
|
+
'path': str(candidate),
|
|
143
|
+
'is_orphaned': is_orphaned
|
|
144
|
+
})
|
|
145
|
+
except Exception as e:
|
|
146
|
+
logger.warning(f"Failed to read package {org_repo_name}: {e}")
|
|
147
|
+
|
|
148
|
+
if not installed_packages:
|
|
149
|
+
logger.progress(
|
|
150
|
+
f"apm_modules/ directory exists but contains no valid packages ({scope_label} scope)"
|
|
151
|
+
)
|
|
152
|
+
return
|
|
153
|
+
|
|
154
|
+
# Display packages in table format
|
|
155
|
+
if has_rich:
|
|
156
|
+
from rich.table import Table
|
|
157
|
+
|
|
158
|
+
table = Table(
|
|
159
|
+
title=f" APM Dependencies ({scope_label})",
|
|
160
|
+
show_header=True,
|
|
161
|
+
header_style="bold cyan",
|
|
162
|
+
)
|
|
163
|
+
table.add_column("Package", style="bold white")
|
|
164
|
+
table.add_column("Version", style="yellow")
|
|
165
|
+
table.add_column("Source", style="blue")
|
|
166
|
+
table.add_column("Prompts", style="magenta", justify="center")
|
|
167
|
+
table.add_column("Instructions", style="green", justify="center")
|
|
168
|
+
table.add_column("Agents", style="cyan", justify="center")
|
|
169
|
+
table.add_column("Skills", style="yellow", justify="center")
|
|
170
|
+
table.add_column("Hooks", style="red", justify="center")
|
|
171
|
+
|
|
172
|
+
for pkg in installed_packages:
|
|
173
|
+
p = pkg['primitives']
|
|
174
|
+
table.add_row(
|
|
175
|
+
pkg['name'],
|
|
176
|
+
pkg['version'],
|
|
177
|
+
pkg['source'],
|
|
178
|
+
str(p.get('prompts', 0)) if p.get('prompts', 0) > 0 else "-",
|
|
179
|
+
str(p.get('instructions', 0)) if p.get('instructions', 0) > 0 else "-",
|
|
180
|
+
str(p.get('agents', 0)) if p.get('agents', 0) > 0 else "-",
|
|
181
|
+
str(p.get('skills', 0)) if p.get('skills', 0) > 0 else "-",
|
|
182
|
+
str(p.get('hooks', 0)) if p.get('hooks', 0) > 0 else "-",
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
console.print(table)
|
|
186
|
+
|
|
187
|
+
# Show orphaned packages warning
|
|
188
|
+
if orphaned_packages:
|
|
189
|
+
console.print(f"\n[!] {len(orphaned_packages)} orphaned package(s) found (not in apm.yml):", style="yellow")
|
|
190
|
+
for pkg in orphaned_packages:
|
|
191
|
+
console.print(f" * {pkg}", style="dim yellow")
|
|
192
|
+
console.print("\n Run 'apm prune' to remove orphaned packages", style="cyan")
|
|
193
|
+
else:
|
|
194
|
+
# Fallback text table
|
|
195
|
+
click.echo(f" APM Dependencies ({scope_label}):")
|
|
196
|
+
click.echo(f"{'Package':<30} {'Version':<10} {'Source':<12} {'Prompts':>7} {'Instr':>7} {'Agents':>7} {'Skills':>7} {'Hooks':>7}")
|
|
197
|
+
click.echo("-" * 98)
|
|
198
|
+
|
|
199
|
+
for pkg in installed_packages:
|
|
200
|
+
p = pkg['primitives']
|
|
201
|
+
name = pkg['name'][:28]
|
|
202
|
+
version = pkg['version'][:8]
|
|
203
|
+
source = pkg['source'][:10]
|
|
204
|
+
prompts = str(p.get('prompts', 0)) if p.get('prompts', 0) > 0 else "-"
|
|
205
|
+
instructions = str(p.get('instructions', 0)) if p.get('instructions', 0) > 0 else "-"
|
|
206
|
+
agents = str(p.get('agents', 0)) if p.get('agents', 0) > 0 else "-"
|
|
207
|
+
skills = str(p.get('skills', 0)) if p.get('skills', 0) > 0 else "-"
|
|
208
|
+
hooks = str(p.get('hooks', 0)) if p.get('hooks', 0) > 0 else "-"
|
|
209
|
+
click.echo(f"{name:<30} {version:<10} {source:<12} {prompts:>7} {instructions:>7} {agents:>7} {skills:>7} {hooks:>7}")
|
|
210
|
+
|
|
211
|
+
# Show orphaned packages warning
|
|
212
|
+
if orphaned_packages:
|
|
213
|
+
click.echo(f"\n[!] {len(orphaned_packages)} orphaned package(s) found (not in apm.yml):")
|
|
214
|
+
for pkg in orphaned_packages:
|
|
215
|
+
click.echo(f" * {pkg}")
|
|
216
|
+
click.echo("\n Run 'apm prune' to remove orphaned packages")
|
|
217
|
+
|
|
218
|
+
|
|
31
219
|
@deps.command(name="list", help="List installed APM dependencies")
|
|
32
|
-
|
|
220
|
+
@click.option("--global", "-g", "global_", is_flag=True, default=False,
|
|
221
|
+
help="List user-scope dependencies (~/.apm/) instead of project")
|
|
222
|
+
@click.option("--all", "show_all", is_flag=True, default=False,
|
|
223
|
+
help="Show both project and user-scope dependencies")
|
|
224
|
+
def list_packages(global_, show_all):
|
|
33
225
|
"""Show all installed APM dependencies with context files and agent workflows."""
|
|
34
226
|
logger = CommandLogger("deps-list")
|
|
35
227
|
|
|
36
228
|
try:
|
|
37
229
|
# Import Rich components with fallback
|
|
38
|
-
from rich.table import Table
|
|
39
230
|
from rich.console import Console
|
|
40
231
|
import shutil
|
|
41
232
|
term_width = shutil.get_terminal_size((120, 24)).columns
|
|
@@ -44,192 +235,29 @@ def list_packages():
|
|
|
44
235
|
except ImportError:
|
|
45
236
|
has_rich = False
|
|
46
237
|
console = None
|
|
47
|
-
|
|
238
|
+
|
|
48
239
|
try:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
# GitHub: owner/repo or owner/virtual-pkg-name (2 levels)
|
|
60
|
-
# Azure DevOps: org/project/repo or org/project/virtual-pkg-name (3 levels)
|
|
61
|
-
declared_sources = {} # dep_path -> 'github' | 'azure-devops'
|
|
62
|
-
try:
|
|
63
|
-
apm_yml_path = project_root / APM_YML_FILENAME
|
|
64
|
-
if apm_yml_path.exists():
|
|
65
|
-
project_package = APMPackage.from_apm_yml(apm_yml_path)
|
|
66
|
-
for dep in project_package.get_apm_dependencies():
|
|
67
|
-
# Build the expected installed package name
|
|
68
|
-
repo_parts = dep.repo_url.split('/')
|
|
69
|
-
source = 'azure-devops' if dep.is_azure_devops() else 'github'
|
|
70
|
-
is_ado = dep.is_azure_devops() and len(repo_parts) >= 3
|
|
71
|
-
is_gh = len(repo_parts) >= 2
|
|
72
|
-
|
|
73
|
-
if not dep.is_virtual:
|
|
74
|
-
# Regular package: use full repo_url path
|
|
75
|
-
if is_ado:
|
|
76
|
-
declared_sources[f"{repo_parts[0]}/{repo_parts[1]}/{repo_parts[2]}"] = source
|
|
77
|
-
elif is_gh:
|
|
78
|
-
declared_sources[f"{repo_parts[0]}/{repo_parts[1]}"] = source
|
|
79
|
-
continue
|
|
80
|
-
|
|
81
|
-
if dep.is_virtual_subdirectory() and dep.virtual_path:
|
|
82
|
-
# Virtual subdirectory packages keep natural path structure.
|
|
83
|
-
if is_ado:
|
|
84
|
-
declared_sources[
|
|
85
|
-
f"{repo_parts[0]}/{repo_parts[1]}/{repo_parts[2]}/{dep.virtual_path}"
|
|
86
|
-
] = source
|
|
87
|
-
elif is_gh:
|
|
88
|
-
declared_sources[
|
|
89
|
-
f"{repo_parts[0]}/{repo_parts[1]}/{dep.virtual_path}"
|
|
90
|
-
] = source
|
|
91
|
-
continue
|
|
92
|
-
|
|
93
|
-
# Virtual file/collection packages are flattened.
|
|
94
|
-
package_name = dep.get_virtual_package_name()
|
|
95
|
-
if is_ado:
|
|
96
|
-
declared_sources[f"{repo_parts[0]}/{repo_parts[1]}/{package_name}"] = source
|
|
97
|
-
elif is_gh:
|
|
98
|
-
declared_sources[f"{repo_parts[0]}/{package_name}"] = source
|
|
99
|
-
except Exception:
|
|
100
|
-
pass # Continue without orphan detection if apm.yml parsing fails
|
|
101
|
-
|
|
102
|
-
# Also load lockfile deps to avoid false orphan flags on transitive deps
|
|
103
|
-
try:
|
|
104
|
-
from ...deps.lockfile import LockFile, get_lockfile_path
|
|
105
|
-
lockfile_path = get_lockfile_path(project_root)
|
|
106
|
-
if lockfile_path.exists():
|
|
107
|
-
lockfile = LockFile.read(lockfile_path)
|
|
108
|
-
for dep in lockfile.dependencies.values():
|
|
109
|
-
# Lockfile keys match declared_sources format (owner/repo)
|
|
110
|
-
dep_key = dep.get_unique_key()
|
|
111
|
-
if dep_key and dep_key not in declared_sources:
|
|
112
|
-
declared_sources[dep_key] = 'github'
|
|
113
|
-
except Exception:
|
|
114
|
-
pass # Continue without lockfile if it can't be read
|
|
115
|
-
|
|
116
|
-
# Scan for installed packages in org-namespaced structure
|
|
117
|
-
# Walks the tree to find directories containing apm.yml or SKILL.md,
|
|
118
|
-
# handling GitHub (2-level), ADO (3-level), and subdirectory (4+ level) packages.
|
|
119
|
-
installed_packages = []
|
|
120
|
-
orphaned_packages = []
|
|
121
|
-
for candidate in apm_modules_path.rglob("*"):
|
|
122
|
-
if not candidate.is_dir() or candidate.name.startswith('.'):
|
|
123
|
-
continue
|
|
124
|
-
has_apm_yml = (candidate / APM_YML_FILENAME).exists()
|
|
125
|
-
has_skill_md = (candidate / SKILL_MD_FILENAME).exists()
|
|
126
|
-
if not has_apm_yml and not has_skill_md:
|
|
127
|
-
continue
|
|
128
|
-
rel_parts = candidate.relative_to(apm_modules_path).parts
|
|
129
|
-
if len(rel_parts) < 2:
|
|
130
|
-
continue
|
|
131
|
-
org_repo_name = "/".join(rel_parts)
|
|
132
|
-
|
|
133
|
-
# Skip sub-skills inside .apm/ directories -- they belong to the parent package
|
|
134
|
-
if '.apm' in rel_parts:
|
|
135
|
-
continue
|
|
136
|
-
|
|
137
|
-
# Skip skill sub-dirs nested inside another package (e.g. plugin
|
|
138
|
-
# skills/ directories that are deployment artifacts, not packages).
|
|
139
|
-
if has_skill_md and not has_apm_yml and _is_nested_under_package(candidate, apm_modules_path):
|
|
140
|
-
continue
|
|
141
|
-
|
|
142
|
-
try:
|
|
143
|
-
version = 'unknown'
|
|
144
|
-
if has_apm_yml:
|
|
145
|
-
package = APMPackage.from_apm_yml(candidate / APM_YML_FILENAME)
|
|
146
|
-
version = package.version or 'unknown'
|
|
147
|
-
primitives = _count_primitives(candidate)
|
|
148
|
-
|
|
149
|
-
is_orphaned = org_repo_name not in declared_sources
|
|
150
|
-
if is_orphaned:
|
|
151
|
-
orphaned_packages.append(org_repo_name)
|
|
152
|
-
|
|
153
|
-
installed_packages.append({
|
|
154
|
-
'name': org_repo_name,
|
|
155
|
-
'version': version,
|
|
156
|
-
'source': 'orphaned' if is_orphaned else declared_sources.get(org_repo_name, 'github'),
|
|
157
|
-
'primitives': primitives,
|
|
158
|
-
'path': str(candidate),
|
|
159
|
-
'is_orphaned': is_orphaned
|
|
160
|
-
})
|
|
161
|
-
except Exception as e:
|
|
162
|
-
logger.warning(f"Failed to read package {org_repo_name}: {e}")
|
|
163
|
-
|
|
164
|
-
if not installed_packages:
|
|
165
|
-
logger.progress("apm_modules/ directory exists but contains no valid packages")
|
|
166
|
-
return
|
|
167
|
-
|
|
168
|
-
# Display packages in table format
|
|
169
|
-
if has_rich:
|
|
170
|
-
table = Table(title=" APM Dependencies", show_header=True, header_style="bold cyan")
|
|
171
|
-
table.add_column("Package", style="bold white")
|
|
172
|
-
table.add_column("Version", style="yellow")
|
|
173
|
-
table.add_column("Source", style="blue")
|
|
174
|
-
table.add_column("Prompts", style="magenta", justify="center")
|
|
175
|
-
table.add_column("Instructions", style="green", justify="center")
|
|
176
|
-
table.add_column("Agents", style="cyan", justify="center")
|
|
177
|
-
table.add_column("Skills", style="yellow", justify="center")
|
|
178
|
-
table.add_column("Hooks", style="red", justify="center")
|
|
179
|
-
|
|
180
|
-
for pkg in installed_packages:
|
|
181
|
-
p = pkg['primitives']
|
|
182
|
-
table.add_row(
|
|
183
|
-
pkg['name'],
|
|
184
|
-
pkg['version'],
|
|
185
|
-
pkg['source'],
|
|
186
|
-
str(p.get('prompts', 0)) if p.get('prompts', 0) > 0 else "-",
|
|
187
|
-
str(p.get('instructions', 0)) if p.get('instructions', 0) > 0 else "-",
|
|
188
|
-
str(p.get('agents', 0)) if p.get('agents', 0) > 0 else "-",
|
|
189
|
-
str(p.get('skills', 0)) if p.get('skills', 0) > 0 else "-",
|
|
190
|
-
str(p.get('hooks', 0)) if p.get('hooks', 0) > 0 else "-",
|
|
191
|
-
)
|
|
192
|
-
|
|
193
|
-
console.print(table)
|
|
194
|
-
|
|
195
|
-
# Show orphaned packages warning
|
|
196
|
-
if orphaned_packages:
|
|
197
|
-
console.print(f"\n[!] {len(orphaned_packages)} orphaned package(s) found (not in apm.yml):", style="yellow")
|
|
198
|
-
for pkg in orphaned_packages:
|
|
199
|
-
console.print(f" * {pkg}", style="dim yellow")
|
|
200
|
-
console.print("\n Run 'apm prune' to remove orphaned packages", style="cyan")
|
|
240
|
+
from ...core.scope import InstallScope, get_apm_dir
|
|
241
|
+
|
|
242
|
+
if show_all:
|
|
243
|
+
# Show both scopes
|
|
244
|
+
_show_scope_deps("Project", get_apm_dir(InstallScope.PROJECT), logger, console, has_rich)
|
|
245
|
+
if console and has_rich:
|
|
246
|
+
console.print() # spacing between tables
|
|
247
|
+
_show_scope_deps("Global", get_apm_dir(InstallScope.USER), logger, console, has_rich)
|
|
248
|
+
elif global_:
|
|
249
|
+
_show_scope_deps("Global", get_apm_dir(InstallScope.USER), logger, console, has_rich)
|
|
201
250
|
else:
|
|
202
|
-
|
|
203
|
-
click.echo(" APM Dependencies:")
|
|
204
|
-
click.echo(f"{'Package':<30} {'Version':<10} {'Source':<12} {'Prompts':>7} {'Instr':>7} {'Agents':>7} {'Skills':>7} {'Hooks':>7}")
|
|
205
|
-
click.echo("-" * 98)
|
|
206
|
-
|
|
207
|
-
for pkg in installed_packages:
|
|
208
|
-
p = pkg['primitives']
|
|
209
|
-
name = pkg['name'][:28]
|
|
210
|
-
version = pkg['version'][:8]
|
|
211
|
-
source = pkg['source'][:10]
|
|
212
|
-
prompts = str(p.get('prompts', 0)) if p.get('prompts', 0) > 0 else "-"
|
|
213
|
-
instructions = str(p.get('instructions', 0)) if p.get('instructions', 0) > 0 else "-"
|
|
214
|
-
agents = str(p.get('agents', 0)) if p.get('agents', 0) > 0 else "-"
|
|
215
|
-
skills = str(p.get('skills', 0)) if p.get('skills', 0) > 0 else "-"
|
|
216
|
-
hooks = str(p.get('hooks', 0)) if p.get('hooks', 0) > 0 else "-"
|
|
217
|
-
click.echo(f"{name:<30} {version:<10} {source:<12} {prompts:>7} {instructions:>7} {agents:>7} {skills:>7} {hooks:>7}")
|
|
218
|
-
|
|
219
|
-
# Show orphaned packages warning
|
|
220
|
-
if orphaned_packages:
|
|
221
|
-
click.echo(f"\n[!] {len(orphaned_packages)} orphaned package(s) found (not in apm.yml):")
|
|
222
|
-
for pkg in orphaned_packages:
|
|
223
|
-
click.echo(f" * {pkg}")
|
|
224
|
-
click.echo("\n Run 'apm prune' to remove orphaned packages")
|
|
225
|
-
|
|
251
|
+
_show_scope_deps("Project", get_apm_dir(InstallScope.PROJECT), logger, console, has_rich)
|
|
226
252
|
except Exception as e:
|
|
227
253
|
logger.error(f"Error listing dependencies: {e}")
|
|
228
254
|
sys.exit(1)
|
|
229
255
|
|
|
230
256
|
|
|
231
|
-
@deps.command(help="Show dependency tree structure")
|
|
232
|
-
|
|
257
|
+
@deps.command(help="Show dependency tree structure")
|
|
258
|
+
@click.option("--global", "-g", "global_", is_flag=True, default=False,
|
|
259
|
+
help="Show user-scope dependency tree (~/.apm/)")
|
|
260
|
+
def tree(global_):
|
|
233
261
|
"""Display dependencies in hierarchical tree format using lockfile."""
|
|
234
262
|
logger = CommandLogger("deps-tree")
|
|
235
263
|
|
|
@@ -242,26 +270,29 @@ def tree():
|
|
|
242
270
|
except ImportError:
|
|
243
271
|
has_rich = False
|
|
244
272
|
console = None
|
|
245
|
-
|
|
273
|
+
|
|
246
274
|
try:
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
275
|
+
from ...core.scope import InstallScope, get_apm_dir
|
|
276
|
+
scope = InstallScope.USER if global_ else InstallScope.PROJECT
|
|
277
|
+
apm_dir = get_apm_dir(scope)
|
|
278
|
+
project_root = apm_dir
|
|
279
|
+
apm_modules_path = apm_dir / APM_MODULES_DIR
|
|
280
|
+
|
|
250
281
|
# Load project info
|
|
251
282
|
project_name = "my-project"
|
|
252
283
|
try:
|
|
253
|
-
apm_yml_path =
|
|
284
|
+
apm_yml_path = apm_dir / APM_YML_FILENAME
|
|
254
285
|
if apm_yml_path.exists():
|
|
255
286
|
root_package = APMPackage.from_apm_yml(apm_yml_path)
|
|
256
287
|
project_name = root_package.name
|
|
257
288
|
except Exception:
|
|
258
289
|
pass
|
|
259
|
-
|
|
290
|
+
|
|
260
291
|
# Try to load lockfile for accurate tree with depth/parent info
|
|
261
292
|
lockfile_deps = None
|
|
262
293
|
try:
|
|
263
294
|
from ...deps.lockfile import LockFile, get_lockfile_path
|
|
264
|
-
lockfile_path = get_lockfile_path(
|
|
295
|
+
lockfile_path = get_lockfile_path(apm_dir)
|
|
265
296
|
if lockfile_path.exists():
|
|
266
297
|
lockfile = LockFile.read(lockfile_path)
|
|
267
298
|
if lockfile:
|
|
@@ -460,7 +491,9 @@ def clean(dry_run: bool, yes: bool):
|
|
|
460
491
|
show_default=True,
|
|
461
492
|
help="Max concurrent package downloads (0 to disable parallelism)",
|
|
462
493
|
)
|
|
463
|
-
|
|
494
|
+
@click.option("--global", "-g", "global_", is_flag=True, default=False,
|
|
495
|
+
help="Update user-scope dependencies (~/.apm/)")
|
|
496
|
+
def update(packages, verbose, force, target, parallel_downloads, global_):
|
|
464
497
|
"""Update APM dependencies to latest git refs.
|
|
465
498
|
|
|
466
499
|
Re-resolves git references (branches/tags) to their current SHAs,
|
|
@@ -490,11 +523,14 @@ def update(packages, verbose, force, target, parallel_downloads):
|
|
|
490
523
|
logger.progress(f"Import error: {_APM_IMPORT_ERROR}")
|
|
491
524
|
sys.exit(1)
|
|
492
525
|
|
|
493
|
-
|
|
526
|
+
from ...core.scope import InstallScope, get_apm_dir
|
|
527
|
+
scope = InstallScope.USER if global_ else InstallScope.PROJECT
|
|
528
|
+
project_root = get_apm_dir(scope)
|
|
494
529
|
apm_yml_path = project_root / APM_YML_FILENAME
|
|
495
530
|
|
|
496
531
|
if not apm_yml_path.exists():
|
|
497
|
-
|
|
532
|
+
scope_hint = "~/.apm/" if global_ else "current directory"
|
|
533
|
+
logger.error(f"No {APM_YML_FILENAME} found in {scope_hint}")
|
|
498
534
|
sys.exit(1)
|
|
499
535
|
|
|
500
536
|
try:
|