#!/usr/bin/env node
/**
 * cli.ts — AILF CLI entry point.
 *
 * Unified command-line interface for the AI Literacy Framework.
 * All evaluation commands are exposed as subcommands under `ailf`.
 *
 * Commands are organized into semantic groups (Core Workflow, Analysis &
 * Reports, etc.) using Commander v14's native `helpGroup()` API. The
 * custom help formatter in `./commands/shared/help.ts` adds styling and
 * appends Quick Start examples.
 *
 * Usage:
 *   ailf run [flags]            # full evaluation run
 *   ailf compare [flags]        # compare evaluation runs
 *   ailf baseline <cmd> [flags] # baseline management
 *   ailf validate [flags]       # config validation
 *   ailf completion bash        # generate shell completions
 *   ailf --help                 # list all commands
 *
 * Global options:
 *   --verbose / -v              # increase log output
 *   --quiet / -q                # suppress non-error output
 *   --dotenv <path>             # override default .env path
 *
 * Dev mode (without building):
 *   tsx src/cli.ts run --debug
 *
 * Module split: this file owns *bootstrap side effects* (dotenv,
 * retired-flag/env/cmd checks, AILF_LOG_LEVEL pre-scan, parseAsync).
 * The Commander wiring lives in ./cli-program.ts so the W0078 M4 black-box
 * harness can build the program in-process without firing those side
 * effects.
 */
import { config as dotenvConfig } from "dotenv";
import { existsSync } from "fs";
import { dirname, resolve } from "path";
import { fileURLToPath } from "url";
import { buildCliProgram } from "./cli-program.js";
import { findExplicitDotenvArg } from "./lib/dotenv-resolution.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = resolve(__dirname, "..");
// ---------------------------------------------------------------------------
// Load .env — must happen before Commander parses so that .env()
// fallbacks resolve correctly.
//
// Resolution order:
//   1. Explicit --dotenv <path> flag
//   2. Monorepo root .env (../../.env relative to packages/eval/)
//   3. Caller's working directory .env
//
// This allows the CLI to work both in the monorepo (dev) and when
// installed globally via npm (production).
// ---------------------------------------------------------------------------
function resolveEnvPath() {
    const explicit = findExplicitDotenvArg();
    if (explicit)
        return explicit;
    // Monorepo root .env (dev mode)
    const monorepoEnv = resolve(ROOT, "..", "..", ".env");
    if (existsSync(monorepoEnv))
        return monorepoEnv;
    // Caller's working directory .env (npm install mode)
    const callerCwd = process.env.AILF_CALLER_CWD ?? process.cwd();
    return resolve(callerCwd, ".env");
}
const envPath = resolveEnvPath();
if (existsSync(envPath)) {
    dotenvConfig({ override: true, path: envPath });
}
// ---------------------------------------------------------------------------
// Pre-scan for --verbose / --quiet to make them available globally before
// Commander parses. Commands can check process.env.AILF_LOG_LEVEL.
// ---------------------------------------------------------------------------
if (process.argv.includes("--verbose") || process.argv.includes("-v")) {
    process.env.AILF_LOG_LEVEL = "verbose";
}
else if (process.argv.includes("--quiet") || process.argv.includes("-q")) {
    process.env.AILF_LOG_LEVEL = "quiet";
}
// ---------------------------------------------------------------------------
// Hard-error on retired flags, env vars, and commands with a migration hint.
// ---------------------------------------------------------------------------
// Each entry maps an old identifier to the message shown when it's seen, so
// failures don't bubble up as opaque "unknown option" errors from Commander.
// W0052 retired the legacy artifact collector; W0075 retired the --skip-*
// negation prefix, the --debug-{n,pattern,sample} filter flags, and several
// top-level report/validator commands that were consolidated into umbrellas.
// ---------------------------------------------------------------------------
const RETIRED_CAPTURE_HINT = "   Use --artifacts-dir / --no-artifacts / --artifacts-exclude instead.\n" +
    "   See docs/guides/cli-guide.md and docs/decisions/D0033-unified-run-anchored-artifact-capture.md.";
