--- name: doctor description: Health-check the execution environment in one pass and record the result, changing nothing. Five checks - plugin versions from jsc-hooks/hooks/version-guard.sh report, hook wiring from jsc-hooks/tools/wire-cli.sh status, CLI, skill and hook runtime tests from tools/test-clis.sh, global settings and current-directory settings from tools/scan-config.sh against tools/config-spec.tsv. Report one findings table per check, then write the whole run to wiki CHECK_{HASH}; use for checkups, not fixes. --- # doctor - execution environment health check Read-only. Every command below either reads local state, calls a read-only CLI command, or asks Gitea. None of them writes a setting. That is the contract with `jsc-cli:setup`: doctor states the facts, setup changes things. Collection (steps 1 to 5) **MUST run as a sub agent** - one sub agent for all five, returning the raw TSV lines. Only the report and the wiki write stay in the main agent. ## 1. Skill versions Run `jsc-hooks/hooks/version-guard.sh report`. It prints `{domain}{local}{remote}{落後|最新|超前|查詢失敗}` per plugin, then `behind{count}`. A report with no `{domain}` row, or one carrying `noregistry{path}`, means this CLI has no local plugin registry. Report it as `無法驗證` - never as `最新`. `behind0` proves nothing when no domain row precedes it. Done when every installed domain has a status literal, or the CLI is reported as unverifiable. ## 2. Hook wiring Run `jsc-hooks/tools/wire-cli.sh status {cli}` for every CLI that `tools/detect-clis.sh` found. Use `status` and nothing else: `wire-cli.sh` without a subcommand rewires, `purge` deletes, and `smoke` executes hooks - all three break the read-only contract. Exit codes: 0 wired, 1 degraded, 3 skipped because the CLI is not installed, 5 unwired. Each `item` line names one wiring point and whether it is present. Only claude reaches `wired`. The other four have no pre-tool hook, so `degraded` is their healthy state. Report the degradation reason as-is and never present it as a defect to fix. Done when every detected CLI has a status and its missing items are listed. ## 3. CLI runtime tests Run `tools/test-clis.sh` with no CLI arguments. It calls `tools/detect-clis.sh`, then runs real commands for every detected CLI. It covers three areas: CLI commands, skill loading, and hook runtime smoke. Output: - `test{area}{cli}{test}{command}{exit-code}{verdict}{detail}` - `summary{ok}{warn}{fail}{skipped}` Areas: `cli`, `skill`, `hook`. Verdicts: `ok`, `warn`, `fail`, `skipped`. Exit codes: 0 completed, 2 usage error, 3 missing `detect-clis.sh`. Any other script exit code is itself a doctor finding. Treat every `fail` as a machine problem, including `skill` and `hook` rows. Treat `warn` as degraded capability: name it in the report, but do not put it in the fix table unless the failing skill needs that feature. Treat `skipped` as no conclusion. Map the report labels to the template as `ok` -> `通過`, `warn` -> `降級`, `fail` -> `失敗`, and `skipped` -> `略過`. Done when every detected CLI has at least a version test row and the summary line is read. ## 4. Global settings Run `tools/scan-config.sh scan global`. It checks every `scope=global` row of `tools/config-spec.tsv` and prints `itemscoperequiredactualexpectfixverdict`, closing with `summary{missing}{invalid}{unset}{skipped}`. Verdicts: `ok`, `default`, `unset`, `missing`, `invalid`, `skipped`. Map the report labels to the template as `ok` -> `通過`, `default` -> `走預設`, `unset` -> `未設定`, `missing` -> `缺漏`, `invalid` -> `設錯`, and `skipped` -> `略過`. Add `-o` when Gitea is unreachable; the Gitea-dependent rows then come back `skipped`. Report those rows as inconclusive and never as passes. Also run `tools/scan-config.sh orphans` - variables used in the source but absent from the spec table. They are a maintenance note for the skill set, not a fault on this machine. Done when the summary line is read and every `missing` and `invalid` row is named. ## 5. Own settings Run `tools/scan-config.sh scan project` from the current working directory. Same output format, `scope=project` rows only. Say which directory was scanned in the report. A project-scope result is meaningless without it, because the answer changes with every `cd`. When `.env` or `.envrc` exists, name the spec-table variables it overrides and state the value actually in effect. A global setting silently overridden here is the failure this check exists to catch. Done when the scanned directory is stated and every project row has a verdict. ## 6. Report and record Report all five tables per `templates/check-page.md`. Then build the `待修項目` table from every `missing`, `invalid`, `unwired` and runtime `fail` item, plus every domain reported `落後`. Order them `missing` -> `invalid` -> `unwired` -> `runtime-fail` -> `落後`. Nothing wrong -> one row reading `無`. Write the page through `jsc-gitea:wiki`: - Wiki repo: `jsc-gitea/tools/gitea.sh wiki-repo CHECK`. - Page name: `CHECK_` plus `gitea.sh hash-id "{hostname}/{user}"` - the host and the login account, not `{owner}/{repo}`. Doctor checks a machine, and it has to work in directories that are not repositories at all. - Overwrite the whole page. This page type keeps only the latest run. - Update `CHECK_CONTENTS` from `templates/check-contents.md` in the same pass. `wiki-repo` exiting 3 means no wiki repo is configured for CHECK. Print the tables, skip the wiki write, and put `JSC_WIKI_REPO_CHECK` at the top of the `待修項目` table - that unset variable is itself a finding, so a failed write never fails the health check. Done when either the wiki page URL is reported, or the skipped write is reported together with the reason. ## 7. Hand off State the counts: required items missing, settings invalid, CLIs unwired, runtime failures grouped by `cli`, `skill` and `hook`, and domains behind. Recommend `/jsc-cli:setup` when any of those is above zero. Never fix anything here. Done when the counts are stated and the recommendation is given or explicitly withheld.