apm-cli 0.16.1__tar.gz → 0.18.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.16.1/src/apm_cli.egg-info → apm_cli-0.18.0}/PKG-INFO +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/pyproject.toml +9 -9
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/adapters/client/base.py +20 -7
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/adapters/client/copilot.py +17 -18
- apm_cli-0.18.0/src/apm_cli/adapters/client/intellij.py +104 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/adapters/client/vscode.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/bundle/lockfile_enrichment.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/bundle/packer.py +0 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/bundle/plugin_exporter.py +12 -49
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/bundle/unpacker.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/cli.py +5 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/_apm_yml_writer.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/_helpers.py +91 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/audit.py +199 -24
- apm_cli-0.18.0/src/apm_cli/commands/compile/cli.py +1002 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/config.py +179 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/deps/_utils.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/deps/cli.py +26 -32
- apm_cli-0.18.0/src/apm_cli/commands/find.py +241 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/init.py +42 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/install.py +118 -47
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/list_cmd.py +0 -1
- apm_cli-0.18.0/src/apm_cli/commands/lock.py +206 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/__init__.py +37 -8
- apm_cli-0.18.0/src/apm_cli/commands/marketplace/audit.py +122 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/plugin/__init__.py +0 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/plugin/remove.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/mcp.py +17 -7
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/outdated.py +80 -9
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/pack.py +115 -72
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/policy.py +1 -3
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/prune.py +2 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/publish.py +36 -10
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/self_update.py +37 -3
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/uninstall/cli.py +1 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/uninstall/engine.py +2 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/update.py +135 -71
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/view.py +1 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/compilation/agents_compiler.py +194 -45
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/compilation/claude_formatter.py +34 -19
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/compilation/constitution.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/compilation/constitution_block.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/compilation/context_optimizer.py +28 -11
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/compilation/distributed_compiler.py +72 -27
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/compilation/gemini_formatter.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/compilation/injector.py +1 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/compilation/link_resolver.py +18 -2
- apm_cli-0.18.0/src/apm_cli/compilation/managed_section.py +96 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/compilation/template_builder.py +17 -7
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/config.py +222 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/core/auth.py +10 -3
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/core/azure_cli.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/core/build_orchestrator.py +129 -10
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/core/command_logger.py +5 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/core/conflict_detector.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/core/docker_args.py +0 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/core/experimental.py +13 -0
- apm_cli-0.18.0/src/apm_cli/core/install_audit.py +176 -0
- apm_cli-0.18.0/src/apm_cli/core/plugin_manifest.py +467 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/core/safe_installer.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/core/scope.py +109 -9
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/core/script_runner.py +0 -3
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/core/target_detection.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/core/token_manager.py +1 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/aggregator.py +0 -3
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/apm_resolver.py +112 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/artifactory_entry.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/dependency_graph.py +2 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/download_strategies.py +0 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/git_remote_ops.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/git_semver_resolver.py +9 -5
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/github_downloader.py +4 -4
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/lockfile.py +17 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/package_validator.py +1 -2
- apm_cli-0.18.0/src/apm_cli/deps/path_anchoring.py +151 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/plugin_parser.py +181 -4
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/registry_proxy.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/transport_selection.py +2 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/verifier.py +0 -3
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/drift.py +5 -3
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/factory.py +2 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/context.py +23 -4
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/drift.py +29 -13
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/errors.py +1 -1
- apm_cli-0.18.0/src/apm_cli/install/lsp/__init__.py +5 -0
- apm_cli-0.18.0/src/apm_cli/install/lsp/integration.py +148 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/mcp/args.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/mcp/command.py +6 -4
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/mcp/conflicts.py +7 -6
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/mcp/entry.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/mcp/registry.py +21 -7
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/mcp/warnings.py +0 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/mcp/writer.py +1 -1
- apm_cli-0.18.0/src/apm_cli/install/phases/_skip_logic.py +57 -0
- apm_cli-0.18.0/src/apm_cli/install/phases/audit.py +135 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/phases/integrate.py +38 -6
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/phases/lockfile.py +7 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/phases/resolve.py +175 -75
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/pipeline.py +126 -46
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/presentation/dry_run.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/request.py +7 -1
- apm_cli-0.18.0/src/apm_cli/install/root_redirect.py +102 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/service.py +2 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/services.py +69 -21
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/sources.py +22 -9
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/summary.py +4 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/template.py +9 -9
- apm_cli-0.18.0/src/apm_cli/install/validation.py +785 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/__init__.py +2 -0
- apm_cli-0.18.0/src/apm_cli/integration/_shared.py +71 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/agent_integrator.py +4 -7
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/base_integrator.py +26 -3
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/cleanup.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/command_integrator.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/dispatch.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/hook_integrator.py +80 -6
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/instruction_integrator.py +158 -13
- apm_cli-0.18.0/src/apm_cli/integration/lsp_integrator.py +508 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/mcp_integrator.py +227 -239
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/mcp_integrator_install.py +323 -215
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/prompt_integrator.py +2 -5
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/skill_integrator.py +353 -39
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/skill_transformer.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/targets.py +33 -4
- apm_cli-0.18.0/src/apm_cli/marketplace/audit.py +337 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/builder.py +3 -7
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/client.py +96 -14
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/migration.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/pr_integration.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/publisher.py +160 -102
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/ref_resolver.py +1 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/registry.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/resolver.py +59 -10
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/semver.py +17 -24
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/shadow_detector.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/tag_pattern.py +80 -3
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/validator.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/version_pins.py +0 -1
- apm_cli-0.18.0/src/apm_cli/marketplace/version_resolver.py +114 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/yml_editor.py +0 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/yml_schema.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/models/__init__.py +27 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/models/apm_package.py +33 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/models/dependency/__init__.py +2 -0
- apm_cli-0.18.0/src/apm_cli/models/dependency/lsp.py +229 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/models/dependency/mcp.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/models/dependency/reference.py +134 -5
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/models/dependency/types.py +0 -1
- apm_cli-0.18.0/src/apm_cli/models/format_detection.py +408 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/models/plugin.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/models/results.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/models/validation.py +47 -67
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/output/formatters.py +0 -5
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/output/models.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/output/script_formatters.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/policy/ci_checks.py +14 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/policy/discovery.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/policy/inheritance.py +73 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/policy/install_preflight.py +0 -3
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/policy/matcher.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/policy/models.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/policy/outcome_routing.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/policy/parser.py +99 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/policy/policy_checks.py +29 -41
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/policy/project_config.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/policy/schema.py +72 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/primitives/discovery.py +0 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/primitives/models.py +2 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/primitives/parser.py +39 -4
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/registry/client.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/registry/integration.py +1 -3
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/registry/operations.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/runtime/base.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/runtime/codex_runtime.py +1 -3
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/runtime/copilot_runtime.py +1 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/runtime/factory.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/runtime/llm_runtime.py +1 -3
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/runtime/manager.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/security/audit_report.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/security/content_scanner.py +1 -2
- apm_cli-0.18.0/src/apm_cli/security/external/__init__.py +27 -0
- apm_cli-0.18.0/src/apm_cli/security/external/base.py +76 -0
- apm_cli-0.18.0/src/apm_cli/security/external/gate.py +35 -0
- apm_cli-0.18.0/src/apm_cli/security/external/generic_sarif.py +85 -0
- apm_cli-0.18.0/src/apm_cli/security/external/options.py +179 -0
- apm_cli-0.18.0/src/apm_cli/security/external/registry.py +41 -0
- apm_cli-0.18.0/src/apm_cli/security/external/runner.py +100 -0
- apm_cli-0.18.0/src/apm_cli/security/external/sarif_ingest.py +149 -0
- apm_cli-0.18.0/src/apm_cli/security/external/skillspector.py +175 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/security/file_scanner.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/security/gate.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/console.py +1 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/content_hash.py +0 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/diagnostics.py +2 -3
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/exclude.py +10 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/helpers.py +0 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/paths.py +23 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/version_checker.py +83 -8
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/yaml_io.py +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/workflow/runner.py +0 -2
- {apm_cli-0.16.1 → apm_cli-0.18.0/src/apm_cli.egg-info}/PKG-INFO +1 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli.egg-info/SOURCES.txt +28 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/tests/test_apm_package_models.py +156 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/tests/test_apm_resolver.py +192 -1
- {apm_cli-0.16.1 → apm_cli-0.18.0}/tests/test_distributed_compilation.py +48 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/tests/test_lockfile.py +55 -0
- apm_cli-0.16.1/src/apm_cli/commands/compile/cli.py +0 -919
- apm_cli-0.16.1/src/apm_cli/install/validation.py +0 -701
- {apm_cli-0.16.1 → apm_cli-0.18.0}/AUTHORS +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/LICENSE +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/NOTICE +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/README.md +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/setup.cfg +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/adapters/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/adapters/client/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/adapters/client/_mcp_runtime_args.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/adapters/client/claude.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/adapters/client/codex.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/adapters/client/cursor.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/adapters/client/gemini.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/adapters/client/opencode.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/adapters/client/windsurf.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/adapters/package_manager/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/adapters/package_manager/base.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/adapters/package_manager/default_manager.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/bundle/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/bundle/local_bundle.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/cache/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/cache/git_cache.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/cache/http_cache.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/cache/integrity.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/cache/locking.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/cache/paths.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/cache/url_normalize.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/cache.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/compile/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/compile/watcher.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/deps/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/deps/why.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/doctor.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/experimental.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/check.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/doctor.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/init.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/migrate.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/outdated.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/plugin/add.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/plugin/set.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/publish.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/marketplace/validate.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/plugin/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/plugin/init.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/run.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/runtime.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/targets.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/commands/uninstall/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/compilation/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/compilation/build_id.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/compilation/constants.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/compilation/output_writer.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/constants.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/core/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/core/apm_yml.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/core/errors.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/core/null_logger.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/core/operations.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/_shared.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/artifactory_orchestrator.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/bare_cache.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/clone_engine.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/git_auth_env.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/git_reference_resolver.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/github_downloader_validation.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/host_backends.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/installed_package.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/outdated_row.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/registry/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/registry/auth.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/registry/client.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/registry/config_loader.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/registry/extractor.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/registry/feature_gate.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/registry/outdated.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/registry/resolver.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/registry/semver.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/shared_clone_cache.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/tiered_ref_resolver.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/deps/why_walker.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/artifactory_resolver.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/cache_pin.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/gitlab_resolver.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/heals/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/heals/base.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/heals/branch_ref_drift.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/heals/buggy_lockfile_recovery.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/helpers/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/helpers/security_scan.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/insecure_policy.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/local_bundle_handler.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/mcp/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/package_resolution.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/package_selection.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/phases/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/phases/_redownload.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/phases/cleanup.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/phases/download.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/phases/finalize.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/phases/heal.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/phases/local_content.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/phases/policy_gate.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/phases/policy_target_check.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/phases/post_deps_local.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/phases/targets.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/plan.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/presentation/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/registry_wiring.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/install/skill_path_migration.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/copilot_app_db.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/copilot_app_project.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/copilot_app_workflow_integrator.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/copilot_app_ws.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/copilot_cowork_paths.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/coverage.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/opencode_frontmatter.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/integration/utils.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/_git_utils.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/_io.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/_shared.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/diagnostics.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/drift_check.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/errors.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/git_stderr.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/init_template.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/models.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/output_mappers.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/output_profiles.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/marketplace/version_check.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/output/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/policy/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/policy/_constraint_pinning.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/policy/_help_text.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/policy/_shared.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/primitives/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/registry/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/runtime/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/runtime/utils.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/security/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/update_policy.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/atomic_io.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/file_ops.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/git_env.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/git_sparse.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/github_host.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/guards.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/install_tui.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/normalization.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/path_security.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/patterns.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/perf_stats.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/reflink.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/short_sha.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/utils/subprocess_env.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/version.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/workflow/__init__.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/workflow/discovery.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli/workflow/parser.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli.egg-info/dependency_links.txt +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli.egg-info/entry_points.txt +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli.egg-info/requires.txt +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/src/apm_cli.egg-info/top_level.txt +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/tests/test_codex_docker_args_fix.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/tests/test_codex_empty_string_and_defaults.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/tests/test_collision_integration.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/tests/test_console.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/tests/test_empty_string_and_defaults.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/tests/test_enhanced_discovery.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/tests/test_github_downloader.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/tests/test_github_downloader_token_precedence.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/tests/test_runnable_prompts.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/tests/test_runtime_manager_token_precedence.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/tests/test_token_manager.py +0 -0
- {apm_cli-0.16.1 → apm_cli-0.18.0}/tests/test_virtual_package_multi_install.py +0 -0
|
@@ -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.18.0"
|
|
8
8
|
description = "MCP configuration tool"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -88,21 +88,22 @@ ignore = [
|
|
|
88
88
|
"S602", # subprocess-popen-with-shell -- intentional in CLI wrapping git/pip
|
|
89
89
|
# --- Deferred rules: enable in dedicated future PRs ---
|
|
90
90
|
"SIM102", # collapsible-if -- 28 violations, auto-fixable style improvement
|
|
91
|
-
"RUF003", # ambiguous-unicode-character-comment -- 14 violations, review against ASCII convention
|
|
92
|
-
"RUF002", # ambiguous-unicode-character-docstring -- 8 violations, same as above
|
|
93
91
|
]
|
|
94
92
|
|
|
95
93
|
[tool.ruff.lint.pylint]
|
|
96
94
|
# High initial thresholds set just above current codebase maximums.
|
|
97
95
|
# Prevents new code from exceeding the worst existing violations.
|
|
98
96
|
# Tighten these over time via dedicated refactoring PRs.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
max-
|
|
102
|
-
max-
|
|
97
|
+
# Stage 1 thresholds (PR #1464, issue #1077).
|
|
98
|
+
# Roadmap: Stage 2 targets max-complexity<=20, max-branches<=25 (McCabe standard).
|
|
99
|
+
max-statements = 200 # Stage 1 (was 275)
|
|
100
|
+
max-args = 15 # Stage 1 (was 18)
|
|
101
|
+
max-branches = 60 # Stage 1 (was 115)
|
|
102
|
+
max-returns = 12 # Stage 1 (was 18)
|
|
103
103
|
|
|
104
104
|
[tool.ruff.lint.mccabe]
|
|
105
|
-
|
|
105
|
+
# Stage 1 (was 100). Stage 2 target: <=20 (McCabe industry standard).
|
|
106
|
+
max-complexity = 50
|
|
106
107
|
|
|
107
108
|
[tool.ruff.lint.per-file-ignores]
|
|
108
109
|
# Subprocess calls are intentional in a CLI tool
|
|
@@ -120,7 +121,6 @@ max-complexity = 100 # current max: 97 (mcp_integrator.py::install)
|
|
|
120
121
|
"src/apm_cli/commands/init.py" = ["F821", "S603", "S607"]
|
|
121
122
|
"src/apm_cli/install/pipeline.py" = ["F821", "S603", "S607"]
|
|
122
123
|
"src/apm_cli/integration/skill_integrator.py" = ["F821", "S603", "S607"]
|
|
123
|
-
|
|
124
124
|
[tool.ruff.format]
|
|
125
125
|
quote-style = "double"
|
|
126
126
|
indent-style = "space"
|
|
@@ -150,6 +150,21 @@ class MCPClientAdapter(ABC):
|
|
|
150
150
|
self._last_env_placeholder_keys: set[str] = set()
|
|
151
151
|
self._last_legacy_angle_vars: set[str] = set()
|
|
152
152
|
|
|
153
|
+
def _format_runtime_env_placeholder(self, name: str) -> str:
|
|
154
|
+
"""Return the target runtime's env-var placeholder syntax for *name*."""
|
|
155
|
+
return "${" + name + "}"
|
|
156
|
+
|
|
157
|
+
def _translate_env_placeholder_for_runtime(self, value):
|
|
158
|
+
"""Translate env-var placeholders to this adapter's runtime syntax."""
|
|
159
|
+
if not isinstance(value, str):
|
|
160
|
+
return value
|
|
161
|
+
|
|
162
|
+
def _to_runtime(match):
|
|
163
|
+
var_name = match.group(1) or match.group(2)
|
|
164
|
+
return self._format_runtime_env_placeholder(var_name)
|
|
165
|
+
|
|
166
|
+
return _ENV_PLACEHOLDER_RE.sub(_to_runtime, value)
|
|
167
|
+
|
|
153
168
|
@property
|
|
154
169
|
def project_root(self) -> Path:
|
|
155
170
|
"""Return the explicit project root or the current working directory."""
|
|
@@ -390,9 +405,7 @@ class MCPClientAdapter(ABC):
|
|
|
390
405
|
continue
|
|
391
406
|
if _has_env_placeholder(raw_value):
|
|
392
407
|
self._last_legacy_angle_vars.update(_extract_legacy_angle_vars(raw_value))
|
|
393
|
-
translated[name] =
|
|
394
|
-
# Record every ${VAR} in the translated value (handles
|
|
395
|
-
# both ${env:VAR} -> ${VAR} and bare ${VAR} cases).
|
|
408
|
+
translated[name] = self._translate_env_placeholder_for_runtime(raw_value)
|
|
396
409
|
placeholder_keys.extend(
|
|
397
410
|
m.group(1) for m in _ENV_VAR_RE.finditer(translated[name])
|
|
398
411
|
)
|
|
@@ -403,7 +416,7 @@ class MCPClientAdapter(ABC):
|
|
|
403
416
|
else:
|
|
404
417
|
# Literal value present in apm.yml -- replace with a
|
|
405
418
|
# runtime placeholder so the secret never touches disk.
|
|
406
|
-
translated[name] =
|
|
419
|
+
translated[name] = self._format_runtime_env_placeholder(name)
|
|
407
420
|
placeholder_keys.append(name)
|
|
408
421
|
self._last_env_placeholder_keys = set(placeholder_keys)
|
|
409
422
|
return translated
|
|
@@ -421,7 +434,7 @@ class MCPClientAdapter(ABC):
|
|
|
421
434
|
if name in self._DEFAULT_GITHUB_ENV:
|
|
422
435
|
resolved[name] = self._DEFAULT_GITHUB_ENV[name]
|
|
423
436
|
else:
|
|
424
|
-
resolved[name] =
|
|
437
|
+
resolved[name] = self._format_runtime_env_placeholder(name)
|
|
425
438
|
placeholder_keys.append(name)
|
|
426
439
|
self._last_env_placeholder_keys = set(placeholder_keys)
|
|
427
440
|
return resolved
|
|
@@ -510,7 +523,7 @@ class MCPClientAdapter(ABC):
|
|
|
510
523
|
self._last_env_placeholder_keys.update(legacy_keys)
|
|
511
524
|
for match in _ENV_VAR_RE.finditer(value):
|
|
512
525
|
self._last_env_placeholder_keys.add(match.group(1))
|
|
513
|
-
return
|
|
526
|
+
return self._translate_env_placeholder_for_runtime(value)
|
|
514
527
|
|
|
515
528
|
from rich.prompt import Prompt
|
|
516
529
|
|
|
@@ -560,7 +573,7 @@ class MCPClientAdapter(ABC):
|
|
|
560
573
|
|
|
561
574
|
if self._supports_runtime_env_substitution:
|
|
562
575
|
self._last_legacy_angle_vars.update(_extract_legacy_angle_vars(processed))
|
|
563
|
-
processed =
|
|
576
|
+
processed = self._translate_env_placeholder_for_runtime(processed)
|
|
564
577
|
else:
|
|
565
578
|
# Resolve only the legacy ``<VAR>`` form; newer syntaxes are
|
|
566
579
|
# preserved verbatim for backward compatibility.
|
|
@@ -26,7 +26,9 @@ from .base import (
|
|
|
26
26
|
_extract_legacy_angle_vars,
|
|
27
27
|
_has_env_placeholder,
|
|
28
28
|
_stringify_env_literal,
|
|
29
|
-
|
|
29
|
+
)
|
|
30
|
+
from .base import (
|
|
31
|
+
_translate_env_placeholder as _translate_env_placeholder,
|
|
30
32
|
)
|
|
31
33
|
|
|
32
34
|
|
|
@@ -117,12 +119,12 @@ class CopilotClientAdapter(MCPClientAdapter):
|
|
|
117
119
|
"""
|
|
118
120
|
current_config = self.get_current_config()
|
|
119
121
|
|
|
120
|
-
# Ensure
|
|
121
|
-
if
|
|
122
|
-
current_config[
|
|
122
|
+
# Ensure servers section exists and is a dict (guard against malformed config).
|
|
123
|
+
if not isinstance(current_config.get(self.mcp_servers_key), dict):
|
|
124
|
+
current_config[self.mcp_servers_key] = {}
|
|
123
125
|
|
|
124
126
|
# Apply updates
|
|
125
|
-
current_config[
|
|
127
|
+
current_config[self.mcp_servers_key].update(config_updates)
|
|
126
128
|
|
|
127
129
|
# Write back to file
|
|
128
130
|
config_path = Path(self.get_config_path())
|
|
@@ -259,7 +261,7 @@ class CopilotClientAdapter(MCPClientAdapter):
|
|
|
259
261
|
current = self.get_current_config()
|
|
260
262
|
except Exception:
|
|
261
263
|
return set(), False
|
|
262
|
-
servers = current.get(
|
|
264
|
+
servers = current.get(self.mcp_servers_key) or {}
|
|
263
265
|
# Match the same key resolution rule used below.
|
|
264
266
|
if server_name:
|
|
265
267
|
key = server_name
|
|
@@ -678,9 +680,9 @@ class CopilotClientAdapter(MCPClientAdapter):
|
|
|
678
680
|
# ({NAME: value-or-placeholder}); registry-sourced deps pass a list
|
|
679
681
|
# of {name, description, required} dicts. Translate-mode handling
|
|
680
682
|
# for the dict shape: each value is either already a placeholder
|
|
681
|
-
# (translate it to the
|
|
682
|
-
# the key as a placeholder reference and emit
|
|
683
|
-
# value never lands on disk). See issue #1152.
|
|
683
|
+
# (translate it to the adapter's runtime form) or a literal
|
|
684
|
+
# (record the key as a placeholder reference and emit a runtime
|
|
685
|
+
# placeholder so the value never lands on disk). See issue #1152.
|
|
684
686
|
if isinstance(env_vars, dict) and self._supports_runtime_env_substitution:
|
|
685
687
|
translated = {}
|
|
686
688
|
placeholder_keys = []
|
|
@@ -694,9 +696,7 @@ class CopilotClientAdapter(MCPClientAdapter):
|
|
|
694
696
|
continue
|
|
695
697
|
if _has_env_placeholder(raw_value):
|
|
696
698
|
self._last_legacy_angle_vars.update(_extract_legacy_angle_vars(raw_value))
|
|
697
|
-
translated[name] =
|
|
698
|
-
# Record every ${VAR} in the translated value (handles
|
|
699
|
-
# both ${env:VAR} -> ${VAR} and bare ${VAR} cases).
|
|
699
|
+
translated[name] = self._translate_env_placeholder_for_runtime(raw_value)
|
|
700
700
|
for match in _ENV_VAR_RE.finditer(translated[name]):
|
|
701
701
|
placeholder_keys.append(match.group(1))
|
|
702
702
|
elif name in default_github_env and raw_value == default_github_env[name]:
|
|
@@ -704,7 +704,7 @@ class CopilotClientAdapter(MCPClientAdapter):
|
|
|
704
704
|
else:
|
|
705
705
|
# Literal value present in apm.yml -- replace with a
|
|
706
706
|
# runtime placeholder so the secret never touches disk.
|
|
707
|
-
translated[name] =
|
|
707
|
+
translated[name] = self._format_runtime_env_placeholder(name)
|
|
708
708
|
placeholder_keys.append(name)
|
|
709
709
|
self._last_env_placeholder_keys = set(placeholder_keys)
|
|
710
710
|
return translated
|
|
@@ -722,10 +722,9 @@ class CopilotClientAdapter(MCPClientAdapter):
|
|
|
722
722
|
# Non-secret literal default -- preserve as-is.
|
|
723
723
|
resolved[name] = default_github_env[name]
|
|
724
724
|
else:
|
|
725
|
-
# Emit a runtime-substitution placeholder;
|
|
726
|
-
#
|
|
727
|
-
|
|
728
|
-
resolved[name] = "${" + name + "}"
|
|
725
|
+
# Emit a runtime-substitution placeholder; APM never reads
|
|
726
|
+
# or stores the value.
|
|
727
|
+
resolved[name] = self._format_runtime_env_placeholder(name)
|
|
729
728
|
placeholder_keys.append(name)
|
|
730
729
|
# Record for the post-install summary line and the
|
|
731
730
|
# security-improvement notice.
|
|
@@ -783,7 +782,7 @@ class CopilotClientAdapter(MCPClientAdapter):
|
|
|
783
782
|
# them (the env-block path tracks via _resolve_environment_variables).
|
|
784
783
|
for match in _ENV_VAR_RE.finditer(value):
|
|
785
784
|
self._last_env_placeholder_keys.add(match.group(1))
|
|
786
|
-
return
|
|
785
|
+
return self._translate_env_placeholder_for_runtime(value)
|
|
787
786
|
|
|
788
787
|
import sys
|
|
789
788
|
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""JetBrains Copilot implementation of the MCP client adapter.
|
|
2
|
+
|
|
3
|
+
GitHub Copilot for JetBrains IDEs stores MCP server configuration under
|
|
4
|
+
a user-scope directory whose location is OS-dependent:
|
|
5
|
+
|
|
6
|
+
Windows : %LOCALAPPDATA%\\github-copilot\\intellij\\mcp.json
|
|
7
|
+
macOS : ~/Library/Application Support/github-copilot/intellij/mcp.json
|
|
8
|
+
Linux : $XDG_DATA_HOME/github-copilot/intellij/mcp.json
|
|
9
|
+
(defaults to ~/.local/share/github-copilot/intellij/mcp.json)
|
|
10
|
+
|
|
11
|
+
The configuration file uses a top-level ``"servers"`` key (unlike most
|
|
12
|
+
other Copilot-family adapters which use ``"mcpServers"``).
|
|
13
|
+
|
|
14
|
+
Ref: https://github.com/orgs/community/discussions/139762
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import os
|
|
18
|
+
import sys
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
from ...utils.path_security import PathTraversalError, ensure_path_within
|
|
22
|
+
from .copilot import CopilotClientAdapter
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _intellij_config_dir() -> Path:
|
|
26
|
+
"""Return the OS-specific JetBrains Copilot config directory.
|
|
27
|
+
|
|
28
|
+
Does not guarantee the directory exists; callers that need to write
|
|
29
|
+
to it should call ``mkdir(parents=True, exist_ok=True)`` first.
|
|
30
|
+
|
|
31
|
+
Raises
|
|
32
|
+
------
|
|
33
|
+
PathTraversalError
|
|
34
|
+
If the environment variable the location is derived from
|
|
35
|
+
(``LOCALAPPDATA`` on Windows, ``XDG_DATA_HOME`` on Linux) is unset
|
|
36
|
+
or not absolute. Without this guard an empty ``LOCALAPPDATA``
|
|
37
|
+
would yield ``Path("")`` -- a *relative* path -- causing APM to
|
|
38
|
+
silently read/write ``./github-copilot/intellij/mcp.json`` in the
|
|
39
|
+
current working directory and to falsely auto-detect the runtime.
|
|
40
|
+
"""
|
|
41
|
+
if sys.platform == "win32":
|
|
42
|
+
local_app_data = os.environ.get("LOCALAPPDATA", "")
|
|
43
|
+
if not local_app_data or not os.path.isabs(local_app_data):
|
|
44
|
+
raise PathTraversalError(
|
|
45
|
+
"LOCALAPPDATA is unset or not an absolute path; cannot locate the "
|
|
46
|
+
"JetBrains Copilot configuration directory."
|
|
47
|
+
)
|
|
48
|
+
return Path(local_app_data) / "github-copilot" / "intellij"
|
|
49
|
+
|
|
50
|
+
if sys.platform == "darwin":
|
|
51
|
+
return Path.home() / "Library" / "Application Support" / "github-copilot" / "intellij"
|
|
52
|
+
|
|
53
|
+
# Linux: honour $XDG_DATA_HOME, fall back to ~/.local/share
|
|
54
|
+
xdg_data = os.environ.get("XDG_DATA_HOME", "")
|
|
55
|
+
if xdg_data:
|
|
56
|
+
if not os.path.isabs(xdg_data):
|
|
57
|
+
raise PathTraversalError(
|
|
58
|
+
"XDG_DATA_HOME is set to a non-absolute path; cannot locate the "
|
|
59
|
+
"JetBrains Copilot configuration directory."
|
|
60
|
+
)
|
|
61
|
+
return Path(xdg_data) / "github-copilot" / "intellij"
|
|
62
|
+
return Path.home() / ".local" / "share" / "github-copilot" / "intellij"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class IntelliJClientAdapter(CopilotClientAdapter):
|
|
66
|
+
"""MCP client adapter for GitHub Copilot inside JetBrains IDEs.
|
|
67
|
+
|
|
68
|
+
JetBrains Copilot stores server definitions in a user-scope JSON file
|
|
69
|
+
with a ``"servers"`` top-level key (not ``"mcpServers"``). This adapter
|
|
70
|
+
inherits registry-resolution and config read/write from
|
|
71
|
+
:class:`CopilotClientAdapter` and overrides the config path,
|
|
72
|
+
``mcp_servers_key``, and runtime env-var placeholder syntax so the parent
|
|
73
|
+
methods operate on the correct schema.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
supports_user_scope: bool = True
|
|
77
|
+
_client_label: str = "JetBrains Copilot"
|
|
78
|
+
target_name: str = "intellij"
|
|
79
|
+
mcp_servers_key: str = "servers"
|
|
80
|
+
|
|
81
|
+
# JetBrains Copilot resolves ${env:VAR} placeholders in mcp.json at
|
|
82
|
+
# server-start, so APM must not bake matching host secrets to disk.
|
|
83
|
+
_supports_runtime_env_substitution: bool = True
|
|
84
|
+
|
|
85
|
+
def _format_runtime_env_placeholder(self, name: str) -> str:
|
|
86
|
+
"""Return JetBrains Copilot's native env-var placeholder syntax."""
|
|
87
|
+
return "${env:" + name + "}"
|
|
88
|
+
|
|
89
|
+
# ------------------------------------------------------------------ #
|
|
90
|
+
# Config path
|
|
91
|
+
# ------------------------------------------------------------------ #
|
|
92
|
+
|
|
93
|
+
def get_config_path(self) -> str:
|
|
94
|
+
"""Return the OS-specific path to ``mcp.json`` for JetBrains Copilot.
|
|
95
|
+
|
|
96
|
+
The config directory is derived from an environment variable
|
|
97
|
+
(``LOCALAPPDATA`` / ``XDG_DATA_HOME``). Validate it resolves
|
|
98
|
+
inside the user's home directory before any read/write so a
|
|
99
|
+
tampered or unexpected environment cannot redirect APM's writes
|
|
100
|
+
outside the user-scope tree (supply-chain hardening).
|
|
101
|
+
"""
|
|
102
|
+
config_dir = _intellij_config_dir()
|
|
103
|
+
ensure_path_within(config_dir, Path.home())
|
|
104
|
+
return str(config_dir / "mcp.json")
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
"""Bundle packer -- creates self-contained APM bundles from the resolved dependency tree."""
|
|
2
2
|
|
|
3
|
-
import os # noqa: F401
|
|
4
3
|
import shutil
|
|
5
4
|
import tarfile
|
|
6
5
|
from dataclasses import dataclass, field
|
|
7
6
|
from pathlib import Path
|
|
8
|
-
from typing import Dict, List, Optional, Union # noqa: F401, UP035
|
|
9
7
|
|
|
10
8
|
from ..core.target_detection import detect_target
|
|
11
9
|
from ..deps.lockfile import LockFile, get_lockfile_path, migrate_lockfile_if_needed
|
|
@@ -9,12 +9,10 @@ under ``pack.bundle_files`` (issue #1098).
|
|
|
9
9
|
|
|
10
10
|
import hashlib
|
|
11
11
|
import json
|
|
12
|
-
import os # noqa: F401
|
|
13
12
|
import re
|
|
14
13
|
import shutil
|
|
15
14
|
import tarfile
|
|
16
15
|
from pathlib import Path, PurePosixPath
|
|
17
|
-
from typing import Dict, List, Optional, Set, Tuple # noqa: F401, UP035
|
|
18
16
|
|
|
19
17
|
import yaml
|
|
20
18
|
|
|
@@ -25,7 +23,7 @@ from ..deps.lockfile import (
|
|
|
25
23
|
migrate_lockfile_if_needed,
|
|
26
24
|
)
|
|
27
25
|
from ..models.apm_package import APMPackage, DependencyReference
|
|
28
|
-
from ..utils.console import
|
|
26
|
+
from ..utils.console import _rich_warning
|
|
29
27
|
from ..utils.path_security import PathTraversalError, ensure_path_within, safe_rmtree
|
|
30
28
|
from .packer import PackResult
|
|
31
29
|
|
|
@@ -270,17 +268,9 @@ def _collect_hooks_from_root(package_root: Path) -> dict:
|
|
|
270
268
|
|
|
271
269
|
def _collect_mcp(package_root: Path) -> dict:
|
|
272
270
|
"""Return ``mcpServers`` dict from ``.mcp.json``."""
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
try:
|
|
277
|
-
data = json.loads(mcp_file.read_text(encoding="utf-8"))
|
|
278
|
-
if isinstance(data, dict):
|
|
279
|
-
servers = data.get("mcpServers", {})
|
|
280
|
-
return dict(servers) if isinstance(servers, dict) else {}
|
|
281
|
-
except (json.JSONDecodeError, OSError):
|
|
282
|
-
pass
|
|
283
|
-
return {}
|
|
271
|
+
from ..core.plugin_manifest import collect_mcp_servers
|
|
272
|
+
|
|
273
|
+
return collect_mcp_servers(package_root)
|
|
284
274
|
|
|
285
275
|
|
|
286
276
|
# ---------------------------------------------------------------------------
|
|
@@ -339,42 +329,15 @@ def _find_or_synthesize_plugin_json(
|
|
|
339
329
|
suppress_missing_warning: bool = False,
|
|
340
330
|
logger=None,
|
|
341
331
|
) -> dict:
|
|
342
|
-
"""Locate an existing ``plugin.json`` or synthesise one from ``apm.yml``.
|
|
343
|
-
|
|
344
|
-
``suppress_missing_warning`` silences the "no plugin.json on disk"
|
|
345
|
-
message when the caller knows synthesis is the expected path -- for
|
|
346
|
-
example a marketplace-publishing run that happens to have
|
|
347
|
-
``dependencies:`` for local dev. Genuine parse errors on an existing
|
|
348
|
-
file are always surfaced.
|
|
349
|
-
"""
|
|
350
|
-
from ..deps.plugin_parser import synthesize_plugin_json_from_apm_yml
|
|
351
|
-
from ..utils.helpers import find_plugin_json
|
|
352
|
-
|
|
353
|
-
plugin_json_path = find_plugin_json(project_root)
|
|
354
|
-
if plugin_json_path is not None:
|
|
355
|
-
try:
|
|
356
|
-
return json.loads(plugin_json_path.read_text(encoding="utf-8"))
|
|
357
|
-
except (json.JSONDecodeError, OSError) as exc:
|
|
358
|
-
_warn_msg = (
|
|
359
|
-
f"Found plugin.json at {plugin_json_path} but could not parse it: {exc}. "
|
|
360
|
-
"Falling back to synthesis from apm.yml."
|
|
361
|
-
)
|
|
362
|
-
if logger:
|
|
363
|
-
logger.warning(_warn_msg)
|
|
364
|
-
else:
|
|
365
|
-
_rich_warning(_warn_msg)
|
|
332
|
+
"""Locate an existing ``plugin.json`` or synthesise one from ``apm.yml``."""
|
|
333
|
+
from ..core.plugin_manifest import find_or_synthesize_plugin_json
|
|
366
334
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
if logger:
|
|
374
|
-
logger.info(_info_msg)
|
|
375
|
-
else:
|
|
376
|
-
_rich_info(_info_msg)
|
|
377
|
-
return synthesize_plugin_json_from_apm_yml(apm_yml_path)
|
|
335
|
+
return find_or_synthesize_plugin_json(
|
|
336
|
+
project_root,
|
|
337
|
+
apm_yml_path,
|
|
338
|
+
suppress_missing_warning=suppress_missing_warning,
|
|
339
|
+
logger=logger,
|
|
340
|
+
)
|
|
378
341
|
|
|
379
342
|
|
|
380
343
|
def _has_marketplace_block(apm_yml_path: Path) -> bool:
|
|
@@ -6,7 +6,6 @@ import tarfile
|
|
|
6
6
|
import tempfile
|
|
7
7
|
from dataclasses import dataclass, field
|
|
8
8
|
from pathlib import Path, PureWindowsPath
|
|
9
|
-
from typing import Dict, List # noqa: F401, UP035
|
|
10
9
|
|
|
11
10
|
from ..deps.lockfile import LEGACY_LOCKFILE_NAME, LOCKFILE_NAME, LockFile
|
|
12
11
|
from ..utils.path_security import PathTraversalError, validate_path_segments
|
|
@@ -24,9 +24,11 @@ from apm_cli.commands.config import config
|
|
|
24
24
|
from apm_cli.commands.deps import deps
|
|
25
25
|
from apm_cli.commands.doctor import doctor
|
|
26
26
|
from apm_cli.commands.experimental import experimental
|
|
27
|
+
from apm_cli.commands.find import find as find_cmd
|
|
27
28
|
from apm_cli.commands.init import init
|
|
28
29
|
from apm_cli.commands.install import install
|
|
29
30
|
from apm_cli.commands.list_cmd import list as list_cmd
|
|
31
|
+
from apm_cli.commands.lock import lock
|
|
30
32
|
from apm_cli.commands.marketplace import marketplace
|
|
31
33
|
from apm_cli.commands.marketplace import search as marketplace_search
|
|
32
34
|
from apm_cli.commands.mcp import mcp
|
|
@@ -50,6 +52,7 @@ _CLI_EPILOG = (
|
|
|
50
52
|
" apm init Scaffold a new project\n"
|
|
51
53
|
" apm install Install dependencies from apm.yml\n"
|
|
52
54
|
" apm install --frozen Reproduce lockfile exactly (CI-safe)\n"
|
|
55
|
+
" apm lock Resolve deps and write lockfile only\n"
|
|
53
56
|
" apm outdated See what's drifted from upstream\n"
|
|
54
57
|
" apm update Refresh refs and rewrite the lockfile\n"
|
|
55
58
|
" apm audit --ci Validate lockfile integrity for CI gates\n"
|
|
@@ -108,6 +111,7 @@ cli.add_command(unpack_cmd, name="unpack")
|
|
|
108
111
|
cli.add_command(publish_cmd, name="publish")
|
|
109
112
|
cli.add_command(init)
|
|
110
113
|
cli.add_command(install)
|
|
114
|
+
cli.add_command(lock)
|
|
111
115
|
cli.add_command(uninstall)
|
|
112
116
|
cli.add_command(prune)
|
|
113
117
|
cli.add_command(update)
|
|
@@ -126,6 +130,7 @@ cli.add_command(policy)
|
|
|
126
130
|
cli.add_command(outdated_cmd, name="outdated")
|
|
127
131
|
cli.add_command(doctor)
|
|
128
132
|
cli.add_command(marketplace)
|
|
133
|
+
cli.add_command(find_cmd)
|
|
129
134
|
cli.add_command(marketplace_search, name="search")
|
|
130
135
|
|
|
131
136
|
|
|
@@ -6,7 +6,6 @@ field. Keeps write-back logic isolated and unit-testable.
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import List, Optional # noqa: F401, UP035
|
|
10
9
|
|
|
11
10
|
from ..models.dependency.reference import DependencyReference
|
|
12
11
|
from ..utils.yaml_io import dump_yaml, load_yaml
|
|
@@ -14,14 +14,15 @@ from colorama import Fore, Style
|
|
|
14
14
|
from colorama import init as colorama_init
|
|
15
15
|
|
|
16
16
|
from ..constants import (
|
|
17
|
-
APM_LOCK_FILENAME, # noqa: F401
|
|
18
17
|
APM_MODULES_DIR,
|
|
19
18
|
APM_MODULES_GITIGNORE_PATTERN,
|
|
20
19
|
APM_YML_FILENAME,
|
|
21
20
|
GITIGNORE_FILENAME,
|
|
22
21
|
)
|
|
23
22
|
from ..update_policy import get_update_hint_message, is_self_update_enabled
|
|
24
|
-
from ..utils.atomic_io import
|
|
23
|
+
from ..utils.atomic_io import (
|
|
24
|
+
atomic_write_text as _atomic_write, # noqa: F401 -- re-exported; tests import from apm_cli.commands._helpers
|
|
25
|
+
)
|
|
25
26
|
from ..utils.console import _rich_echo, _rich_info, _rich_warning
|
|
26
27
|
from ..utils.path_security import PathTraversalError, validate_path_segments
|
|
27
28
|
from ..utils.version_checker import check_for_updates
|
|
@@ -331,6 +332,74 @@ def _check_orphaned_packages():
|
|
|
331
332
|
return []
|
|
332
333
|
|
|
333
334
|
|
|
335
|
+
# ------------------------------------------------------------------
|
|
336
|
+
# Dependency-update helpers (shared by `apm update` and `apm deps update`)
|
|
337
|
+
# ------------------------------------------------------------------
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
class UnknownPackageError(Exception):
|
|
341
|
+
"""A requested package token matched no declared dependency.
|
|
342
|
+
|
|
343
|
+
Carries the offending *token* and the list of *available* display
|
|
344
|
+
names so the CLI caller can render a consistent error message.
|
|
345
|
+
"""
|
|
346
|
+
|
|
347
|
+
def __init__(self, token: str, available: list[str]):
|
|
348
|
+
self.token = token
|
|
349
|
+
self.available = available
|
|
350
|
+
super().__init__(f"Package '{token}' not found")
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def resolve_requested_packages(
|
|
354
|
+
packages: tuple[str, ...] | list[str],
|
|
355
|
+
all_deps: list,
|
|
356
|
+
) -> list[str] | None:
|
|
357
|
+
"""Map requested package tokens to canonical dependency keys.
|
|
358
|
+
|
|
359
|
+
The install engine matches ``only_packages`` by ``DependencyReference``
|
|
360
|
+
identity (e.g. ``owner/repo``), so short names like ``compliance-rules``
|
|
361
|
+
must be normalised to their canonical key before the engine is called.
|
|
362
|
+
|
|
363
|
+
Args:
|
|
364
|
+
packages: Raw tokens from the CLI ``[PACKAGES]...`` argument.
|
|
365
|
+
all_deps: Declared dependencies (direct + dev) to match against.
|
|
366
|
+
|
|
367
|
+
Returns:
|
|
368
|
+
An order-preserving, de-duplicated list of canonical keys, or
|
|
369
|
+
``None`` when *packages* is empty (meaning "refresh everything").
|
|
370
|
+
|
|
371
|
+
Raises:
|
|
372
|
+
UnknownPackageError: when a token matches no declared dependency.
|
|
373
|
+
"""
|
|
374
|
+
if not packages:
|
|
375
|
+
return None
|
|
376
|
+
|
|
377
|
+
token_to_canonical: dict[str, str] = {}
|
|
378
|
+
for dep in all_deps:
|
|
379
|
+
canonical_key = dep.get_unique_key() or dep.repo_url or dep.get_display_name()
|
|
380
|
+
tokens = {canonical_key, dep.get_display_name(), dep.repo_url}
|
|
381
|
+
if getattr(dep, "alias", None):
|
|
382
|
+
tokens.add(dep.alias)
|
|
383
|
+
parts = dep.repo_url.split("/")
|
|
384
|
+
if len(parts) >= 2:
|
|
385
|
+
tokens.add(parts[-1])
|
|
386
|
+
for token in tokens:
|
|
387
|
+
if token and token not in token_to_canonical:
|
|
388
|
+
token_to_canonical[token] = canonical_key
|
|
389
|
+
|
|
390
|
+
resolved: list[str] = []
|
|
391
|
+
seen: set[str] = set()
|
|
392
|
+
for pkg in packages:
|
|
393
|
+
canonical = token_to_canonical.get(pkg)
|
|
394
|
+
if not canonical:
|
|
395
|
+
available = [dep.get_display_name() for dep in all_deps]
|
|
396
|
+
raise UnknownPackageError(pkg, available)
|
|
397
|
+
if canonical not in seen:
|
|
398
|
+
seen.add(canonical)
|
|
399
|
+
resolved.append(canonical)
|
|
400
|
+
return resolved
|
|
401
|
+
|
|
402
|
+
|
|
334
403
|
def print_version(ctx, param, value):
|
|
335
404
|
"""Print version and exit."""
|
|
336
405
|
if not value or ctx.resilient_parsing:
|
|
@@ -656,3 +725,23 @@ def _create_minimal_apm_yml(config, plugin=False, target_path=None):
|
|
|
656
725
|
content = content.replace("dependencies:", skeleton + "\ndependencies:", 1)
|
|
657
726
|
|
|
658
727
|
out_file.write_text(content, encoding="utf-8")
|
|
728
|
+
|
|
729
|
+
|
|
730
|
+
def _find_apm_yml(start: Path | None = None) -> Path | None:
|
|
731
|
+
"""Walk parent directories from ``start`` (or cwd) to find ``apm.yml``.
|
|
732
|
+
|
|
733
|
+
Matches the npm / cargo / poetry ergonomic: a developer running
|
|
734
|
+
an ``apm`` command from a subdirectory of their project (``src/``,
|
|
735
|
+
``docs/``, ``scripts/``) finds the manifest and operates on it.
|
|
736
|
+
|
|
737
|
+
The walk stops at the filesystem root or when an ``apm.yml`` is
|
|
738
|
+
found, whichever comes first. Returns the absolute path to the
|
|
739
|
+
``apm.yml`` file when found; ``None`` when no project root is
|
|
740
|
+
discoverable from ``start`` upward.
|
|
741
|
+
"""
|
|
742
|
+
cwd = (start or Path.cwd()).resolve()
|
|
743
|
+
for candidate in (cwd, *cwd.parents):
|
|
744
|
+
manifest = candidate / "apm.yml"
|
|
745
|
+
if manifest.is_file():
|
|
746
|
+
return manifest
|
|
747
|
+
return None
|