You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Doctor: add health-check contract and --lint validation (#80055)
* 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
- Performance: non-interactive `doctor` runs skip eager plugin loading so headless health checks stay fast. Interactive sessions still fully load plugins when a check needs their contribution.
|`openclaw doctor`| yes | no | friendly health report | a human checking status |
89
+
|`openclaw doctor --fix`| sometimes | yes, with repair policy | friendly repair log | applying approved repairs |
90
+
|`openclaw doctor --lint`| no | no | structured findings | CI, preflight, and review gates |
91
+
92
+
Modernized health checks may provide an optional `repair()` implementation.
93
+
`doctor --fix` applies those repairs when they exist and continues to use the
94
+
existing doctor repair flow for checks that have not migrated yet.
95
+
The structured repair contract also separates repair reporting from detection:
96
+
`detect()` reports current findings, while `repair()` can report changes,
97
+
config/file diffs, and non-file side effects. That keeps the migration path open
98
+
for future `doctor --fix --dry-run` and diff output without making lint checks
99
+
plan mutations.
100
+
101
+
Examples:
102
+
103
+
```bash
104
+
openclaw doctor --lint
105
+
openclaw doctor --lint --severity-min warning
106
+
openclaw doctor --lint --json
107
+
openclaw doctor --lint --only core/doctor/gateway-config --json
108
+
```
109
+
110
+
JSON output includes:
111
+
112
+
-`ok`: whether any visible finding met the selected severity threshold
113
+
-`checksRun`: number of health checks executed
114
+
-`checksSkipped`: checks skipped by `--only` or `--skip`
115
+
-`findings`: structured diagnostics with `checkId`, `severity`, `message`, and
116
+
optional `path`, `line`, `column`, `ocPath`, and `fixHint`
117
+
118
+
Exit codes:
119
+
120
+
-`0`: no findings at or above the selected threshold
121
+
-`1`: one or more findings met the selected threshold
122
+
-`2`: command/runtime failure before lint findings could be emitted
123
+
124
+
Use `--severity-min info|warning|error` to control both what is printed and what
125
+
causes a non-zero lint exit. Use `--only <id>` for narrow preflight gates and
126
+
`--skip <id>` to temporarily exclude a noisy check while keeping the rest of the
127
+
lint run active.
128
+
Lint-output options such as `--json`, `--severity-min`, `--only`, and `--skip`
129
+
must be paired with `--lint`; regular doctor and repair runs reject them.
130
+
69
131
## What it does (summary)
70
132
71
133
<AccordionGroup>
@@ -471,8 +533,8 @@ That stages grounded durable candidates into the short-term dreaming store while
471
533
472
534
- `openclaw doctor` prompts before rewriting supervisor config.
473
535
- `openclaw doctor --yes` accepts the default repair prompts.
474
-
- `openclaw doctor --repair` applies recommended fixes without prompts.
475
-
- `openclaw doctor --repair --force` overwrites custom supervisor configs.
536
+
- `openclaw doctor --fix` applies recommended fixes without prompts (`--repair` is an alias).
537
+
- `openclaw doctor --fix --force` overwrites custom supervisor configs.
476
538
- `OPENCLAW_SERVICE_REPAIR_POLICY=external` keeps doctor read-only for gateway service lifecycle. It still reports service health and runs non-service repairs, but skips service install/start/restart/bootstrap, supervisor config rewrites, and legacy service cleanup because an external supervisor owns that lifecycle.
477
539
- On Linux, doctor does not rewrite command/entrypoint metadata while the matching systemd gateway unit is active. It also ignores inactive non-legacy extra gateway-like units during the duplicate-service scan so companion service files do not create cleanup noise.
478
540
- If token auth requires a token and `gateway.auth.token` is SecretRef-managed, doctor service install/repair validates the SecretRef but does not persist resolved plaintext token values into supervisor service environment metadata.
0 commit comments