* feat(doctor): add --lint mode + structured HealthFinding shape
Adds the core machinery for `openclaw doctor --lint` per the
doctor-lint-and-oc-rules upstream proposal. PR-1 of the proposal:
no new top-level verb, no public plugin SDK; everything internal.
Files:
- src/flows/checks.ts ? HealthFinding / HealthCheck / HealthCheckContext
types. Findings carry severity per-finding; checks return
readonly HealthFinding[]. Mode tag (doctor/lint/fix) lets a check
distinguish the calling posture.
- src/flows/health-check-registry.ts ? module-level registry with
duplicate-id rejection + test reset helper.
- src/flows/doctor-lint-flow.ts ? runner over registered checks.
Catches throws into synthetic error findings (anchored at check id;
message scrubbed of control chars, capped at 256 bytes). Sorts
findings by severity desc, check id, path. Exports
exitCodeFromFindings (1 if any warning/error, 0 otherwise).
- src/flows/doctor-core-checks.ts ? 4 modern HealthChecks rewriting
logic from existing legacy run*Health functions:
core/doctor/gateway-config (warning)
core/doctor/command-owner (info)
core/doctor/workspace-status (info)
core/doctor/final-config-validation (error)
Each was audited safe per the proposal's adapter constraints
(no writes, no repair calls, no prompts, no probes incl. local-bind).
Legacy run*Health contributions in doctor-health-contributions.ts
are unchanged ? doctor mode (no --lint) still runs the existing 35.
- src/commands/doctor-lint.ts ? CLI dispatch for --lint. Reads config
snapshot, builds HealthCheckContext (mode: "lint"), runs the registry,
filters by --severity-min, emits human or JSON output, returns exit
code from unfiltered set so --severity-min hides info findings
without changing CI signal.
- src/cli/program/register.maintenance.ts ? adds --lint, --json,
--severity-min, --skip, --only flags to existing doctor command.
--lint branches to runDoctorLintCli; without --lint, doctor runs
unchanged.
LoC: 382 src across 6 files. Tests + doc + oc-path-side rule packs
follow as separate commits on this branch.
* fix: avoid string spread in doctor errors
* chore: refresh plugin SDK API baseline
* docs: clarify doctor lint usage
* feat(doctor): prepare repairs for dry-run reporting
Fixes#1327 - 'clawdbot message --channel telegram' fails with
'Unknown channel: telegram' because plugins weren't loaded.
The Commander code path (non-route-first) calls ensureConfigReady() in
preAction but doesn't load the plugin registry. Channel plugins like
telegram are registered during plugin loading, so getChannelPlugin()
returns undefined without it.
This adds ensurePluginRegistryLoaded() call for commands that need
channel plugin access: message, channels, directory.
Add shared parseBooleanValue()/isTruthyEnvValue() and apply across CLI, gateway, memory, and live-test flags for consistent env handling.
Introduce route-first fast paths, lazy subcommand registration, and deferred plugin loading to reduce CLI startup overhead.
Centralize config validation via ensureConfigReady() and add config caching/deferred shell env fallback for fewer IO passes.
Harden logger initialization/imports and add focused tests for argv, boolean parsing, frontmatter, and CLI subcommands.