/**
 * Legacy cloudflared tunnel adoption.
 *
 * Phase 1 of the "runtime credentials" rollout requires every agent to
 * operate against the profile-managed tunnel directory
 * (`~/.visionclaw/profiles/<profile>/tunnel/`) rather than the shared
 * user-level `~/.cloudflared/` directory. Before the onboarding service
 * can safely issue tunnel `credentialBundle` deliveries, every existing agent must
 * first be migrated so the two worlds don't overlap.
 *
 * This module performs a one-shot, file-level adoption:
 *   1. Read `~/.cloudflared/config.yml` to discover the tunnel UUID,
 *      credentials-file path, and ingress hostname used today.
 *   2. Copy the `{UUID}.json` credentials into the profile tunnel dir.
 *   3. Write a fresh profile `config.yml` that points at the copied
 *      credentials and preserves the existing hostname.
 *
 * Crucially, this module never touches Cloudflare's control plane
 * (no `cloudflared tunnel create`, no `tunnel route dns`). It also never
 * deletes the legacy `~/.cloudflared` files — they stay in place as a
 * safety net for repair / rollback until a later phase cleans them up.
 *
 * Idempotency:
 *   - If `probeLocalTunnelCredential()` already returns a valid snapshot,
 *     adoption is skipped (profile dir is the source of truth).
 *   - If any precondition fails, adoption is skipped — we never half-write
 *     the profile dir.
 */
import type { VisionClawConfig } from "../config/types.js";
export type AdoptionOutcome = {
    status: "adopted";
    tunnelId: string;
    tunnelName: string;
    hostname: string;
    hostnames: string[];
    /**
     * Every named ingress rule preserved from the legacy config, with
     * its per-rule `service` kept verbatim. This matters because agents
     * in the wild route multiple hostnames through a single tunnel to
     * different local ports (obs + other user services); collapsing
     * them onto a single service silently breaks the non-obs routes.
     */
    rules: {
        hostname: string;
        service: string;
    }[];
} | {
    status: "skipped";
    reason: AdoptionSkipReason;
};
export type AdoptionSkipReason = "already-profile-managed" | "tunnel-not-cloudflared" | "tunnel-name-missing" | "ops-claw-mini-tunnel-present" | "legacy-config-missing" | "legacy-config-unreadable" | "legacy-config-invalid" | "legacy-credentials-missing" | "legacy-credentials-unreadable" | "legacy-credentials-invalid" | "legacy-credentials-mismatch" | "hostname-missing" | "write-failed";
export interface AdoptLegacyTunnelOptions {
    /** Override the legacy cloudflared dir; primarily for tests. */
    legacyCloudflaredDir?: string;
}
export type LegacyCloudflaredArchiveResult = {
    status: "archived";
    archivePath: string;
    prunedDevIngressCount: number;
    dedupedIngressCount: number;
} | {
    status: "renamed";
    backupDir: string;
    prunedDevIngressCount: number;
    dedupedIngressCount: number;
} | {
    status: "skipped";
    reason: "missing";
    prunedDevIngressCount: 0;
    dedupedIngressCount: 0;
} | {
    status: "failed";
    reason: string;
    prunedDevIngressCount: number;
    dedupedIngressCount: number;
};
/**
 * Normalize the ingress section of a legacy `~/.cloudflared/config.yml` in
 * place so the about-to-be-archived file on disk is a faithful, deduplicated
 * snapshot of the hostnames the agent actually served. Two transformations
 * are applied, in order:
 *
 *   1. Drop every rule whose hostname ends in `.visionclawobs.dev` — those
 *      are historical DNS mistakes that were later superseded by the
 *      `.visionclawobs.com` canonical hostname.
 *   2. Collapse consecutive / repeated named hostnames (case-insensitive) to
 *      the first occurrence. This defends against a legacy config where an
 *      earlier in-place fix appended the `.com` rule alongside an existing
 *      duplicate instead of replacing it.
 *
 * Catch-all rules (no hostname, e.g. `service: http_status:404`) are
 * intentionally left untouched — they're always semantically equivalent in
 * our codebase and rewriting them would be out of scope for the user-
 * observed hostname duplication concern.
 *
 * Exported so unit tests can exercise the pure file-level transform without
 * depending on the archive/zip side effect (zip on some test environments
 * is not installed, and on success the directory is removed before tests
 * could read the normalized bytes back).
 */
export declare function normalizeLegacyIngress(legacyConfigPath: string): {
    prunedCount: number;
    dedupedCount: number;
};
export declare function archiveLegacyCloudflaredDir(legacyDir: string): LegacyCloudflaredArchiveResult;
/**
 * Run legacy → profile adoption if the preconditions are met.
 *
 * Returns a structured outcome so callers can log what happened. Never
 * throws: any unexpected failure degrades to a `skipped` outcome with the
 * narrowest reason we can determine.
 */
export declare function adoptLegacyTunnelIfNeeded(config: VisionClawConfig, opts?: AdoptLegacyTunnelOptions): AdoptionOutcome;
/**
 * Human-readable mapping for skip reasons. Kept separate so the adoption
 * result can be logged without string-shaping at every call site.
 */
export declare function describeAdoptionOutcome(outcome: AdoptionOutcome): string;
//# sourceMappingURL=legacy-tunnel-adoption.d.ts.map