Skip to content

refactor(arch): cli = parse + route only; domain logic relocated to owning subsystems#129

Merged
Sunrisepeak merged 7 commits into
mainfrom
refactor/cli-modularization
Jun 10, 2026
Merged

refactor(arch): cli = parse + route only; domain logic relocated to owning subsystems#129
Sunrisepeak merged 7 commits into
mainfrom
refactor/cli-modularization

Conversation

@Sunrisepeak

@Sunrisepeak Sunrisepeak commented Jun 10, 2026

Copy link
Copy Markdown
Member

Motivation

src/cli.cppm had grown to 6192 lines, mixing command dispatch, the entire build-orchestration pipeline (prepare_build, ~2240 lines), toolchain payload post-install fixups, install-progress UI plumbing, and 25 command implementations in one module — the slowest incremental rebuild unit in the repo and a permanent merge-conflict hotspot.

This PR restructures the whole CLI surface in two layers:

  1. Dispatchercli.cppm is now a 481-line module containing only the usage screen and the cmdline::App + run() dispatch.
  2. Parse + route adapterssrc/cli/cmd_*.cppm (7 modules, ~450 lines total) contain only argument handling, CLI-shape validation, and routing. No domain logic; mcpplibs.cmdline never crosses below the cli layer.

All implementations were relocated into their owning subsystems:

New module Owns
mcpp.project manifest/workspace discovery + workspace-dep merging (also folds the private copy pm.commands kept to avoid importing the old cli)
mcpp.fetcher.progress xlings NDJSON → download-progress UI adapters, path-shortening context
mcpp.build.prepare BuildContext, BuildOverrides, prepare_build (workspace → toolchain → dependency resolution → features → modgraph → fingerprint → plan → lockfile)
mcpp.build.execute build cache + fast-path rebuilds, run_build_plan, run/test/clean pipelines
mcpp.toolchain.post_install patchelf / specs / cfg payload fixups
mcpp.toolchain.lifecycle toolchain list / install / set-default / remove + version matching
mcpp.pm.index_management search + index list/add/remove/update/pin/unpin
mcpp.bmi_cache.maintenance BMI cache walk/list/info/prune/clean + fs-size helpers
mcpp.scaffold.create package-shipped templates + builtin project creation
mcpp.publish.pipeline publish pipeline + xpkg emission
mcpp.pack.pipeline pack orchestration
mcpp.doctor doctor / why / env / explain + self init/config

Layering rules: cmd_* adapters never import each other; domain ops take plain typed parameters (never ParsedArgs); export surface is explicit per symbol; module names state their responsibility (no grab-bag ops/manager/utils names). Full architecture + relocation map: .agents/docs/2026-06-10-cli-modularization.md.

Zero behavior change

Bodies were moved byte-identical via scripted line-range extraction (same statement order, messages, exit codes). The only edits: namespaces, export keywords, explicit qualification at cross-namespace call sites, and CliInstallProgressInstallProgressHandler (renamed for its new fetcher-domain home). No platform-conditional code touched; source discovery is glob-based so no manifest change on any platform.

Verification (after each phase)

  • Self-host build: clean (the two imgui.* scanner warnings from the template raw-string literal pre-date this PR — identical on main)
  • mcpp test: 18/18 unit tests pass
  • tests/e2e/run_all.sh: 67 pass / 1 skip — the 6 llvm_* failures fail identically with the pre-refactor binary on the same host (local LLVM payload exec issue, environment-specific, not a regression)
  • CLI sanity: --help screen, version, unknown-command exit 127 unchanged
  • CI: all three platform lanes green on both the phase-1 and phase-2 commits

Follow-ups (documented in the plan doc)

  • Decompose prepare_build internally now that it lives in mcpp.build.prepare
  • Tighten mcpp.build.prepare's inherited import list
  • Migrate pm.commands (add/remove/update) behind typed ops to complete the parse/route pattern

cli.cppm (6192 lines) -> thin dispatcher (481 lines). All command
implementations move into dedicated modules, byte-identical bodies:

  mcpp.cli.common         project/workspace discovery + fs utils
  mcpp.cli.install_ui     xlings NDJSON -> ui download-progress adapters
  mcpp.toolchain.post_install  patchelf/specs/cfg payload fixups
  mcpp.cli.build          BuildContext + prepare_build (build core)
  mcpp.cli.cmd_build      build/run/test/clean/dyndep + fast-path cache
  mcpp.cli.cmd_new        new + package templates
  mcpp.cli.cmd_registry   search + index management
  mcpp.cli.cmd_cache      cache list/info/prune/clean
  mcpp.cli.cmd_toolchain  toolchain install/list/default/remove
  mcpp.cli.cmd_publish    publish/pack/emit-xpkg
  mcpp.cli.cmd_self       self */doctor/why/env/explain

Zero behavior change (same statement order, messages, exit codes).
Architecture + plan: .agents/docs/2026-06-10-cli-modularization.md
…se + route)

Phase 2 of the cli modularization: every implementation now lives in
its owning subsystem; cli/cmd_* modules contain only argument handling,
CLI-shape validation and routing (no ParsedArgs below the cli layer).

  mcpp.project            manifest/workspace discovery (pm.commands' private
                          copy folded in)
  mcpp.fetcher.progress   xlings NDJSON -> ui adapters (InstallProgressHandler)
  mcpp.build.prepare      BuildContext + prepare_build
  mcpp.build.execute      build cache/fast-path, run_build_plan, run/test/clean
  mcpp.toolchain.manager  toolchain list/install/set-default/remove
  mcpp.pm.index_ops       search + index list/add/remove/update/pin/unpin
  mcpp.bmi_cache.ops      cache walk/list/info/prune/clean + fs size helpers
  mcpp.scaffold.ops       package templates + builtin project creation
  mcpp.publish.ops        publish pipeline + emit xpkg
  mcpp.pack.ops           pack orchestration
  mcpp.doctor             doctor/why/env/explain + self init/config

mcpp.cli.{common,install_ui,build} are gone; the whole cli layer is now
cli.cppm (481) + seven adapters (450 lines total). Bodies moved verbatim
(zero behavior change). Doc: .agents/docs/2026-06-10-cli-modularization.md
@Sunrisepeak Sunrisepeak changed the title refactor(cli): split cli.cppm into focused modules (dispatcher-only CLI) refactor(arch): cli = parse + route only; domain logic relocated to owning subsystems Jun 10, 2026
…onsibility names

mcpp.bmi_cache.ops      -> mcpp.bmi_cache.maintenance
mcpp.scaffold.ops       -> mcpp.scaffold.create
mcpp.publish.ops        -> mcpp.publish.pipeline
mcpp.pack.ops           -> mcpp.pack.pipeline
mcpp.pm.index_ops       -> mcpp.pm.index_management
mcpp.toolchain.manager  -> mcpp.toolchain.lifecycle

Pure rename (module/file/import sites); namespaces, exported symbols and
behavior unchanged.
@Sunrisepeak Sunrisepeak merged commit e9ed0e9 into main Jun 10, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant