/** * Doctor health checks - ported from lib/validation/doctor-checks.sh * * Global health check functions: CLI installation, version, docs accessibility, * agent configs, registered projects, injection files, and aliases. * * @task T4525 * @epic T4454 */ import type { CheckResult } from '@cleocode/contracts/scaffold-diagnostics'; export type { CheckResult, CheckStatus, } from '@cleocode/contracts/scaffold-diagnostics'; /** @task T4525 */ export declare function checkCliInstallation(cleoHome?: string): CheckResult; /** @task T4525 */ export declare function checkCliVersion(cleoHome?: string): CheckResult; /** @task T4525 */ export declare function checkDocsAccessibility(cleoHome?: string): CheckResult; /** @task T4525 */ export declare function checkAtReferenceResolution(): CheckResult; /** * Check that AGENTS.md exists in project root and contains the CAAMP:START marker, * indicating it serves as the injection hub for CLEO protocol content. */ export declare function checkAgentsMdHub(projectRoot?: string): CheckResult; /** * Check if project root .gitignore is blocking the entire .cleo/ directory. * This prevents core CLEO data from being tracked by git. * @task T4641 * @epic T4637 */ export declare function checkRootGitignore(projectRoot?: string): CheckResult; /** * Check if .cleo/.gitignore exists and matches the template. * @task T4700 */ export declare function checkCleoGitignore(projectRoot?: string): CheckResult; /** * Check that vital CLEO configuration files are tracked by git. * Only checks config files (config.json, .gitignore, project-info.json, * project-context.json). SQLite databases are excluded per ADR-013. * @task T4700 */ export declare function checkVitalFilesTracked(projectRoot?: string): CheckResult; /** * Check that core CLEO files are not being ignored by .gitignore. * Uses `git check-ignore` to detect files that would be excluded by * any gitignore rule (root, .cleo/, or global). * Returns critical status if any protected file is gitignored. */ export declare function checkCoreFilesNotIgnored(projectRoot?: string): CheckResult; /** * Check that SQLite databases (.cleo/tasks.db) are NOT tracked by project git. * Tracked SQLite files cause data loss from merge conflicts (ADR-013). * Warns if tasks.db is currently tracked so the user can untrack it. * @task T5160 */ export declare function checkSqliteNotTracked(projectRoot?: string): CheckResult; /** * Warn when a stash stack is shared by several worktrees. * * ## The failure this exists to stop (T12161) * * The stash is a property of the repository, not of the working tree. Every * worktree sharing a `.git` sees the same stack, so `git stash pop` — which * takes `stash@{0}` when given no argument — pops whatever another session * pushed most recently, into YOUR tree, on YOUR branch. * * Measured 2026-09-12 in this repo: an agent ran `git stash push` on an * untracked file (a no-op, so nothing was pushed), then `git stash pop`, and * silently received an unrelated entry from a 26-deep stack belonging to * another session's branch work. It modified a generated manifest the agent * had never touched. It was caught before commit by a diff review, not by any * tooling. * * The stack here is not transient: entries date back months, across branches * that are long merged. A single-worktree repo has none of this exposure, * which is why the check stays silent there rather than nagging every user * about a normal stash. * * @param projectRoot - repository to inspect; defaults to the resolved root. * @returns a warning naming the depth and the top entry, or a pass. * * @task T12161 */ export declare function checkSharedWorktreeStashes(projectRoot?: string): CheckResult; /** * Warn when a repo-LOCAL identity override is absent from recent history. * * ## The failure this exists to stop (T12161) * * `user.name` and `user.email` set at `--local` scope live in `.git/config`, * which every worktree shares. One session setting a throwaway identity — for * a measurement, a probe, a bisect — silently re-authors every commit made by * every other session in every other worktree until someone notices. * * Measured 2026-09-12 in this repo: `user.name` was left as `compose probe * ` after a merge-composition experiment, and three commits from * a different session on a different branch were authored under it. Nothing * warned; it was found by reading `git log` for an unrelated reason. * * ## Why this reads `--local` and not the effective identity * * `git config user.email` returns the MERGED value — local, then global, then * system. Reading that would flag a first-time contributor whose perfectly * correct global identity simply has no commits here yet, which is noise. A * repo-local override is different in kind: it is a deliberate act scoped to * this repository, it is the only kind that one session can impose on another * through the shared `.git`, and when it authored none of recent history the * overwhelmingly likely explanation is that somebody else set it for something * else. So the remedy is to REMOVE the override and fall back to the * committer's own global identity — not to set another value. * * Gated on a shared `.git` for the same reason as the stash check: a local * identity in a single-worktree repo affects only the person who set it. * * @param projectRoot - repository to inspect; defaults to the resolved root. * @returns a warning naming the override, or a pass. * * @task T12161 */ export declare function checkSharedGitIdentity(projectRoot?: string): CheckResult; /** * Check if any legacy output directories still exist. * Delegates detection to the migration/agent-outputs utility. * @task T4700 */ export declare function checkLegacyAgentOutputs(projectRoot?: string): CheckResult; /** * Validate that artifacts are at canonical RCASD paths per ADR-045. * Detects drift: deprecated flat dirs, misplaced agent outputs, etc. * * @task T708 (scaffolding path drift validator) */ export declare function checkCanonicalRcasdPaths(projectRoot?: string): CheckResult; /** * Verify CAAMP marker integrity across the instruction-file cascade. * * Checks three distinct failure modes: * * - **Damaged markers** — a marker whose delimiters were mangled (for example * `!-- CAAMP:START -->`, having lost its leading `<`). The strict block * pattern cannot see these, so before T12051 they were invisible here while * causing `inject()` to prepend duplicate blocks on every run. * - **Unbalanced markers** — START and END counts differ. * - **Duplicate blocks** — more than one block in a file, which means the * referenced protocol text is loaded into every agent's context more than * once. * * The **global hub** `~/.agents/AGENTS.md` is included deliberately. It is the * most-written file in the system — every `cleo init`, `cleo upgrade` and * `cleo doctor` run rewrites it no matter which project invoked them — and it * was previously the one file no health check inspected. The corruption this * check now catches was found there. * * @param projectRoot - Project directory to check; defaults to the resolved project root * @returns Check result naming each offending file * * @task T5153 * @task T12051 */ export declare function checkCaampMarkerIntegrity(projectRoot?: string): CheckResult; /** * Parse @ references from AGENTS.md CAAMP block and verify each target file exists. * @task T5153 */ export declare function checkAtReferenceTargetExists(projectRoot?: string): CheckResult; /** * Compare templates/CLEO-INJECTION.md vs the XDG-canonical deployed path. * @task T5153 */ export declare function checkTemplateFreshness(projectRoot?: string): CheckResult; /** * Verify all 3 tier markers exist with matching close tags in deployed template. * @task T5153 */ export declare function checkTierMarkersPresent(): CheckResult; /** * Check that Node.js meets the minimum required version. * Provides OS-specific upgrade instructions when below minimum. */ export declare function checkNodeVersion(): CheckResult; /** * Check that global schemas at ~/.cleo/schemas/ are installed and not stale. * Delegates to checkGlobalSchemas() from schema-management.ts. * * The projectRoot parameter exists for API consistency with other check * functions in runAllGlobalChecks(), but global schemas live at ~/.cleo/schemas/ * (not per-project). The parameter is intentionally unused because schema * health is a system-wide concern, not project-scoped. */ export declare function checkGlobalSchemaHealth(_projectRoot?: string): CheckResult; /** * Warn if deprecated .cleo/schemas/ directory still exists in the project. * Schemas should live in ~/.cleo/schemas/ (global), not in project directories. */ export declare function checkNoLocalSchemas(projectRoot?: string): CheckResult; /** * Audit orphaned CLEO agent worktree directories. * * Lists all directories under `getCleoWorktreesRoot()` (the platform CLEO * data dir, where `cleo orchestrate spawn` provisions) whose names are NOT in the provided * `activeTaskIds` set. Surfaces them as a `warning` so the operator can * clean them with `cleo gc --worktrees`. * * @param worktreesRoot - Override for the worktrees root (testing). * @param activeTaskIds - Set of currently active task IDs to preserve. * @returns CheckResult with orphan paths in `details.orphans`. * * @task T9043 */ export declare function auditOrphanWorktrees(worktreesRoot?: string, activeTaskIds?: Set): CheckResult; /** * Audit orphaned CLEO-generated temp directories. * * Scans `os.tmpdir()` for directories matching any prefix in * `CLEO_TEMP_PREFIXES` that are older than 2 hours (the default orphan * threshold). Surfaces them as a `warning` so the operator can clean them * with `cleo gc --temp`. * * @param tempDirOverride - Override for os.tmpdir() (testing). * @param maxAgeMs - Maximum age threshold in ms (default: 2 hours). * @returns CheckResult with orphan paths in `details.orphans`. * * @task T9043 */ export declare function auditOrphanTempDirs(tempDirOverride?: string, maxAgeMs?: number): Promise; /** * Check that active JSON files (config.json, project-info.json, etc.) are valid * against their schemas and have current schema versions. * * Maps JsonFileIntegrityResult[] from checkSchemaIntegrity() into CheckResult[], * then returns a single rolled-up CheckResult for the doctor summary. */ export declare function checkJsonSchemaIntegrity(projectDir: string): Promise; /** * Detect stranded legacy source DBs after an exodus cutover. * * Once a scope's exodus completion marker (`exodus-complete`) exists, every one * of the six legacy source DBs for that scope SHOULD have been archived into the * scope's `_archive/` directory. A source still present on disk is "stranded * residue" — it re-arms the `tasks_tasks=0` auto-recover / exodus-on-open * corruption trigger (DHQ-052 · T11662). This check surfaces that residue so it * can be archived via `cleo doctor exodus-residue --fix`. * * Read-only. Returns `'passed'` when no marker exists yet (a pre-cutover install * where the legacy DBs are still the live source of truth — NOT residue) or when * every marked scope's sources have been archived. Returns `'warning'` when * residue is found (it is recoverable, never data-loss — the fix only MOVES * files into `_archive/`). * * @param projectRoot - Project root used to resolve the project `.cleo/` dir. * @returns A {@link CheckResult} describing stranded residue (if any). * * @task T11777 */ export declare function checkExodusStrandedResidue(projectRoot?: string): Promise; /** * Check the portable project identity: `.cleo/project.json` and its legacy * `.cleo/project-id` mirror against the `project-info.json` cache, and * whether git tracks the file (T12353 · ADR-094 · T12716). * * A conflict, a mirror conflict or an invalid file is `failed`, because local * state is keyed by an id no clone will ever share. A missing, legacy, * mirror-missing, uncommitted or ignored file is a `warning`: nothing is wrong * locally yet, but a clone (or an older build) would not see the identity. * Every non-passing result carries the exact remedy command in `fix`. * * @param projectRoot - Project root; defaults to the resolved current project. * @returns The check result. * @task T12353 */ export declare function checkProjectIdentity(projectRoot?: string): CheckResult; /** * Check that the global registry labels this project with the name it * declares in `.cleo/project.json` (T12716). Drift is a `warning` whose fix * syncs the label; an unreadable registry is `info` (coverage missing), never * `passed`. * * @param projectRoot - Project root; defaults to the resolved current project. * @param cleoHome - Global CLEO home whose registry is read. * @returns The check result. * @task T12716 */ export declare function checkProjectNameDrift(projectRoot?: string, cleoHome?: string): Promise; /** * Check that a workspace's `tool:test` evidence runs the affected packages, * not the whole suite, and name `ci:` as the preferred `testsPassed` * evidence when the project accepts it (T13125). * * - `passed`: `testing.affectedCommand` is declared, or the project is not a * workspace (nothing to scope). * - `info`: none declared, but one derives from `testing.command`; the fix * proposes pinning it. * - `warning`: a workspace with no declared or derivable template, so every * `cleo verify --evidence tool:test` runs the whole suite. * * @param projectRoot - Project root; defaults to the resolved current project. * @returns The check result. * @task T13125 */ export declare function checkAffectedTestScope(projectRoot?: string): CheckResult; /** * Check that a project with GitHub workflows opts in to merged-PR CI as * `testsPassed`/`qaPassed` evidence (`evidence.ciSatisfies`, T13096). Without * it, a task whose PR merged after a scoped run can only complete on a full * local suite. The warning's fix is the ready-to-paste `evidence` block with * the default branch's required checks ({@link ciSatisfiesRemedy}). * * @param projectRoot - Project root; defaults to the resolved current project. * @returns `passed` when the setting is on or there are no workflows; else `warning`. * @task T13096 */ export declare function checkCiSatisfies(projectRoot?: string): Promise; /** * Warn about CANT files left in the pre-T12602 Linux-style dirs on macOS and * Windows. * * The global and user CANT tiers used to resolve to * `~/.local/share/cleo/cant` and `~/.config/cleo/cant` on every OS. They now * resolve through `@cleocode/paths` (`/cant` and * `/cant`), so `.cant` files still in the old dirs are no * longer read. On Linux the old and new dirs are the same, so this check * passes there. * * @param home - Home directory holding the old dirs (testing). * @returns `warning` listing each old dir that still holds `.cant` files and * where to move them; `passed` otherwise. * * @task T12602 */ export declare function checkLegacyCantDirs(home?: string): CheckResult; /** * Report what an old CLEO left in the user-global Claude settings (T13221). * * Releases whose Claude Code adapter install ran (before T13128 removed that * step) could enable the `cleo@cleocode` plugin, add hooks tagged * `# cleo-hook` under any event (`Stop`, `PostToolUse`, `PreCompact`) in the * user-global `settings.json`, and copy hook scripts into its `hooks/` dir. * CLEO never writes the user-global Claude settings, and removing an entry is * writing, so this check is REPORT-ONLY: it reads, and its `fix` spells out * the manual removal steps. It never edits or deletes anything there. * * @param claudeHome - The user-global Claude dir. * @defaultValue `CLAUDE_HOME`, else `~/.claude` * @returns `warning` listing each leftover and how to remove it by hand, or * naming a settings file it could not parse; `passed` when there is none. * * @example * ```ts * checkUserGlobalClaudeLeftovers('/tmp/sandbox/.claude'); * ``` * * @task T13221 */ export declare function checkUserGlobalClaudeLeftovers(claudeHome?: string): CheckResult; /** * Run all global health checks and return results array. * @task T4525 */ export declare function runAllGlobalChecks(cleoHome?: string, projectRoot?: string): CheckResult[]; /** * Calculate overall status from check results. * Returns: 0=passed, 50=warning, 52=critical. * @task T4525 */ export declare function calculateHealthStatus(checks: CheckResult[]): number; //# sourceMappingURL=checks.d.ts.map