/** * Doctor command — One-command diagnosis of all provider configurations. * * Usage: * buff doctor — Run full health check on all providers * buff doctor --provider groq — Check only a specific provider * buff doctor --watch — Continuous monitoring mode (refreshes every 30s) * buff doctor --verbose — Show detailed diagnostic info * buff doctor --fix — Attempt auto-fix for common issues (create ~/.buff dirs, etc.) * * The health check runs all provider tests in parallel with timeouts: * 1. API Key presence check * 2. Endpoint reachability check * 3. Provider availability check (isAvailable()) * 4. Model listing check * 5. Quick generation test (optional, with --verbose) * * Each test returns a status: ✅ PASS, ⚠️ WARN, ❌ FAIL * With fix suggestions for common failure modes. */ import { Command } from 'commander'; import { BaseCommand } from './commands.js'; import type { BuffConfig } from '../config/types.js'; import { ConfigManager } from '../config/manager.js'; export type HealthStatus = 'pass' | 'warn' | 'fail'; export interface CheckResult { name: string; status: HealthStatus; message: string; detail?: string; fix?: string; } export interface ProviderHealth { providerType: string; displayName: string; configured: boolean; checks: CheckResult[]; overallStatus: HealthStatus; } export interface DoctorReport { timestamp: number; system: CheckResult[]; providers: ProviderHealth[]; durationMs: number; } /** * Result of the P5 M5.1 sidecar probe (`${getCliName()} doctor --nuvira`). * * The probe checks an external OpenAI-compatible gateway the way a gateway * consumer should: GET {base}/models (reachability + model list), then a * best-effort GET {base}/version (many gateways expose one — liteLLM serves * it at the root, i.e. {baseWithoutV1}/version). */ export interface NuviraSidecarProbe { /** 'pass' when /models answers 200; 'fail' when unreachable/HTTP error. */ status: HealthStatus; /** Number of models the gateway lists (0 when unreachable or empty list). */ modelCount: number; /** Gateway version string when the /version probe succeeds, else null. */ version: string | null; /** The base URL probed. */ baseUrl: string; /** Error message when status is 'fail' (or a partial failure like a bad version probe). */ error?: string; } /** * Probe the Nuvira sidecar gateway (P5 M5.1). Pure + unit-testable: talks * only over HTTP to the given base URL, never touches global state. * * @param baseUrl Gateway base URL, default http://127.0.0.1:20128/v1 * @param timeoutMs Per-request timeout (default 5000ms) * @param apiKey Optional gateway auth token (from providers.nuvira.apiKey) — * production gateways require one; the probe honors it. */ export declare function probeNuviraSidecar(baseUrl?: string, timeoutMs?: number, apiKey?: string): Promise; /** * Audit integrity check for a JSONL telemetry/audit file: every line must * parse as JSON (append-only, tamper-evident shape). Corrupt lines indicate a * truncated write or manual tampering. Pure + unit-testable. */ export declare function auditJsonlIntegrity(filePath: string): { total: number; corrupt: number; }; /** * Secrets-hygiene check: for each keyed provider, is the key supplied via a * secure env var (or a `~/.buff/.env` file) rather than hardcoded in the * plaintext `~/.buff/buffconfig.json`? Pure + testable (env passed in). */ export declare function checkSecretsBackend(config: BuffConfig, env: Record): CheckResult; /** * One provider's gateway usage-health flags (M7.4). Aggregated from the * quota ledger + cost tracker — NEVER from captured prompt content. */ export interface GatewayUsageFlags { provider: string; /** Total requests tracked for this provider (quota ledger). */ requests: number; /** Total tokens consumed for this provider (quota ledger). */ tokens: number; /** Estimated spend in USD (cost tracker). */ costUsd: number; /** Whether the provider is currently parked (window exhausted / cooldown). */ parked: boolean; /** Ms until the current window resets (0 when not parked). */ resetsInMs: number; } /** Aggregate gateway usage-health view (M7.4), fed to checkGatewayTelemetry. */ export interface GatewayUsage { /** Per-provider health flags, sorted by provider name. */ providers: GatewayUsageFlags[]; /** Sum of requests across all tracked providers. */ totalRequests: number; /** Sum of tokens across all tracked providers. */ totalTokens: number; /** Sum of estimated spend in USD across all tracked providers. */ totalCostUsd: number; } /** * M7.4 telemetry/usage-health check. OPT-IN AND OFF BY DEFAULT: privacy- * preserving by construction — the numbers come from aggregate quota/cost * tracking, never prompt content. When the flag is off (default) the check is * an INFORMATIVE warn with the exact enable command, never a failure; when on * it reports the aggregate headline, plus per-provider health flags when * `healthFlags` is also enabled. */ export declare function checkGatewayTelemetry(config: BuffConfig, usage: GatewayUsage): CheckResult; /** * Build the M7.4 aggregate gateway-usage view from the quota ledger + cost * tracker singletons (aggregate counts only — never prompt content). * Best-effort: any read failure degrades to an empty usage view. * * @param configManager When provided, its `routing.quota` limits are used to * compute quota-configured parking (window exhausted), so the per-provider * health flags show parked state accurately. */ export declare function buildGatewayUsage(configManager?: import('../config/manager.js').ConfigManager): GatewayUsage; /** * P6 M6.3 chain-integrity check, built from a pure verify result (callers * run `verifyAuditFile` — this function never touches the filesystem). * Legacy pre-chain stores verify as a WARN (records readable; chain starts on * the next write); broken chains are a FAIL with the exact tamper line. */ /** * P6 M6.6 supply-chain check: does the installed dependency set match what a * generated SBOM claims? Pure core — the caller passes a pre-built verify * result (file I/O lives in runDiagnosis). Drift/tamper → fail; flagged * copyleft/unknown licenses → warn (compliance review, not a defect); a * missing lockfile → warn (can't bill-of-material). */ export declare function checkSbomSupplyChain(verify: { ok: boolean; added: string[]; removed: string[]; changed: Array<{ name: string; }>; flaggedLicenses: Array<{ name: string; license: string; }>; } | null, lockfilePresent: boolean): CheckResult; export declare function checkAuditChainIntegrity(name: string, verify: { totalLines: number; legacyLines: number; corruptLines: number; tamperLine: number; verdict: string; }): CheckResult; /** * The full M7.1 enterprise self-check, built from pure inputs so it is * trivially testable: config snapshot + env + gateway probe result + audit * file paths + opt-in gateway usage (M7.4). Returns the ordered CheckResult[] * the CLI renders. */ export declare function buildEnterpriseChecks(inputs: { config: BuffConfig; env: Record; gatewayProbe: NuviraSidecarProbe | null; gatewayConfigured: boolean; auditFiles: Array<{ name: string; path: string; }>; /** M7.4 opt-in gateway usage-health flags (default: empty = no tracked usage). */ gatewayUsage?: GatewayUsage; /** * P6 M6.3 pre-computed chain-verify results (pure core, file I/O done by * the caller) — keyed by audit-file name. When present, an extra chain * integrity check per audit file is appended after the JSONL-integrity one. */ auditChains?: Array<{ name: string; result: { totalLines: number; legacyLines: number; corruptLines: number; tamperLine: number; verdict: string; }; }>; /** * P6 M6.6 pre-computed SBOM verify result (pure core, file I/O done by the * caller). Undefined → the supply-chain check is skipped (keeps non- * enterprise doctor runs unchanged). */ sbomVerify?: { ok: boolean; added: string[]; removed: string[]; changed: Array<{ name: string; }>; flaggedLicenses: Array<{ name: string; license: string; }>; } | null; /** Whether package-lock.json exists in the project root (for the warn path). */ lockfilePresent?: boolean; }): CheckResult[]; export declare function runSystemChecks(configManager: ConfigManager): Promise; /** * The shared all-checks composition (dashboard command-runner + `${getCliName()} doctor * --enterprise`): system checks + the enterprise self-check. One source — the * dashboard's /api/admin/checks and the CLI render the SAME checks. */ export declare function runAllChecks(configManager: ConfigManager): Promise<{ system: CheckResult[]; enterprise: CheckResult[]; }>; /** * Build the P7 M7.1 enterprise self-check (gateway, secrets backend, audit * chains, SBOM posture, governance) as pure CheckResults — shared between the * CLI (--enterprise) and the dashboard command-runner. */ export declare function runEnterpriseChecks(configManager: ConfigManager): Promise; export declare class DoctorCommand extends BaseCommand { create(): Command; private runDiagnosis; private runWatchMode; private checkProvider; private renderSystemSection; private renderEnterpriseSection; private renderNuviraSidecarSection; private renderProviderSection; private renderSummary; private autoFix; private statusIcon; private hasApiKey; private createProvider; private getEnvVarName; private getDefaultModel; private getFixSuggestion; private getEndpointFailureDetail; private getEndpointFix; private getGenerationFix; private calculateOverallStatus; private withTimeout; } //# sourceMappingURL=doctor.d.ts.map