/** * Cross-project health checks for every project registered in `nexus.db`. * * This module iterates the global NEXUS `project_registry` table and, for each * registered project, probes ALL of its databases (tasks.db, brain.db, * conduit.db) plus its key JSON files (config.json, project-info.json). It * also probes the global-tier databases (nexus.db, signaldock.db). * * Results are aggregated into a {@link FullHealthReport} and optionally * written back to the `healthStatus` column so subsequent `cleo nexus list` * calls surface stale/degraded projects without re-running the full probe. * * Probe guarantees (STRICT): * 1. Public functions NEVER throw — every failure is captured as an `error` * field on a {@link DbProbeResult} or {@link ProjectHealthReport}. * 2. All paths come from SSoT resolvers ({@link getPlatformPaths}, * {@link getCleoHome}, {@link getCleoDirAbsolute}). No `join(homedir(), * '.cleo')` is constructed locally. * 3. Concurrency is bounded by a counter-based limiter (default 8) — no new * third-party dependencies. * 4. The registry-update path short-circuits cleanly when `nexus.db` cannot * be opened (fresh install, pre-migration), so this module is safe to * run from `cleo self-update` BEFORE `runUpgrade()` repairs state. * * @task T-PROJECT-HEALTH */ /** Discrete health verdict stored on the `project_registry.health_status` column. */ export type ProjectHealthStatus = 'healthy' | 'degraded' | 'unreachable' | 'unknown'; /** * Programmatic probe result for a single SQLite database file. * * Captures filesystem presence, openability, PRAGMA-level integrity, and * WAL sidecar coherence. Every field is populated even on the error path so * callers can render actionable diagnostics without re-probing. */ export interface DbProbeResult { /** Absolute path to the probed database file. */ path: string; /** True if the file exists on disk. */ exists: boolean; /** True if the current process has read permission for the file. */ readable: boolean; /** True if `node:sqlite` successfully opened the file. */ sqliteOpenable: boolean; /** True iff `PRAGMA integrity_check` returned exactly the value `'ok'`. */ integrityOk: boolean; /** * True if either (a) no WAL sidecar is present, or (b) a WAL sidecar is * present AND the DB opened successfully (meaning SQLite could merge it). * False if the sidecar exists but the DB could not be opened. */ walSidecarClean: boolean; /** Value of `PRAGMA user_version` — undefined if the DB could not be opened. */ schemaVersion?: number; /** * Number of applied migrations from the `__drizzle_migrations` table (or the * DB-specific equivalent). Undefined when the DB could not be opened or when * no recognised migration tracking table exists. */ migrationCount?: number; /** * Expected migration count for this database as defined by the source-code * migration directories. Populated only when `probeDb` is called with the * `expectedVersion` option. Undefined otherwise. */ expectedVersion?: number; /** * True when `migrationCount` is defined and is less than `expectedVersion`, * indicating the database is behind the expected schema. Always `false` (not * `undefined`) when `expectedVersion` was supplied. */ schemaDrift?: boolean; /** Size of the DB file in bytes, or `-1` when `stat` fails. */ sizeBytes: number; /** First error encountered during the probe (null when the probe succeeded). */ error?: string; } /** Presence + parseability check for a JSON file (config.json, project-info.json). */ export interface JsonFileProbe { /** True if the file exists on disk. */ exists: boolean; /** True if the file parsed as JSON without throwing. */ parseable: boolean; /** * Schema version extracted from the file's top-level `schemaVersion` or * `version` field. Undefined when the file is absent, unparseable, or * carries no version field. */ schemaVersion?: string; /** * Expected schema version for this file. Populated only when * {@link probeJsonFile} is called with the `expectedVersion` option. */ expectedVersion?: string; /** * True when `schemaVersion` is defined and does not match `expectedVersion`. * Always `false` (not `undefined`) when `expectedVersion` was supplied. */ schemaDrift?: boolean; /** First error encountered (missing file, IO error, parse error). */ error?: string; } /** * Aggregated health report for a single registered project. * * Combines DB probes, JSON-file probes, and a top-level {@link overall} * verdict that mirrors the taxonomy stored in `project_registry.healthStatus`. */ export interface ProjectHealthReport { /** 12-char projectHash PK from `project_registry`. */ projectHash: string; /** Absolute project root path as recorded in the registry. */ projectPath: string; /** True iff the project directory is accessible AND `.cleo/` exists. */ reachable: boolean; /** DB probes for the three project-tier SQLite files. */ dbs: { tasks: DbProbeResult; brain: DbProbeResult; conduit: DbProbeResult; }; /** Probes for the two canonical JSON config files. */ files: { config: JsonFileProbe; projectInfo: JsonFileProbe; }; /** Overall verdict — folded from all probes via {@link deriveOverallStatus}. */ overall: ProjectHealthStatus; /** Human-readable summary strings suitable for a table column. */ issues: string[]; /** ISO 8601 timestamp when the probe completed. */ checkedAt: string; } /** Aggregated health report for the two global-tier databases. */ export interface GlobalHealthReport { /** Absolute CLEO home directory (via {@link getCleoHome}). */ cleoHome: string; /** Global-tier SQLite probes. */ dbs: { nexus: DbProbeResult; signaldock: DbProbeResult; }; /** Overall verdict across both global DBs. */ overall: ProjectHealthStatus; /** Human-readable summary strings. */ issues: string[]; /** ISO 8601 timestamp when the probe completed. */ checkedAt: string; } /** Top-level report combining global + all per-project reports. */ export interface FullHealthReport { /** Global-tier probe. */ global: GlobalHealthReport; /** One report per registered project. */ projects: ProjectHealthReport[]; /** Numeric summary for quick rendering. */ summary: { totalProjects: number; healthy: number; degraded: number; unreachable: number; unknown: number; }; /** ISO 8601 timestamp when the full report was assembled. */ generatedAt: string; } /** Options for {@link checkAllRegisteredProjects}. */ export interface CheckAllOptions { /** * When true, write each project's computed {@link ProjectHealthReport.overall} * back to `project_registry.health_status` and bump `last_seen`. * Defaults to true. */ updateRegistry?: boolean; /** Concurrency cap for per-project probes. Defaults to 8. */ parallelism?: number; /** When true (default), include the global-tier probe. */ includeGlobal?: boolean; } /** * Expected migration counts for each known database file, derived from the * number of timestamped directories present in * `packages/core/migrations/drizzle-/` at build time. * * - `tasks.db`, `brain.db`, `nexus.db`, `signaldock.db` use Drizzle migrations * tracked in `__drizzle_migrations`. * - `conduit.db` uses a bespoke `_conduit_migrations` table (1 initial entry). * * When the applied migration count in a database falls below the expected * count, {@link probeDb} sets `schemaDrift = true` and the health check * surfaces the affected project as `degraded`. */ export declare const DB_EXPECTED_VERSIONS: Readonly>; /** * Expected schema version strings for the two canonical JSON config files. * * - `config.json` uses the top-level `version` key (matches `CleoConfig.version`). * - `project-info.json` uses the top-level `schemaVersion` key. */ export declare const JSON_EXPECTED_VERSIONS: Readonly>; /** * Probe a single SQLite database file. Never throws — failures surface as * `error` on the returned {@link DbProbeResult}. * * Performs, in order: * 1. `fs.access` — existence + read permission. * 2. `fs.stat` — size in bytes. * 3. WAL sidecar detection (`-wal`). * 4. Open via `node:sqlite` in read-only mode. * 5. `PRAGMA integrity_check` — expects exactly the string `'ok'`. * 6. `PRAGMA user_version` — captured as `schemaVersion`. * 7. Applied-migration count from `__drizzle_migrations` (or * `_conduit_migrations` for conduit.db) — captured as `migrationCount`. * 8. When `expectedVersion` is provided: compares `migrationCount` against * it and sets `schemaDrift`. * * @param dbPath - Absolute path to the SQLite DB file. * @param expectedVersion - Optional expected migration count for this database. * When provided, {@link DbProbeResult.expectedVersion} and * {@link DbProbeResult.schemaDrift} are populated. Use * {@link DB_EXPECTED_VERSIONS} to look up the canonical value for each DB. * @returns A fully populated {@link DbProbeResult}. * * @example * ```typescript * const probe = await probeDb('/my/project/.cleo/tasks.db', 11); * if (probe.schemaDrift) console.warn('Schema is behind expected version'); * if (!probe.integrityOk) console.error(probe.error); * ``` */ export declare function probeDb(dbPath: string, expectedVersion?: number): Promise; /** * Check the health of every database + config file for a single registered * project. Never throws — returns a populated report with `error` fields. * * @param projectPath - Absolute path to the project root (as stored in * `project_registry.project_path`). * @param projectHash - 12-char project hash (as stored in * `project_registry.project_hash`). * @returns Fully populated {@link ProjectHealthReport}. * * @example * ```typescript * const report = await checkProjectHealth('/my/project', 'abcdef012345'); * if (report.overall !== 'healthy') console.log(report.issues); * ``` */ export declare function checkProjectHealth(projectPath: string, projectHash: string): Promise; /** * Check the two global-tier databases (nexus.db, signaldock.db) under * `getCleoHome()`. Never throws. * * Safe to call before `cleo init` — missing global DBs yield an `unknown` * verdict rather than a failure. * * @returns Populated {@link GlobalHealthReport}. */ export declare function checkGlobalHealth(): Promise; /** * Load every registered project from `nexus.db` and probe each one. Never * throws — if `nexus.db` is not initialized, returns a report with an empty * projects list. * * On success (and when `opts.updateRegistry` is true, the default), writes * the computed {@link ProjectHealthReport.overall} back to * `project_registry.health_status` and bumps `last_seen`. * * @param opts - See {@link CheckAllOptions}. * @returns Aggregated {@link FullHealthReport}. * * @example * ```typescript * const full = await checkAllRegisteredProjects({ parallelism: 4 }); * console.log(`${full.summary.degraded} project(s) degraded`); * ``` */ export declare function checkAllRegisteredProjects(opts?: CheckAllOptions): Promise; /** * Resolve the parent directory of a DB path — used by higher-level callers * (e.g. the doctor CLI) to check free space. Local helper; not part of the * public contract. * * @internal */ export declare function _parentDirOf(dbPath: string): string; //# sourceMappingURL=project-health.d.ts.map