/**
 * Per-version, per-cwd resource diff for `agents doctor <agent[@version]>`.
 *
 * Mirrors what `syncResourcesToVersion` writes into a version home, then
 * compares each kind back against its resolved source (project > user > system
 * > extra repos). Surfaces:
 *   - ok       — present in home, content matches resolved source
 *   - diff     — present in home, content differs from resolved source
 *   - missing  — resolved source exists, not present in home
 *   - extra    — present in home, no source in any layer
 *
 * Coverage — every kind `syncResourcesToVersion` writes is content-aware, so a
 * byte change under an unchanged name is `diff`, never a false `ok` (PHNX-3504):
 *   commands, skills, hooks, rules — full content compare with source layer.
 *   mcp        — structural compare of the home server def vs resolved source.
 *   subagents  — re-render source through the registry transform, byte-compare.
 *   workflows  — layout-aware per-harness content compare (dir tree or file).
 *   memory     — knowledge facts (~/.agents/memory/*.md), per-fact byte-compare.
 *   plugins    — per-item content compare of the marketplace mirror.
 *   permissions — per-rule compare in the harness's native vocabulary for the
 *     representable harnesses (claude/opencode/cursor/droid/openclaw); the lossy
 *     TOML/flag harnesses stay presence-only with an honest `detail`, never a
 *     faked `ok`.
 * A completeness test binds `DOCTOR_ALL_KINDS` to the writer set so a future
 * synced kind cannot silently become a blind spot. `promptcuts` is NOT a kind —
 * it is not version-scoped, so there is nothing per-home to diff.
 *
 * Intentional asymmetries (must mirror sync):
 *   - hooks ignore the project layer (`syncResourcesToVersion` skips
 *     project/.agents/hooks/ for safety).
 *   - rules/AGENTS.md is compared against the preset composition the rules writer
 *     emits (`composeRulesFromState`), re-rendered from the current `subrules/`
 *     fragments — so a fragment edit is caught even though `rules/AGENTS.md`
 *     never changed. A non-@-import home compiled by `agents refresh-rules`
 *     carries a leading `COMPILED_HEADER`, which is stripped before comparing so
 *     a header-compiled home still reconciles (the header is not source content).
 */
import type { AgentId } from './types.js';
import type { DiscoveredPlugin } from './types.js';
import { type HookWiringReport } from './hooks/install.js';
import { type ResourceInventory } from './resource-inventory.js';
export type DoctorKind = 'commands' | 'skills' | 'hooks' | 'rules' | 'mcp' | 'permissions' | 'subagents' | 'plugins' | 'workflows' | 'memory';
export type DiffStatus = 'ok' | 'diff' | 'missing' | 'extra';
export type SourceLayer = 'project' | 'user' | 'system' | 'extra';
export interface ResourceDiff {
    kind: DoctorKind;
    name: string;
    status: DiffStatus;
    source?: SourceLayer;
    /** Absolute path to the resolved source file/dir (when source is known). */
    sourcePath?: string;
    /** Absolute path to the file/dir inside the version home (when present). */
    homePath?: string;
    /** Human-readable specifics for a divergent row — e.g. for a stale plugin:
     *  "0.6.1→0.7.0, missing skills: ship, learn". Currently set for plugins. */
    detail?: string;
}
/** A source layer (user / system / an extra repo) that is behind its upstream —
 *  reconciled against stale truth. Attached to the report by the doctor command
 *  (needs a git probe, kept out of the pure per-version diff). */
export interface SourceLayerBehind {
    layer: 'user' | 'system' | 'extra';
    /** Human label for the layer's on-disk root (e.g. `~/.agents`). */
    label: string;
    /** `agents repo pull` alias for the remediation hint. */
    alias: string;
    behind: number;
    /** Upstream ref the layer trails (e.g. `origin/main`). */
    branch: string;
}
export interface VersionResourceReport {
    agent: AgentId;
    version: string;
    home: string;
    cwd: string;
    layers: {
        project: string | null;
        user: string;
        system: string;
        extras: Array<{
            alias: string;
            dir: string;
        }>;
    };
    kinds: Record<DoctorKind, ResourceDiff[]>;
    summary: {
        ok: number;
        diff: number;
        missing: number;
        extra: number;
    };
    /** Wiring inspection for the version's native settings.json (claude/droid).
     *  Populated only when the `hooks` kind is in scope. */
    hookWiring?: HookWiringReport;
    /** Harness-scoped hook state from the shared inventory engine. */
    hookInventory?: ResourceInventory;
    /** Source layers behind their upstream. Filled by the doctor command (a git
     *  probe), not the pure diff — undefined when uncomputed. */
    sourceBehind?: SourceLayerBehind[];
}
/**
 * True when `filePath` is a git symlink that was CHECKED OUT AS A PLAIN TEXT
 * FILE — the shape git produces on a client without symlink support (Windows
 * without Developer Mode, `core.symlinks=false`). Such a file holds exactly the
 * link target (a relative path, no trailing newline) instead of the pointed-to
 * content. `lstat().isSymbolicLink()` is FALSE for it, so callers that only
 * skip real symlinks (e.g. the rules/permissions alias files CLAUDE.md /
 * GEMINI.md, which are symlinks to AGENTS.md in the repo) wrongly treat it as
 * an independent resource that no sync can ever reconcile (PHNX-3187). The
 * signal is unambiguous: a whole file with no newline whose entire content
 * resolves to an existing sibling path. Real markdown rule files always contain
 * newlines, so this never false-positives on genuine content.
 */
export declare function isCheckedOutSymlink(filePath: string): boolean;
/**
 * Describe how a version's marketplace MIRROR of a plugin diverges from its
 * central source — the detail presence-only checks miss. Surfaces a stale mirror
 * version, a Claude-invalid manifest, and (the part users care about) the
 * plugin's own skills/commands that never made it into the mirror. Returns null
 * when the mirror faithfully matches source.
 */
export declare function describePluginDrift(central: DiscoveredPlugin, mirrorDir: string): string | null;
export interface DiffOptions {
    cwd?: string;
    /** Restrict to specific kinds; undefined = all. */
    kinds?: DoctorKind[];
    /**
     * Drop the project (`<cwd>/.agents/`) layer from resolution. Used by the heal
     * path: the GLOBAL version home is only ever reconciled against user/system/
     * extra sources — project resources are layered at launch, never synced into
     * the global home, so counting them as "missing" there is a false gap.
     */
    excludeProject?: boolean;
}
export declare function diffVersionResources(agent: AgentId, version: string, options?: DiffOptions): VersionResourceReport;
export declare const DOCTOR_ALL_KINDS: DoctorKind[];