const RETIRED_FLAG_HINTS = {
    "--capture": RETIRED_CAPTURE_HINT,
    "--capture-dir": RETIRED_CAPTURE_HINT,
    "--no-capture-compress": RETIRED_CAPTURE_HINT,
    "--no-capture-extras": RETIRED_CAPTURE_HINT,
    "--capture-exclude": RETIRED_CAPTURE_HINT,
    "--skip-fetch": "   Use --no-fetch instead. See docs/design-docs/cli-naming-convention.md (W0075).",
    "--skip-eval": "   Use --no-eval instead. See docs/design-docs/cli-naming-convention.md (W0075).",
    "--debug-n": "   Use --filter-first-n instead. See docs/design-docs/cli-naming-convention.md (W0075).",
    "--debug-pattern": "   Use --filter-pattern instead. See docs/design-docs/cli-naming-convention.md (W0075).",
    "--debug-sample": "   Use --filter-sample instead. See docs/design-docs/cli-naming-convention.md (W0075).",
    "--output-format": "   Use --format instead. See docs/design-docs/cli-naming-convention.md (W0075).",
    "--artifacts-dry-run": "   Use --no-artifacts-write instead. See docs/design-docs/cli-naming-convention.md (W0075).",
    "--readiness": "   Use `ailf report readiness --from-run <path>` instead. See docs/design-docs/pipeline-command-surface.md (W0077).",
    "--discovery-report": "   Use `ailf report discovery --from-run <path>` instead. See docs/design-docs/pipeline-command-surface.md (W0077).",
    "--compare-baseline": "   Use `--compare <path>` instead. `--compare` now takes an optional baseline argument. See docs/design-docs/pipeline-command-surface.md (W0077).",
    "--before": "   Use --before-source instead. The flag was renamed to disambiguate from baseline comparison. See docs/design-docs/pipeline-command-surface.md (W0077).",
    "--concurrency": "   Set `execution.concurrency` in .ailf/config.yaml instead. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6b).",
    "--grader-replications": "   Set `execution.graderReplications` in .ailf/config.yaml instead. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6b).",
    "--no-gap-analysis": "   Set `execution.gapAnalysis: false` in .ailf/config.yaml instead. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6b).",
    "--api-url": "   Set `execution.apiUrl` in .ailf/config.yaml or use the AILF_API_URL env var. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6b).",
    "--report-dataset": "   Set `reportStore.dataset` in .ailf/config.yaml or use the AILF_REPORT_DATASET env var. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6e).",
    "--report-project": "   Set `reportStore.projectId` in .ailf/config.yaml or use the AILF_REPORT_PROJECT_ID env var. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6e).",
    "--owner-team": "   Set `owner.team` in .ailf/config.yaml or use the AILF_OWNER_TEAM env var. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6f).",
    "--owner-individual": "   Set `owner.individual` in .ailf/config.yaml or use the AILF_OWNER_INDIVIDUAL env var. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6f).",
    "--header": "   Set `agentic.headers` (key/value object) in .ailf/config.yaml or use the DOC_HEADERS env var. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6f).",
    "--allowed-origin": "   Set `agentic.allowedOrigins` (list of globs) in .ailf/config.yaml or use the DOC_ALLOWED_ORIGINS env var. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6f).",
    "--task-source": "   Set `taskSource.type` (content-lake | repo) in .ailf/config.yaml instead. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6h).",
    "--repo-tasks-path": "   Set `taskSource.repoTasksPath` in .ailf/config.yaml instead. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6h).",
};
const RETIRED_COMMAND_HINTS = {
    pipeline: "   Use `ailf run` instead. See docs/design-docs/pipeline-command-surface.md (W0077).",
    "validate-tasks": "   Use `ailf validate tasks` instead. See docs/design-docs/cli-naming-convention.md (W0075).",
    "readiness-report": "   Use `ailf report readiness` instead. See docs/design-docs/cli-naming-convention.md (W0075).",
    "chronic-failures": "   Use `ailf report chronic-failures` instead. See docs/design-docs/cli-naming-convention.md (W0075).",
    "coverage-audit": "   Use `ailf report coverage` instead. See docs/design-docs/cli-naming-convention.md (W0075).",
    "discovery-report": "   Use `ailf report discovery` instead. See docs/design-docs/cli-naming-convention.md (W0075).",
    "agent-report": "   Use `ailf report agent` instead. See docs/design-docs/cli-naming-convention.md (W0075).",
    "weekly-digest": "   Use `ailf report digest` instead. See docs/design-docs/cli-naming-convention.md (W0075).",
    "check-staleness": "   Use `ailf report staleness` instead. See docs/design-docs/cli-naming-convention.md (W0075).",
};
/**
 * Per-subcommand retired-flag hints. Use this for flags that were retired
 * from one subcommand but still exist on others (e.g. `--output-dir` is
 * retired from `ailf run` but still present on `ailf publish`,
 * `ailf pr-comment`, etc.). Keys are subcommand names; values share the
 * same shape as `RETIRED_FLAG_HINTS`.
 */
