Restore doctor / clean / watch / init CLI commands¶
Problem¶
Command Reference documented four testo subcommands — doctor, clean, watch, init — with full flag tables and sample output, but none of them existed on main. testo_core/cli/app.py's _register_commands() only wired up run, config-db, diff, summary, cycles/plans, config, report, version. Only stale .pyc cache files remained as evidence the four commands once ran locally.
Root cause: the source files (testo_core/cli/commands/doctor.py, watch.py, clean.py, init_cmd.py) were added on branch cursor/report-infra-e976a but that branch was never merged and drifted ~20 commits behind main, with no open PR.
Decision¶
Port the four command modules from cursor/report-infra-e976a into main, adapting them to APIs that changed on main in the meantime rather than cherry-picking blindly.
What changed vs. the source branch¶
testo_core/cli/ui/feedback.py(print_ok/print_fail/print_warnhelpers) never existed onmain— replaced with directconsole.print("[ok]...[/]")-style calls, matching the pattern already used intesto_core/cli/commands/config_db.py.testo_core/cli/cleanup.py(used byclean) also never existed onmain— ported verbatim (self-contained, no API surface drift).testo_core/cli/runner.py'sexecute_plan_command()onmainno longer acceptstag/fail_fast/dry_runkeyword arguments (those options exist in the CLI help text but are not implemented inrun.pyonmaineither — pre-existing gap, out of scope here).watch.py's call site was adjusted to only pass the kwargsexecute_plan_command()currently supports.doctor.pyhad a latent bug in the source branch: it readcfg.cycles/cfg.source_pathguarded byif not hard_fail:even thoughcfgis only bound when config load succeeds — a CLI-executable hard-fail (not a config-load fail) would still enter that branch safely, but a config-load failure combined with any later flag flip would have risked aNameError. Fixed by gating onif cfg is not None:instead.init.py's generated YAML dropped atags: [smoke]line —Plan/_parse_cycleintesto_core/config/schema.pyandloader.pyonmainhave notagsconcept; the key was silently ignored, so it was dead/misleading scaffolding.- Added
watchdog>=4.0.0topyproject.tomlcoredependencies— required bywatch.py, was previously undeclared. - Exit code reconciliation: Command Reference had two contradictory claims for
testo doctor's hard-failure exit code — "exits 3" in thetesto doctorsection vs. "2 on hard FAIL" in Troubleshooting and Error Codes § Commands that use exit codes. The restored code usesEngineExitCode.INVALID_INPUT(2), matching both the original branch implementation and the Troubleshooting doc (the authoritative exit-code table). Fixed the contradictory line in Command Reference.
Current implementation (HOW — codebase)¶
| Command | Module | Registered in |
|---|---|---|
testo doctor |
testo_core/cli/commands/doctor.py |
testo_core/cli/app.py → _register_commands() |
testo clean |
testo_core/cli/commands/clean.py + testo_core/cli/cleanup.py |
same |
testo watch |
testo_core/cli/commands/watch.py |
same |
testo init |
testo_core/cli/commands/init_cmd.py |
same |
Tests: tests/unit/testo_core/test_cli_doctor.py, test_cli_clean.py, test_cli_watch.py, test_cli_init.py.
Out of scope (deliberately not touched)¶
Shell completion, top-level --version, help-panel grouping/emoji (rich_help_panel=), and drift-guard tests — those are separate, parallel PRs. _register_commands() additions here intentionally match the plain (no rich_help_panel) style already on main, not the richer style also present in the source branch's app.py.
Context & Links: Command Reference, Troubleshooting and Error Codes, Architecture Overview § Exit code contract