#!/usr/bin/env tsx /** * Doctor — diagnostic checklist + readiness score for release-it-preset * * Inspects four categories: * 1. Environment — all known env vars, source (env vs default) * 2. Repository — git state (branch, tag, dirty WD, upstream) * 3. Configuration — CHANGELOG.md, .release-it.json, package.json * 4. Summary — READY / WARNINGS / BLOCKED + score * * Usage: * node dist/scripts/doctor.js * node dist/scripts/doctor.js --json */ import type { ExecSyncOptions } from 'node:child_process'; import { existsSync, readdirSync, readFileSync } from 'node:fs'; export type CheckStatus = 'PASS' | 'WARN' | 'FAIL'; export interface CheckResult { name: string; status: CheckStatus; value: string; detail?: string; } export interface EnvVarInfo { name: string; value: string | undefined; source: 'env' | 'default' | 'unset'; defaultValue?: string; } export interface EnvironmentSection { checks: CheckResult[]; vars: EnvVarInfo[]; status: CheckStatus; } export interface RepositorySection { checks: CheckResult[]; status: CheckStatus; } export interface ConfigurationSection { checks: CheckResult[]; status: CheckStatus; } export interface DoctorSummary { pass: number; warn: number; fail: number; total: number; score: string; status: 'READY' | 'WARNINGS' | 'BLOCKED'; recommendations: string[]; } export interface DoctorReport { environment: EnvironmentSection; repository: RepositorySection; configuration: ConfigurationSection; summary: DoctorSummary; } export interface DoctorDeps { execSync: (command: string, options?: ExecSyncOptions) => Buffer | string; existsSync: typeof existsSync; readdirSync: typeof readdirSync; readFileSync: typeof readFileSync; getEnv: (key: string) => string | undefined; cwd: () => string; } export declare function safeExec(command: string, deps: DoctorDeps): string | null; export declare function collectEnvironment(deps: DoctorDeps): EnvironmentSection; export declare function inspectRepository(deps: DoctorDeps): RepositorySection; export declare function validatePublishWorkflowFreshness(deps: DoctorDeps): CheckResult | null; export declare function workflowHasIdTokenWritePermission(content: string): boolean; export declare function validateNpmProvenanceReadiness(deps: DoctorDeps): CheckResult | null; export declare function validateWorkspaceDependencyRanges(deps: DoctorDeps): CheckResult | null; export declare function validateConfiguration(deps: DoctorDeps): ConfigurationSection; /** * Runs Check A (peer range satisfaction) and Check B (major version advisor). * Returns an array of CheckResult to be appended into validateConfiguration. * Check B is silently skipped when the npm registry is unreachable. */ export declare function validateReleaseItPeer(deps: DoctorDeps): CheckResult[]; export declare function summarize(report: Omit): DoctorSummary; export declare function runDoctor(deps: DoctorDeps): DoctorReport; export declare function formatHuman(report: DoctorReport): string; export declare function formatJson(report: DoctorReport): string;