-
Notifications
You must be signed in to change notification settings - Fork 45
Labels
acceptedDirection approved, safe to start workDirection approved, safe to start workenhancementNew feature or requestNew feature or request
Description
Is your feature request related to a problem? Please describe.
Two source files have grown far beyond maintainable size:
src/apm_cli/cli.py— ~4,675 lines containing 15+ Click commands, 60+ helper functions, and an 860-line install engine all in a single file.src/apm_cli/models/apm_package.py— ~1,186 lines mixing dataclasses, enums, a 377-lineDependencyReference.parse()method, and validation logic.
This makes parallel development difficult, increases merge conflicts, and hurts code navigability. The rest of the codebase follows good modular patterns (50–200 line files).
Describe the solution you'd like
Phase 1 — Extract CLI commands from cli.py into commands/
Reduce cli.py from ~4,675 → ~120 lines (thin wiring layer). Follow the existing commands/deps.py pattern.
| New file | What moves there | ~Lines |
|---|---|---|
commands/_helpers.py |
Shared utilities: _get_console(), lazy loaders, color constants, _check_orphaned_packages(), _atomic_write() |
~250 |
commands/init.py |
init() command + _interactive_project_setup(), _auto_detect_author(), _get_default_config(), _create_minimal_apm_yml() |
~400 |
commands/install.py |
install() command + _install_apm_dependencies() (860-line core engine), _validate_and_add_packages_to_apm_yml(), MCP dep helpers, summary display |
~1,400 |
commands/uninstall.py |
uninstall() command + transitive cleanup |
~420 |
commands/prune.py |
prune() command |
~150 |
commands/update.py |
update() command |
~130 |
commands/compile.py |
compile() command + _watch_mode(), validation display helpers |
~700 |
commands/run.py |
run() + preview() commands + runtime detection helpers |
~350 |
commands/list.py |
list() command |
~90 |
commands/config.py |
config group (set/get) |
~160 |
commands/runtime.py |
runtime group (setup/list/remove/status) |
~80 |
commands/mcp.py |
mcp group (search/show/list) |
~200 |
cli.py becomes a thin wiring layer: @click.group, cli.add_command(...), print_version(), and main().
Design rules:
- The
set = builtins.set/list = builtins.listtrick must move to any command file whose Click name clashes with builtins. _helpers.pymust NOT import from command modules (prevents circular imports).- Command modules must NOT import from each other — shared logic goes in
_helpers.py.
Phase 2 — Split apm_package.py into focused model files
Reduce apm_package.py from ~1,186 → ~400 lines.
| New file | What moves there | ~Lines |
|---|---|---|
models/dependency.py |
DependencyReference (incl. 377-line parse()), ResolvedReference, GitReferenceType, parse_git_reference() |
~650 |
models/validation.py |
ValidationResult, ValidationError, PackageType, validate_apm_package() + private validators, _has_hook_json(), InvalidVirtualPackageExtensionError |
~300 |
apm_package.py (slimmed) |
APMPackage, PackageInfo, PackageContentType, cache logic |
~400 |
models/__init__.py re-exports all symbols so from apm_cli.models import X keeps working everywhere.
Verification
uv run pytest -q— full test suite, zero regressionsuv run python -c "from apm_cli.cli import cli; print('OK')"— no circular importsuv run python -c "from apm_cli.models import DependencyReference, APMPackage, ValidationResult, ResolvedReference, PackageInfo; print('OK')"— re-exports intactuv run pytest tests/benchmarks/ -q— no perf regressionuv run apm --version && uv run apm --help— CLI smoke test
Describe alternatives you've considered
- Partial extraction (only the largest commands like
installandcompile): Would help but still leaves a 2,000+ line cli.py. A full extraction is cleaner and sets the right pattern going forward. - Keeping models in one file: The 377-line
parse()method and validation logic are sufficiently independent domains to justify separate files. Leaving them mixed increases cognitive load.
Additional context
- Phases 1 and 2 are independent and can be done in parallel or either order.
_install_apm_dependencies()(860 lines) is a candidate for further decomposition into resolve/download/integrate phases, but that should be a separate follow-up to limit blast radius.- No user-facing behavior changes — this is pure internal restructuring.
- The existing
commands/deps.py(823 lines withlist,tree,clean,update,infosubcommands) serves as the template for new command files.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
acceptedDirection approved, safe to start workDirection approved, safe to start workenhancementNew feature or requestNew feature or request