const RETIRED_FLAG_HINTS_BY_COMMAND = {
    run: {
        "--output-dir": "   Set `output.dir` in .ailf/config.yaml instead. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6c).",
        "--sanity-dataset": "   Set `source.dataset` in .ailf/config.yaml or use the SANITY_DATASET env var. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6d).",
        "--sanity-project": "   Set `source.projectId` in .ailf/config.yaml or use the SANITY_PROJECT_ID env var. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6d).",
        "--sanity-studio-origin": "   Set `source.studioOrigin` in .ailf/config.yaml or use the SANITY_STUDIO_ORIGIN env var. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6d).",
        "--no-artifacts": "   Set `artifacts.enabled: false` in .ailf/config.yaml instead. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6g).",
        "--artifacts-dir": "   Set `artifacts.dir` in .ailf/config.yaml or use the AILF_ARTIFACTS_DIR env var. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6g).",
        "--artifacts-exclude": "   Set `artifacts.exclude` (list of artifact-type names) in .ailf/config.yaml instead. See docs/design-docs/pipeline-command-surface.md (W0077 Phase 6g).",
    },
};
const RETIRED_ENV_VARS = [
    "AILF_CAPTURE",
    "AILF_CAPTURE_DIR",
    "AILF_CAPTURE_COMPRESS",
    "AILF_CAPTURE_EXTRAS",
    "AILF_CAPTURE_GCS_BUCKET",
    "AILF_CAPTURE_GCS_PREFIX",
    "AILF_LEGACY_COLLECTOR",
    "AILF_UNIFIED_ARTIFACTS",
];
/**
 * Identify the subcommand the user invoked — the first non-flag arg after
 * `ailf` (argv[0]=node, argv[1]=cli.ts). Returns undefined if none.
 */
function findInvokedSubcommand() {
    for (let i = 2; i < process.argv.length; i++) {
        const arg = process.argv[i];
        if (!arg.startsWith("-"))
            return arg;
    }
    return undefined;
}
function findRetiredFlag() {
    const subcommand = findInvokedSubcommand();
    const subcommandHints = subcommand
        ? RETIRED_FLAG_HINTS_BY_COMMAND[subcommand]
        : undefined;
    for (const arg of process.argv) {
        const bare = arg.split("=")[0];
        if (subcommandHints && bare in subcommandHints) {
            return { flag: bare, hint: subcommandHints[bare] };
        }
        if (bare in RETIRED_FLAG_HINTS) {
            return { flag: bare, hint: RETIRED_FLAG_HINTS[bare] };
        }
    }
    return undefined;
}
function findRetiredCommand() {
    // The first non-flag argument after `ailf` (argv[0]=node, argv[1]=cli.ts).
    for (let i = 2; i < process.argv.length; i++) {
        const arg = process.argv[i];
        if (!arg.startsWith("-") && arg in RETIRED_COMMAND_HINTS)
            return arg;
        if (!arg.startsWith("-"))
            return undefined;
    }
    return undefined;
}
function findRetiredEnv() {
    for (const name of RETIRED_ENV_VARS) {
        if (process.env[name] !== undefined)
            return name;
    }
    return undefined;
}
const retiredFlag = findRetiredFlag();
const retiredCommand = findRetiredCommand();
const retiredEnv = findRetiredEnv();
if (retiredFlag || retiredCommand || retiredEnv) {
    if (retiredFlag) {
        console.error(`❌ flag "${retiredFlag.flag}" was retired.`);
        console.error(retiredFlag.hint);
    }
    else if (retiredCommand) {
        console.error(`❌ command "${retiredCommand}" was retired.`);
        console.error(RETIRED_COMMAND_HINTS[retiredCommand]);
    }
    else if (retiredEnv) {
        console.error(`❌ environment variable "${retiredEnv}" was retired in W0052 along with the legacy artifact collector.`);
        console.error(RETIRED_CAPTURE_HINT);
    }
    process.exit(2);
}
// ---------------------------------------------------------------------------
// Build CLI program (delegates Commander wiring to ./cli-program.ts)
// ---------------------------------------------------------------------------
const program = buildCliProgram({ evalRoot: ROOT });
// ---------------------------------------------------------------------------
// Parse and run — default to showing help when no arguments given.
//
// The interactive wizard is still available via `ailf interactive`.
// ---------------------------------------------------------------------------
if (process.argv.length <= 2) {
    program.outputHelp();
}
else {
    await program.parseAsync();
}
