#!/usr/bin/env node
import {
  __require,
  analyzeUnified,
  scoreUnified
} from "./chunk-7K3CNS6C.mjs";

// src/cli.ts
import { Command } from "commander";
import { readFileSync as readFileSync4 } from "fs";
import { join, dirname } from "path";
import { fileURLToPath } from "url";

// src/commands/scan.ts
import chalk3 from "chalk";
import { writeFileSync, readFileSync as readFileSync2 } from "fs";
import { resolve as resolvePath3 } from "path";
import {
  loadMergedConfig,
  handleJSONOutput,
  handleCLIError as handleCLIError2,
  resolveOutputPath,
  formatScore,
  calculateTokenBudget,
  estimateCostFromBudget,
  getModelPreset,
  getRating,
  getRepoMetadata,
  Severity,
  ToolName
} from "@aiready/core";

// src/utils/helpers.ts
import { resolve as resolvePath } from "path";
import { existsSync, readdirSync, statSync, readFileSync } from "fs";
import chalk from "chalk";
function getReportTimestamp() {
  const now = /* @__PURE__ */ new Date();
  const pad = (n) => String(n).padStart(2, "0");
  return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
}
function findLatestScanReport(dirPath) {
  const aireadyDir = resolvePath(dirPath, ".aiready");
  if (!existsSync(aireadyDir)) {
    return null;
  }
  let files = readdirSync(aireadyDir).filter(
    (f) => f.startsWith("aiready-report-") && f.endsWith(".json")
  );
  if (files.length === 0) {
    files = readdirSync(aireadyDir).filter(
      (f) => f.startsWith("aiready-scan-") && f.endsWith(".json")
    );
  }
  if (files.length === 0) {
    return null;
  }
  const sortedFiles = files.map((f) => ({
    name: f,
    path: resolvePath(aireadyDir, f),
    mtime: statSync(resolvePath(aireadyDir, f)).mtime
  })).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
  return sortedFiles[0].path;
}
async function warnIfGraphCapExceeded(report, dirPath) {
  try {
    const { loadConfig: loadConfig4 } = await import("@aiready/core");
    void loadConfig4;
    let graphConfig = { maxNodes: 400, maxEdges: 600 };
    const configPath = resolvePath(dirPath, "aiready.json");
    if (existsSync(configPath)) {
      try {
        const rawConfig = JSON.parse(readFileSync(configPath, "utf8"));
        if (rawConfig.visualizer?.graph) {
          graphConfig = {
            maxNodes: rawConfig.visualizer.graph.maxNodes ?? graphConfig.maxNodes,
            maxEdges: rawConfig.visualizer.graph.maxEdges ?? graphConfig.maxEdges
          };
        }
      } catch (err) {
        void err;
      }
    }
    const nodeCount = (report.context?.length || 0) + (report.patterns?.length || 0);
    const edgeCount = report.context?.reduce((sum, ctx) => {
      const relCount = ctx.relatedFiles?.length || 0;
      const depCount = ctx.dependencies?.length || 0;
      return sum + relCount + depCount;
    }, 0) || 0;
    if (nodeCount > graphConfig.maxNodes || edgeCount > graphConfig.maxEdges) {
      console.log("");
      console.log(
        chalk.yellow(`\u26A0\uFE0F  Graph may be truncated at visualization time:`)
      );
      if (nodeCount > graphConfig.maxNodes) {
        console.log(
          chalk.dim(`   \u2022 Nodes: ${nodeCount} > limit ${graphConfig.maxNodes}`)
        );
      }
      if (edgeCount > graphConfig.maxEdges) {
        console.log(
          chalk.dim(`   \u2022 Edges: ${edgeCount} > limit ${graphConfig.maxEdges}`)
        );
      }
      console.log(chalk.dim(`   To increase limits, add to aiready.json:`));
      console.log(chalk.dim(`   {`));
      console.log(chalk.dim(`     "visualizer": {`));
      console.log(
        chalk.dim(`       "graph": { "maxNodes": 2000, "maxEdges": 5000 }`)
      );
      console.log(chalk.dim(`     }`));
      console.log(chalk.dim(`   }`));
    }
  } catch (err) {
    void err;
  }
}
function generateMarkdownReport(report, elapsedTime) {
  let markdown = `# Consistency Analysis Report

`;
  markdown += `**Generated:** ${(/* @__PURE__ */ new Date()).toISOString()}
`;
  markdown += `**Analysis Time:** ${elapsedTime}s

`;
  markdown += `## Summary

`;
  markdown += `- **Files Analyzed:** ${report.summary.filesAnalyzed}
`;
  markdown += `- **Total Issues:** ${report.summary.totalIssues}
`;
  markdown += `  - Naming: ${report.summary.namingIssues}
`;
  markdown += `  - Patterns: ${report.summary.patternIssues}

`;
  if (report.recommendations.length > 0) {
    markdown += `## Recommendations

`;
    report.recommendations.forEach((rec, i) => {
      markdown += `${i + 1}. ${rec}
`;
    });
  }
  return markdown;
}

// src/commands/upload.ts
import fs from "fs";
import { resolve as resolvePath2 } from "path";
import chalk2 from "chalk";
import { handleCLIError } from "@aiready/core";
async function uploadAction(file, options) {
  const startTime = Date.now();
  const filePath = resolvePath2(process.cwd(), file);
  const serverUrl = options.server || process.env.AIREADY_SERVER || "https://dev.platform.getaiready.dev";
  const apiKey = options.apiKey || process.env.AIREADY_API_KEY;
  if (!apiKey) {
    console.error(chalk2.red("\u274C API Key is required for upload."));
    console.log(
      chalk2.dim(
        "   Set AIREADY_API_KEY environment variable or use --api-key flag."
      )
    );
    console.log(
      chalk2.dim(
        "   Get an API key from https://platform.getaiready.dev/dashboard"
      )
    );
    process.exit(1);
  }
  if (!fs.existsSync(filePath)) {
    console.error(chalk2.red(`\u274C File not found: ${filePath}`));
    process.exit(1);
  }
  try {
    console.log(chalk2.blue(`\u{1F680} Uploading report to ${serverUrl}...`));
    console.log(chalk2.dim(`   Reading report from ${filePath}...`));
    const reportContent = fs.readFileSync(filePath, "utf-8");
    const reportData = JSON.parse(reportContent);
    console.log(chalk2.dim(`   Successfully parsed report JSON.`));
    const repoId = options.repoId || reportData.repository?.repoId;
    const res = await fetch(`${serverUrl}/api/analysis/upload`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${apiKey}`
      },
      body: JSON.stringify({
        data: reportData,
        repoId
        // Might be null, server will handle mapping
      })
    });
    const contentType = res.headers.get("content-type");
    let result = {};
    if (contentType?.includes("application/json")) {
      result = await res.json();
    } else {
      const text = await res.text();
      result = { error: text || res.statusText };
    }
    if (!res.ok) {
      console.error(
        chalk2.red(`\u274C Upload failed: ${result.error || res.statusText}`)
      );
      if (contentType?.includes("text/html")) {
        console.log(
          chalk2.yellow(
            "   Note: Received an HTML response. This often indicates a redirect (e.g., to a login page) or a server error."
          )
        );
        if (result.error?.includes("Redirecting")) {
          console.log(
            chalk2.dim(
              "   Detected redirect. Check if the API endpoint requires authentication or has changed."
            )
          );
        }
      }
      if (res.status === 401) {
        console.log(
          chalk2.dim("   Hint: Your API key may be invalid or expired.")
        );
      }
      process.exit(1);
    }
    const duration = ((Date.now() - startTime) / 1e3).toFixed(2);
    console.log(chalk2.green(`
\u2705 Upload successful! (${duration}s)`));
    console.log(chalk2.cyan(`   View results: ${serverUrl}/dashboard`));
    if (result.analysis) {
      console.log(chalk2.dim(`   Analysis ID: ${result.analysis.id}`));
      console.log(chalk2.dim(`   Score: ${result.analysis.aiScore}/100`));
    }
  } catch (error) {
    handleCLIError(error, "Upload");
  }
}
var uploadHelpText = `
EXAMPLES:
  $ aiready upload report.json --api-key ar_...
  $ aiready upload .aiready/latest.json
  $ AIREADY_API_KEY=ar_... aiready upload report.json

ENVIRONMENT VARIABLES:
  AIREADY_API_KEY    Your platform API key
  AIREADY_SERVER     Custom platform URL (default: https://dev.platform.getaiready.dev)
`;

// src/commands/scan.ts
async function scanAction(directory, options) {
  console.log(chalk3.blue("\u{1F680} Starting AIReady unified analysis...\n"));
  const startTime = Date.now();
  const resolvedDir = resolvePath3(process.cwd(), directory || ".");
  const repoMetadata = getRepoMetadata(resolvedDir);
  try {
    const defaults = {
      tools: [
        "pattern-detect",
        "context-analyzer",
        "naming-consistency",
        "ai-signal-clarity",
        "agent-grounding",
        "testability-index",
        "doc-drift",
        "dependency-health",
        "change-amplification"
      ],
      include: void 0,
      exclude: void 0,
      output: {
        format: "console",
        file: void 0
      }
    };
    let profileTools = options.tools ? options.tools.split(",").map((t) => t.trim()) : void 0;
    if (options.profile) {
      switch (options.profile.toLowerCase()) {
        case "agentic":
          profileTools = [
            ToolName.AiSignalClarity,
            ToolName.AgentGrounding,
            ToolName.TestabilityIndex
          ];
          break;
        case "cost":
          profileTools = [ToolName.PatternDetect, ToolName.ContextAnalyzer];
          break;
        case "security":
          profileTools = [
            ToolName.NamingConsistency,
            ToolName.TestabilityIndex
          ];
          break;
        case "onboarding":
          profileTools = [
            ToolName.ContextAnalyzer,
            ToolName.NamingConsistency,
            ToolName.AgentGrounding
          ];
          break;
        default:
          console.log(
            chalk3.yellow(
              `
\u26A0\uFE0F  Unknown profile '${options.profile}'. Using defaults.`
            )
          );
      }
    }
    const cliOverrides = {
      include: options.include?.split(","),
      exclude: options.exclude?.split(",")
    };
    if (profileTools) cliOverrides.tools = profileTools;
    const baseOptions = await loadMergedConfig(
      resolvedDir,
      defaults,
      cliOverrides
    );
    let finalOptions = { ...baseOptions };
    if (baseOptions.tools.includes(ToolName.PatternDetect) || baseOptions.tools.includes("patterns")) {
      const { getSmartDefaults } = await import("@aiready/pattern-detect");
      const patternSmartDefaults = await getSmartDefaults(
        resolvedDir,
        baseOptions
      );
      finalOptions = {
        ...patternSmartDefaults,
        ...finalOptions,
        ...baseOptions
      };
    }
    console.log(chalk3.cyan("\n=== AIReady Run Preview ==="));
    console.log(
      chalk3.white("Tools to run:"),
      (finalOptions.tools || []).join(", ")
    );
    const progressCallback = (event) => {
      if (event.message) {
        process.stdout.write(`\r\x1B[K   [${event.tool}] ${event.message}`);
        return;
      }
      process.stdout.write("\r\x1B[K");
      console.log(chalk3.cyan(`--- ${event.tool.toUpperCase()} RESULTS ---`));
      const res = event.data;
      if (res && res.summary) {
        if (res.summary.totalIssues !== void 0)
          console.log(`  Issues found: ${chalk3.bold(res.summary.totalIssues)}`);
        if (res.summary.score !== void 0)
          console.log(`  Tool Score: ${chalk3.bold(res.summary.score)}/100`);
        if (res.summary.totalFiles !== void 0)
          console.log(
            `  Files analyzed: ${chalk3.bold(res.summary.totalFiles)}`
          );
      }
    };
    const results = await analyzeUnified({
      ...finalOptions,
      progressCallback,
      onProgress: () => {
      },
      suppressToolConfig: true
    });
    console.log(chalk3.cyan("\n=== AIReady Run Summary ==="));
    console.log(
      `  Total issues (all tools): ${chalk3.bold(String(results.summary.totalIssues || 0))}`
    );
    let scoringResult;
    if (options.score || finalOptions.scoring?.showBreakdown) {
      scoringResult = await scoreUnified(results, finalOptions);
      console.log(chalk3.bold("\n\u{1F4CA} AI Readiness Overall Score"));
      console.log(`  ${formatScore(scoringResult)}`);
      if (options.compareTo) {
        try {
          const prevReport = JSON.parse(
            readFileSync2(resolvePath3(process.cwd(), options.compareTo), "utf8")
          );
          const prevScore = prevReport.scoring?.overall || prevReport.scoring?.score;
          if (typeof prevScore === "number") {
            const diff = scoringResult.overall - prevScore;
            const diffStr = diff > 0 ? `+${diff}` : String(diff);
            if (diff > 0)
              console.log(
                chalk3.green(
                  `  \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
                )
              );
            else if (diff < 0)
              console.log(
                chalk3.red(
                  `  \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
                )
              );
            else
              console.log(
                chalk3.blue(
                  `  \u2796 Trend: No change (${prevScore} \u2192 ${scoringResult.overall})`
                )
              );
          }
        } catch (e) {
          void e;
        }
      }
      const totalWastedDuplication = (scoringResult.breakdown || []).reduce(
        (sum, s) => sum + (s.tokenBudget?.wastedTokens.bySource.duplication || 0),
        0
      );
      const totalWastedFragmentation = (scoringResult.breakdown || []).reduce(
        (sum, s) => sum + (s.tokenBudget?.wastedTokens.bySource.fragmentation || 0),
        0
      );
      const totalContext = Math.max(
        ...(scoringResult.breakdown || []).map(
          (s) => s.tokenBudget?.totalContextTokens || 0
        ),
        0
      );
      if (totalContext > 0) {
        const unifiedBudget = calculateTokenBudget({
          totalContextTokens: totalContext,
          wastedTokens: {
            duplication: totalWastedDuplication,
            fragmentation: totalWastedFragmentation,
            chattiness: 0
          }
        });
        const modelPreset = getModelPreset(options.model || "claude-4.6");
        const costEstimate = estimateCostFromBudget(unifiedBudget, modelPreset);
        console.log(chalk3.bold("\n\u{1F4CA} AI Token Budget Analysis"));
        console.log(
          `  Efficiency: ${(unifiedBudget.efficiencyRatio * 100).toFixed(0)}%`
        );
        console.log(
          `  Wasted Tokens: ${chalk3.red(unifiedBudget.wastedTokens.total.toLocaleString())}`
        );
        console.log(
          `  Est. Monthly Cost (${modelPreset.name}): ${chalk3.bold("$" + costEstimate.total)}`
        );
        scoringResult.tokenBudget = unifiedBudget;
        scoringResult.costEstimate = {
          model: modelPreset.name,
          ...costEstimate
        };
      }
      if (scoringResult.breakdown) {
        console.log(chalk3.bold("\nTool breakdown:"));
        scoringResult.breakdown.forEach((tool) => {
          const rating = getRating(tool.score);
          console.log(`  - ${tool.toolName}: ${tool.score}/100 (${rating})`);
        });
      }
    }
    const mapToUnifiedReport = (res, scoring) => {
      const allResults = [];
      const totalFilesSet = /* @__PURE__ */ new Set();
      let criticalCount = 0;
      let majorCount = 0;
      res.summary.toolsRun.forEach((toolId) => {
        const spokeRes = res[toolId];
        if (!spokeRes || !spokeRes.results) return;
        spokeRes.results.forEach((r) => {
          totalFilesSet.add(r.fileName);
          allResults.push(r);
          r.issues?.forEach((i) => {
            if (i.severity === Severity.Critical) criticalCount++;
            if (i.severity === Severity.Major) majorCount++;
          });
        });
      });
      return {
        ...res,
        results: allResults,
        summary: {
          ...res.summary,
          totalFiles: totalFilesSet.size,
          criticalIssues: criticalCount,
          majorIssues: majorCount
        },
        scoring
      };
    };
    const outputData = {
      ...mapToUnifiedReport(results, scoringResult),
      repository: repoMetadata
    };
    const outputFormat = options.output || finalOptions.output?.format || "console";
    const outputPath = resolveOutputPath(
      options.outputFile || finalOptions.output?.file,
      `aiready-report-${getReportTimestamp()}.json`,
      resolvedDir
    );
    if (outputFormat === "json") {
      handleJSONOutput(
        outputData,
        outputPath,
        `\u2705 Report saved to ${outputPath}`
      );
    } else {
      try {
        writeFileSync(outputPath, JSON.stringify(outputData, null, 2));
        console.log(chalk3.dim(`\u2705 Report auto-persisted to ${outputPath}`));
      } catch (err) {
        void err;
      }
    }
    if (options.upload) {
      await uploadAction(outputPath, {
        apiKey: options.apiKey,
        server: options.server
      });
    }
    await warnIfGraphCapExceeded(outputData, resolvedDir);
    const isCI = options.ci || process.env.CI === "true";
    if (isCI && scoringResult) {
      const threshold = options.threshold ? parseInt(options.threshold) : void 0;
      const failOnLevel = options.failOn || "critical";
      let shouldFail = false;
      let failReason = "";
      if (threshold && scoringResult.overall < threshold) {
        shouldFail = true;
        failReason = `Score ${scoringResult.overall} < threshold ${threshold}`;
      }
      const report = mapToUnifiedReport(results, scoringResult);
      if (failOnLevel !== "none") {
        if (failOnLevel === "critical" && report.summary.criticalIssues > 0) {
          shouldFail = true;
          failReason = `Found ${report.summary.criticalIssues} critical issues`;
        } else if (failOnLevel === "major" && report.summary.criticalIssues + report.summary.majorIssues > 0) {
          shouldFail = true;
          failReason = `Found ${report.summary.criticalIssues} critical and ${report.summary.majorIssues} major issues`;
        }
      }
      if (shouldFail) {
        console.log(chalk3.red(`
\u{1F6AB} PR BLOCKED: ${failReason}`));
        process.exit(1);
      } else {
        console.log(chalk3.green("\n\u2705 PR PASSED"));
      }
    }
  } catch (error) {
    handleCLIError2(error, "Analysis");
  }
}
var scanHelpText = `...`;

// src/commands/patterns.ts
import chalk4 from "chalk";
import { resolve as resolvePath4 } from "path";
import {
  loadMergedConfig as loadMergedConfig2,
  handleJSONOutput as handleJSONOutput2,
  handleCLIError as handleCLIError3,
  getElapsedTime as getElapsedTime2,
  resolveOutputPath as resolveOutputPath2,
  formatToolScore as formatToolScore2
} from "@aiready/core";
async function patternsAction(directory, options) {
  console.log(chalk4.blue("\u{1F50D} Analyzing patterns...\n"));
  const startTime = Date.now();
  const resolvedDir = resolvePath4(process.cwd(), directory || ".");
  try {
    const useSmartDefaults = !options.fullScan;
    const defaults = {
      useSmartDefaults,
      include: void 0,
      exclude: void 0,
      output: {
        format: "console",
        file: void 0
      }
    };
    if (!useSmartDefaults) {
      defaults.minSimilarity = 0.4;
      defaults.minLines = 5;
    }
    const cliOptions = {
      minSimilarity: options.similarity ? parseFloat(options.similarity) : void 0,
      minLines: options.minLines ? parseInt(options.minLines) : void 0,
      useSmartDefaults,
      include: options.include?.split(","),
      exclude: options.exclude?.split(",")
    };
    if (options.maxCandidates) {
      cliOptions.maxCandidatesPerBlock = parseInt(options.maxCandidates);
    }
    if (options.minSharedTokens) {
      cliOptions.minSharedTokens = parseInt(options.minSharedTokens);
    }
    const finalOptions = await loadMergedConfig2(
      resolvedDir,
      defaults,
      cliOptions
    );
    const { analyzePatterns, generateSummary, calculatePatternScore } = await import("@aiready/pattern-detect");
    const { results, duplicates } = await analyzePatterns(finalOptions);
    const elapsedTime = getElapsedTime2(startTime);
    const summary = generateSummary(results);
    let patternScore;
    if (options.score) {
      patternScore = calculatePatternScore(duplicates, results.length);
    }
    const outputFormat = options.output || finalOptions.output?.format || "console";
    const userOutputFile = options.outputFile || finalOptions.output?.file;
    if (outputFormat === "json") {
      const outputData = {
        results,
        summary: { ...summary, executionTime: parseFloat(elapsedTime) },
        ...patternScore && { scoring: patternScore }
      };
      const outputPath = resolveOutputPath2(
        userOutputFile,
        `aiready-report-${getReportTimestamp()}.json`,
        resolvedDir
      );
      handleJSONOutput2(
        outputData,
        outputPath,
        `\u2705 Results saved to ${outputPath}`
      );
    } else {
      const terminalWidth = process.stdout.columns || 80;
      const dividerWidth = Math.min(60, terminalWidth - 2);
      const divider = "\u2501".repeat(dividerWidth);
      console.log(chalk4.cyan(divider));
      console.log(chalk4.bold.white("  PATTERN ANALYSIS SUMMARY"));
      console.log(chalk4.cyan(divider) + "\n");
      console.log(
        chalk4.white(`\u{1F4C1} Files analyzed: ${chalk4.bold(results.length)}`)
      );
      console.log(
        chalk4.yellow(
          `\u26A0  Duplicate patterns found: ${chalk4.bold(summary.totalPatterns)}`
        )
      );
      console.log(
        chalk4.red(
          `\u{1F4B0} Token cost (wasted): ${chalk4.bold(summary.totalTokenCost.toLocaleString())}`
        )
      );
      console.log(
        chalk4.gray(`\u23F1  Analysis time: ${chalk4.bold(elapsedTime + "s")}`)
      );
      const sortedTypes = Object.entries(summary.patternsByType || {}).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
      if (sortedTypes.length > 0) {
        console.log(chalk4.cyan("\n" + divider));
        console.log(chalk4.bold.white("  PATTERNS BY TYPE"));
        console.log(chalk4.cyan(divider) + "\n");
        sortedTypes.forEach(([type, count]) => {
          console.log(`  ${chalk4.white(type.padEnd(15))} ${chalk4.bold(count)}`);
        });
      }
      if (summary.totalPatterns > 0 && duplicates.length > 0) {
        console.log(chalk4.cyan("\n" + divider));
        console.log(chalk4.bold.white("  TOP DUPLICATE PATTERNS"));
        console.log(chalk4.cyan(divider) + "\n");
        const topDuplicates = [...duplicates].sort((a, b) => b.similarity - a.similarity).slice(0, 10);
        topDuplicates.forEach((dup) => {
          const severity = dup.similarity > 0.95 ? "CRITICAL" : dup.similarity > 0.9 ? "HIGH" : "MEDIUM";
          const severityIcon = dup.similarity > 0.95 ? "\u{1F534}" : dup.similarity > 0.9 ? "\u{1F7E1}" : "\u{1F535}";
          const file1Name = dup.file1.split("/").pop() || dup.file1;
          const file2Name = dup.file2.split("/").pop() || dup.file2;
          console.log(
            `${severityIcon} ${severity}: ${chalk4.bold(file1Name)} \u2194 ${chalk4.bold(file2Name)}`
          );
          console.log(
            `   Similarity: ${chalk4.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${chalk4.bold(dup.tokenCost.toLocaleString())} tokens each`
          );
          console.log(
            `   Lines: ${chalk4.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${chalk4.cyan(dup.line2 + "-" + dup.endLine2)}
`
          );
        });
      } else {
        console.log(
          chalk4.green("\n\u2728 Great! No duplicate patterns detected.\n")
        );
      }
      if (patternScore) {
        console.log(chalk4.cyan(divider));
        console.log(chalk4.bold.white("  AI READINESS SCORE (Patterns)"));
        console.log(chalk4.cyan(divider) + "\n");
        console.log(formatToolScore2(patternScore));
        console.log();
      }
    }
  } catch (error) {
    handleCLIError3(error, "Pattern analysis");
  }
}
var patternsHelpText = `
EXAMPLES:
  $ aiready patterns                                 # Default analysis
  $ aiready patterns --similarity 0.6               # Stricter matching
  $ aiready patterns --min-lines 10                 # Larger patterns only
`;

// src/commands/context.ts
import chalk5 from "chalk";
import { resolve as resolvePath5 } from "path";
import {
  loadMergedConfig as loadMergedConfig3,
  handleJSONOutput as handleJSONOutput3,
  handleCLIError as handleCLIError4,
  getElapsedTime as getElapsedTime3,
  resolveOutputPath as resolveOutputPath3,
  formatToolScore as formatToolScore3
} from "@aiready/core";
async function contextAction(directory, options) {
  console.log(chalk5.blue("\u{1F9E0} Analyzing context costs...\n"));
  const startTime = Date.now();
  const resolvedDir = resolvePath5(process.cwd(), directory || ".");
  try {
    const defaults = {
      maxDepth: 5,
      maxContextBudget: 1e4,
      include: void 0,
      exclude: void 0,
      output: {
        format: "console",
        file: void 0
      }
    };
    const baseOptions = await loadMergedConfig3(resolvedDir, defaults, {
      maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
      maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
      include: options.include?.split(","),
      exclude: options.exclude?.split(",")
    });
    let finalOptions = { ...baseOptions };
    const { getSmartDefaults } = await import("@aiready/context-analyzer");
    const contextSmartDefaults = await getSmartDefaults(
      resolvedDir,
      baseOptions
    );
    finalOptions = { ...contextSmartDefaults, ...finalOptions };
    console.log("\u{1F4CB} Configuration:");
    console.log(`   Max depth: ${finalOptions.maxDepth}`);
    console.log(`   Max context budget: ${finalOptions.maxContextBudget}`);
    console.log(
      `   Min cohesion: ${(finalOptions.minCohesion * 100).toFixed(1)}%`
    );
    console.log(
      `   Max fragmentation: ${(finalOptions.maxFragmentation * 100).toFixed(1)}%`
    );
    console.log(`   Analysis focus: ${finalOptions.focus}`);
    console.log("");
    const { analyzeContext, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
    const results = await analyzeContext(finalOptions);
    const elapsedTime = getElapsedTime3(startTime);
    const summary = generateSummary(results);
    let contextScore;
    if (options.score) {
      contextScore = calculateContextScore(summary);
    }
    const outputFormat = options.output || finalOptions.output?.format || "console";
    const userOutputFile = options.outputFile || finalOptions.output?.file;
    if (outputFormat === "json") {
      const outputData = {
        results,
        summary: { ...summary, executionTime: parseFloat(elapsedTime) },
        ...contextScore && { scoring: contextScore }
      };
      const outputPath = resolveOutputPath3(
        userOutputFile,
        `aiready-report-${getReportTimestamp()}.json`,
        resolvedDir
      );
      handleJSONOutput3(
        outputData,
        outputPath,
        `\u2705 Results saved to ${outputPath}`
      );
    } else {
      const terminalWidth = process.stdout.columns || 80;
      const dividerWidth = Math.min(60, terminalWidth - 2);
      const divider = "\u2501".repeat(dividerWidth);
      console.log(chalk5.cyan(divider));
      console.log(chalk5.bold.white("  CONTEXT ANALYSIS SUMMARY"));
      console.log(chalk5.cyan(divider) + "\n");
      console.log(
        chalk5.white(`\u{1F4C1} Files analyzed: ${chalk5.bold(summary.totalFiles)}`)
      );
      console.log(
        chalk5.white(
          `\u{1F4CA} Total tokens: ${chalk5.bold(summary.totalTokens.toLocaleString())}`
        )
      );
      console.log(
        chalk5.yellow(
          `\u{1F4B0} Avg context budget: ${chalk5.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
        )
      );
      console.log(
        chalk5.white(`\u23F1  Analysis time: ${chalk5.bold(elapsedTime + "s")}
`)
      );
      const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
      if (totalIssues > 0) {
        console.log(chalk5.bold("\u26A0\uFE0F  Issues Found:\n"));
        if (summary.criticalIssues > 0) {
          console.log(
            chalk5.red(`   \u{1F534} Critical: ${chalk5.bold(summary.criticalIssues)}`)
          );
        }
        if (summary.majorIssues > 0) {
          console.log(
            chalk5.yellow(`   \u{1F7E1} Major: ${chalk5.bold(summary.majorIssues)}`)
          );
        }
        if (summary.minorIssues > 0) {
          console.log(
            chalk5.blue(`   \u{1F535} Minor: ${chalk5.bold(summary.minorIssues)}`)
          );
        }
        console.log(
          chalk5.green(
            `
   \u{1F4A1} Potential savings: ${chalk5.bold(summary.totalPotentialSavings.toLocaleString())} tokens
`
          )
        );
      } else {
        console.log(chalk5.green("\u2705 No significant issues found!\n"));
      }
      if (summary.deepFiles.length > 0) {
        console.log(chalk5.bold("\u{1F4CF} Deep Import Chains:\n"));
        console.log(
          chalk5.gray(`   Average depth: ${summary.avgImportDepth.toFixed(1)}`)
        );
        console.log(
          chalk5.gray(`   Maximum depth: ${summary.maxImportDepth}
`)
        );
        summary.deepFiles.slice(0, 10).forEach((item) => {
          const fileName = item.file.split("/").slice(-2).join("/");
          console.log(
            `   ${chalk5.cyan("\u2192")} ${chalk5.white(fileName)} ${chalk5.dim(`(depth: ${item.depth})`)}`
          );
        });
        console.log();
      }
      if (summary.fragmentedModules.length > 0) {
        console.log(chalk5.bold("\u{1F9E9} Fragmented Modules:\n"));
        console.log(
          chalk5.gray(
            `   Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
`
          )
        );
        summary.fragmentedModules.slice(0, 10).forEach((module) => {
          console.log(
            `   ${chalk5.yellow("\u25CF")} ${chalk5.white(module.domain)} - ${chalk5.dim(`${module.files.length} files, ${(module.fragmentationScore * 100).toFixed(0)}% scattered`)}`
          );
          console.log(
            chalk5.dim(
              `     Token cost: ${module.totalTokens.toLocaleString()}, Cohesion: ${(module.avgCohesion * 100).toFixed(0)}%`
            )
          );
        });
        console.log();
      }
      if (summary.lowCohesionFiles.length > 0) {
        console.log(chalk5.bold("\u{1F500} Low Cohesion Files:\n"));
        console.log(
          chalk5.gray(
            `   Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
`
          )
        );
        summary.lowCohesionFiles.slice(0, 10).forEach((item) => {
          const fileName = item.file.split("/").slice(-2).join("/");
          const scorePercent = (item.score * 100).toFixed(0);
          const color = item.score < 0.4 ? chalk5.red : chalk5.yellow;
          console.log(
            `   ${color("\u25CB")} ${chalk5.white(fileName)} ${chalk5.dim(`(${scorePercent}% cohesion)`)}`
          );
        });
        console.log();
      }
      if (summary.topExpensiveFiles.length > 0) {
        console.log(chalk5.bold("\u{1F4B8} Most Expensive Files (Context Budget):\n"));
        summary.topExpensiveFiles.slice(0, 10).forEach((item) => {
          const fileName = item.file.split("/").slice(-2).join("/");
          const severityColor = item.severity === "critical" ? chalk5.red : item.severity === "major" ? chalk5.yellow : chalk5.blue;
          console.log(
            `   ${severityColor("\u25CF")} ${chalk5.white(fileName)} ${chalk5.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
          );
        });
        console.log();
      }
      if (contextScore) {
        console.log(chalk5.cyan(divider));
        console.log(chalk5.bold.white("  AI READINESS SCORE (Context)"));
        console.log(chalk5.cyan(divider) + "\n");
        console.log(formatToolScore3(contextScore));
        console.log();
      }
    }
  } catch (error) {
    handleCLIError4(error, "Context analysis");
  }
}

// src/commands/consistency.ts
import chalk6 from "chalk";
import { writeFileSync as writeFileSync2 } from "fs";
import { resolve as resolvePath6 } from "path";
import {
  loadMergedConfig as loadMergedConfig4,
  handleJSONOutput as handleJSONOutput4,
  handleCLIError as handleCLIError5,
  getElapsedTime as getElapsedTime4,
  resolveOutputPath as resolveOutputPath4,
  formatToolScore as formatToolScore4
} from "@aiready/core";
async function consistencyAction(directory, options) {
  console.log(chalk6.blue("\u{1F50D} Analyzing consistency...\n"));
  const startTime = Date.now();
  const resolvedDir = resolvePath6(process.cwd(), directory || ".");
  try {
    const defaults = {
      checkNaming: true,
      checkPatterns: true,
      minSeverity: "info",
      include: void 0,
      exclude: void 0,
      output: {
        format: "console",
        file: void 0
      }
    };
    const finalOptions = await loadMergedConfig4(resolvedDir, defaults, {
      checkNaming: options.naming !== false,
      checkPatterns: options.patterns !== false,
      minSeverity: options.minSeverity,
      include: options.include?.split(","),
      exclude: options.exclude?.split(",")
    });
    const { analyzeConsistency, calculateConsistencyScore } = await import("@aiready/consistency");
    const report = await analyzeConsistency(finalOptions);
    const elapsedTime = getElapsedTime4(startTime);
    let consistencyScore;
    if (options.score) {
      const issues = report.results?.flatMap((r) => r.issues) || [];
      consistencyScore = calculateConsistencyScore(
        issues,
        report.summary.filesAnalyzed
      );
    }
    const outputFormat = options.output || finalOptions.output?.format || "console";
    const userOutputFile = options.outputFile || finalOptions.output?.file;
    if (outputFormat === "json") {
      const outputData = {
        ...report,
        summary: {
          ...report.summary,
          executionTime: parseFloat(elapsedTime)
        },
        ...consistencyScore && { scoring: consistencyScore }
      };
      const outputPath = resolveOutputPath4(
        userOutputFile,
        `aiready-report-${getReportTimestamp()}.json`,
        resolvedDir
      );
      handleJSONOutput4(
        outputData,
        outputPath,
        `\u2705 Results saved to ${outputPath}`
      );
    } else if (outputFormat === "markdown") {
      const markdown = generateMarkdownReport(report, elapsedTime);
      const outputPath = resolveOutputPath4(
        userOutputFile,
        `aiready-report-${getReportTimestamp()}.md`,
        resolvedDir
      );
      writeFileSync2(outputPath, markdown);
      console.log(chalk6.green(`\u2705 Report saved to ${outputPath}`));
    } else {
      console.log(chalk6.bold("\n\u{1F4CA} Summary\n"));
      console.log(
        `Files Analyzed: ${chalk6.cyan(report.summary.filesAnalyzed)}`
      );
      console.log(`Total Issues: ${chalk6.yellow(report.summary.totalIssues)}`);
      console.log(`  Naming: ${chalk6.yellow(report.summary.namingIssues)}`);
      console.log(`  Patterns: ${chalk6.yellow(report.summary.patternIssues)}`);
      console.log(
        `  Architecture: ${chalk6.yellow(report.summary.architectureIssues || 0)}`
      );
      console.log(`Analysis Time: ${chalk6.gray(elapsedTime + "s")}
`);
      if (report.summary.totalIssues === 0) {
        console.log(
          chalk6.green(
            "\u2728 No consistency issues found! Your codebase is well-maintained.\n"
          )
        );
      } else {
        const namingResults = report.results.filter(
          (r) => r.issues.some((i) => i.category === "naming")
        );
        const patternResults = report.results.filter(
          (r) => r.issues.some((i) => i.category === "patterns")
        );
        if (namingResults.length > 0) {
          console.log(chalk6.bold("\u{1F3F7}\uFE0F  Naming Issues\n"));
          let shown = 0;
          for (const result of namingResults) {
            if (shown >= 5) break;
            for (const issue of result.issues) {
              if (shown >= 5) break;
              const severityColor = issue.severity === "critical" ? chalk6.red : issue.severity === "major" ? chalk6.yellow : issue.severity === "minor" ? chalk6.blue : chalk6.gray;
              console.log(
                `${severityColor(issue.severity.toUpperCase())} ${chalk6.dim(`${issue.location.file}:${issue.location.line}`)}`
              );
              console.log(`  ${issue.message}`);
              if (issue.suggestion) {
                console.log(
                  `  ${chalk6.dim("\u2192")} ${chalk6.italic(issue.suggestion)}`
                );
              }
              console.log();
              shown++;
            }
          }
          const remaining = namingResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
          if (remaining > 0) {
            console.log(chalk6.dim(`  ... and ${remaining} more issues
`));
          }
        }
        if (patternResults.length > 0) {
          console.log(chalk6.bold("\u{1F504} Pattern Issues\n"));
          let shown = 0;
          for (const result of patternResults) {
            if (shown >= 5) break;
            for (const issue of result.issues) {
              if (shown >= 5) break;
              const severityColor = issue.severity === "critical" ? chalk6.red : issue.severity === "major" ? chalk6.yellow : issue.severity === "minor" ? chalk6.blue : chalk6.gray;
              console.log(
                `${severityColor(issue.severity.toUpperCase())} ${chalk6.dim(`${issue.location.file}:${issue.location.line}`)}`
              );
              console.log(`  ${issue.message}`);
              if (issue.suggestion) {
                console.log(
                  `  ${chalk6.dim("\u2192")} ${chalk6.italic(issue.suggestion)}`
                );
              }
              console.log();
              shown++;
            }
          }
          const remaining = patternResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
          if (remaining > 0) {
            console.log(chalk6.dim(`  ... and ${remaining} more issues
`));
          }
        }
        if (report.recommendations.length > 0) {
          console.log(chalk6.bold("\u{1F4A1} Recommendations\n"));
          report.recommendations.forEach((rec, i) => {
            console.log(`${i + 1}. ${rec}`);
          });
          console.log();
        }
      }
      if (consistencyScore) {
        console.log(chalk6.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
        console.log(formatToolScore4(consistencyScore));
        console.log();
      }
    }
  } catch (error) {
    handleCLIError5(error, "Consistency analysis");
  }
}

// src/commands/visualize.ts
import chalk7 from "chalk";
import { writeFileSync as writeFileSync3, readFileSync as readFileSync3, existsSync as existsSync2, copyFileSync } from "fs";
import { resolve as resolvePath7 } from "path";
import { spawn } from "child_process";
import { handleCLIError as handleCLIError6 } from "@aiready/core";
import { generateHTML } from "@aiready/core";
async function visualizeAction(directory, options) {
  try {
    const dirPath = resolvePath7(process.cwd(), directory || ".");
    let reportPath = options.report ? resolvePath7(dirPath, options.report) : null;
    if (!reportPath || !existsSync2(reportPath)) {
      const latestScan = findLatestScanReport(dirPath);
      if (latestScan) {
        reportPath = latestScan;
        console.log(
          chalk7.dim(`Found latest report: ${latestScan.split("/").pop()}`)
        );
      } else {
        console.error(chalk7.red("\u274C No AI readiness report found"));
        console.log(
          chalk7.dim(
            `
Generate a report with:
  aiready scan --output json

Or specify a custom report:
  aiready visualise --report <path-to-report.json>`
          )
        );
        return;
      }
    }
    const raw = readFileSync3(reportPath, "utf8");
    const report = JSON.parse(raw);
    const configPath = resolvePath7(dirPath, "aiready.json");
    let graphConfig = { maxNodes: 400, maxEdges: 600 };
    if (existsSync2(configPath)) {
      try {
        const rawConfig = JSON.parse(readFileSync3(configPath, "utf8"));
        if (rawConfig.visualizer?.graph) {
          graphConfig = {
            maxNodes: rawConfig.visualizer.graph.maxNodes ?? graphConfig.maxNodes,
            maxEdges: rawConfig.visualizer.graph.maxEdges ?? graphConfig.maxEdges
          };
        }
      } catch (e) {
        void e;
      }
    }
    const envVisualizerConfig = JSON.stringify(graphConfig);
    process.env.AIREADY_VISUALIZER_CONFIG = envVisualizerConfig;
    console.log("Building graph from report...");
    const { GraphBuilder } = await import("@aiready/visualizer/graph");
    const graph = GraphBuilder.buildFromReport(report, dirPath);
    let useDevMode = options.dev || false;
    let devServerStarted = false;
    if (useDevMode) {
      try {
        const localWebDir = resolvePath7(dirPath, "packages/visualizer");
        let webDir = "";
        let visualizerAvailable = false;
        if (existsSync2(localWebDir)) {
          webDir = localWebDir;
          visualizerAvailable = true;
        } else {
          const nodemodulesLocations = [
            resolvePath7(dirPath, "node_modules", "@aiready", "visualizer"),
            resolvePath7(
              process.cwd(),
              "node_modules",
              "@aiready",
              "visualizer"
            )
          ];
          let currentDir = dirPath;
          while (currentDir !== "/" && currentDir !== ".") {
            nodemodulesLocations.push(
              resolvePath7(currentDir, "node_modules", "@aiready", "visualizer")
            );
            const parent = resolvePath7(currentDir, "..");
            if (parent === currentDir) break;
            currentDir = parent;
          }
          for (const location of nodemodulesLocations) {
            if (existsSync2(location) && existsSync2(resolvePath7(location, "package.json"))) {
              webDir = location;
              visualizerAvailable = true;
              break;
            }
          }
          if (!visualizerAvailable) {
            try {
              const vizPkgPath = __require.resolve("@aiready/visualizer/package.json");
              webDir = resolvePath7(vizPkgPath, "..");
              visualizerAvailable = true;
            } catch (err) {
              void err;
            }
          }
        }
        const webViteConfigExists = webDir && existsSync2(resolvePath7(webDir, "web", "vite.config.ts"));
        if (visualizerAvailable && webViteConfigExists) {
          const spawnCwd = webDir;
          const { watch } = await import("fs");
          const copyReportToViz = () => {
            try {
              const destPath = resolvePath7(spawnCwd, "web", "report-data.json");
              copyFileSync(reportPath, destPath);
              console.log(`\u{1F4CB} Report synced to ${destPath}`);
            } catch (e) {
              console.error("Failed to sync report:", e);
            }
          };
          copyReportToViz();
          let watchTimeout = null;
          const reportWatcher = watch(reportPath, () => {
            if (watchTimeout) clearTimeout(watchTimeout);
            watchTimeout = setTimeout(copyReportToViz, 100);
          });
          const envForSpawn = {
            ...process.env,
            AIREADY_REPORT_PATH: reportPath,
            AIREADY_VISUALIZER_CONFIG: envVisualizerConfig
          };
          const vite = spawn("pnpm", ["run", "dev:web"], {
            cwd: spawnCwd,
            stdio: "inherit",
            shell: true,
            env: envForSpawn
          });
          const onExit = () => {
            try {
              reportWatcher.close();
            } catch (err) {
              void err;
            }
            try {
              vite.kill();
            } catch (err) {
              void err;
            }
            process.exit(0);
          };
          process.on("SIGINT", onExit);
          process.on("SIGTERM", onExit);
          devServerStarted = true;
          void devServerStarted;
          return;
        } else {
          console.log(
            chalk7.yellow(
              "\u26A0\uFE0F  Dev server not available (requires local @aiready/visualizer with web assets)."
            )
          );
          console.log(
            chalk7.cyan("   Falling back to static HTML generation...\n")
          );
          useDevMode = false;
        }
      } catch (err) {
        console.error("Failed to start dev server:", err);
        console.log(
          chalk7.cyan("   Falling back to static HTML generation...\n")
        );
        useDevMode = false;
      }
    }
    console.log("Generating HTML...");
    const html = generateHTML(graph);
    const defaultOutput = "visualization.html";
    const outPath = resolvePath7(dirPath, options.output || defaultOutput);
    writeFileSync3(outPath, html, "utf8");
    console.log(chalk7.green(`\u2705 Visualization written to: ${outPath}`));
    if (options.open || options.serve) {
      const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
      if (options.serve) {
        try {
          const port = typeof options.serve === "number" ? options.serve : 5173;
          const http = await import("http");
          const fsp = await import("fs/promises");
          const server = http.createServer(async (req, res) => {
            try {
              const urlPath = req.url || "/";
              if (urlPath === "/" || urlPath === "/index.html") {
                const content = await fsp.readFile(outPath, "utf8");
                res.writeHead(200, {
                  "Content-Type": "text/html; charset=utf-8"
                });
                res.end(content);
                return;
              }
              res.writeHead(404, { "Content-Type": "text/plain" });
              res.end("Not found");
            } catch (e) {
              void e;
              res.writeHead(500, { "Content-Type": "text/plain" });
              res.end("Server error");
            }
          });
          server.listen(port, () => {
            const addr = `http://localhost:${port}/`;
            console.log(
              chalk7.cyan(`\u{1F310} Local visualization server running at ${addr}`)
            );
            spawn(opener, [`"${addr}"`], { shell: true });
          });
          process.on("SIGINT", () => {
            server.close();
            process.exit(0);
          });
        } catch (err) {
          console.error("Failed to start local server:", err);
        }
      } else if (options.open) {
        spawn(opener, [`"${outPath}"`], { shell: true });
      }
    }
  } catch (err) {
    handleCLIError6(err, "Visualization");
  }
}
var visualizeHelpText = `
EXAMPLES:
  $ aiready visualize .  # Auto-detects latest report, generates HTML
  $ aiready visualize . --report .aiready/aiready-report-20260217-143022.json
  $ aiready visualize . --report report.json -o out/visualization.html --open
  $ aiready visualize . --report report.json --serve
  $ aiready visualize . --report report.json --serve 8080
  $ aiready visualize . --report report.json --dev

NOTES:
  - The value passed to --report is interpreted relative to the directory argument (first positional).
    If the report is not found, the CLI will suggest running 'aiready scan' to generate it.
  - Default output path: visualization.html (in the current directory).
  - --serve starts a tiny single-file HTTP server (default port: 5173) and opens your browser.
  - --dev starts a Vite dev server with live reload (requires local @aiready/visualizer installation).
    When --dev is not available, it falls back to static HTML generation.
`;
var visualiseHelpText = `
EXAMPLES:
  $ aiready visualise .  # Auto-detects latest report
  $ aiready visualise . --report .aiready/aiready-report-20260217-143022.json
  $ aiready visualise . --report report.json --serve 8080

NOTES:
  - Same options as 'visualize'. Use --serve to host the static HTML, or --dev for live reload.
`;

// src/commands/ai-signal-clarity.ts
import chalk8 from "chalk";
import { loadConfig, mergeConfigWithDefaults } from "@aiready/core";

// src/commands/agent-grounding.ts
import chalk9 from "chalk";
import { loadConfig as loadConfig2, mergeConfigWithDefaults as mergeConfigWithDefaults2 } from "@aiready/core";

// src/commands/testability.ts
import chalk10 from "chalk";
import { loadConfig as loadConfig3, mergeConfigWithDefaults as mergeConfigWithDefaults3 } from "@aiready/core";

// src/commands/change-amplification.ts
import { changeAmplificationAction } from "@aiready/change-amplification/dist/cli.js";

// src/cli.ts
var getDirname = () => {
  if (typeof __dirname !== "undefined") return __dirname;
  return dirname(fileURLToPath(import.meta.url));
};
var packageJson = JSON.parse(
  readFileSync4(join(getDirname(), "../package.json"), "utf8")
);
var program = new Command();
program.name("aiready").description("AIReady - Assess and improve AI-readiness of codebases").version(packageJson.version).addHelpText(
  "after",
  `
AI READINESS SCORING:
  Get a 0-100 score indicating how AI-ready your codebase is.
  Use --score flag with any analysis command for detailed breakdown.

EXAMPLES:
  $ aiready scan                          # Comprehensive analysis of current directory
  $ aiready scan --score                  # Get AI Readiness Score (0-100)
  $ aiready scan --tools patterns         # Run only pattern detection
  $ npx @aiready/cli scan                 # Industry standard way to run standard scan
  $ aiready scan --output json            # Output raw JSON for piping

GETTING STARTED:
  1. Run 'aiready scan' to analyze your codebase
  2. Use 'aiready scan --score' for AI readiness assessment
  3. Create aiready.json for persistent configuration
  4. Set up CI/CD with '--threshold' for quality gates

CONFIGURATION:
  Config files (searched upward): aiready.json, .aiready.json, aiready.config.*
  CLI options override config file settings

  Example aiready.json:
  {
    "scan": { "exclude": ["**/dist/**", "**/node_modules/**"] },
    "tools": {
      "pattern-detect": { "minSimilarity": 0.5 },
      "context-analyzer": { "maxContextBudget": 15000 }
    },
    "output": { "format": "json", "directory": ".aiready" }
  }

VERSION: ${packageJson.version}
DOCUMENTATION: https://aiready.dev/docs/cli
GITHUB: https://github.com/caopengau/aiready-cli
LANDING: https://github.com/caopengau/aiready-landing`
);
program.command("scan").description(
  "Run comprehensive AI-readiness analysis (patterns + context + consistency)"
).argument("[directory]", "Directory to analyze", ".").option(
  "-t, --tools <tools>",
  "Tools to run (comma-separated: patterns,context,consistency,doc-drift,deps-health,aiSignalClarity,grounding,testability,changeAmplification)"
).option(
  "--profile <type>",
  "Scan profile to use (agentic, cost, security, onboarding)"
).option(
  "--compare-to <path>",
  "Compare results against a previous AIReady report JSON"
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option(
  "--no-score",
  "Disable calculating AI Readiness Score (enabled by default)"
).option("--weights <weights>", "Custom scoring weights").option("--threshold <score>", "Fail CI/CD if score below threshold (0-100)").option(
  "--ci",
  "CI mode: GitHub Actions annotations, no colors, fail on threshold"
).option(
  "--fail-on <level>",
  "Fail on issues: critical, major, any",
  "critical"
).option("--api-key <key>", "Platform API key for automatic upload").option("--upload", "Automatically upload results to the platform").option("--server <url>", "Custom platform URL").addHelpText("after", scanHelpText).action(async (directory, options) => {
  await scanAction(directory, options);
});
program.command("patterns").description("Detect duplicate code patterns that confuse AI models").argument("[directory]", "Directory to analyze", ".").option("-s, --similarity <number>", "Minimum similarity score (0-1)", "0.40").option("-l, --min-lines <number>", "Minimum lines to consider", "5").option(
  "--max-candidates <number>",
  "Maximum candidates per block (performance tuning)"
).option(
  "--min-shared-tokens <number>",
  "Minimum shared tokens for candidates (performance tuning)"
).option(
  "--full-scan",
  "Disable smart defaults for comprehensive analysis (slower)"
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option(
  "--score",
  "Calculate and display AI Readiness Score for patterns (0-100)"
).addHelpText("after", patternsHelpText).action(async (directory, options) => {
  await patternsAction(directory, options);
});
program.command("context").description("Analyze context window costs and dependency fragmentation").argument("[directory]", "Directory to analyze", ".").option("--max-depth <number>", "Maximum acceptable import depth", "5").option(
  "--max-context <number>",
  "Maximum acceptable context budget (tokens)",
  "10000"
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option(
  "--score",
  "Calculate and display AI Readiness Score for context (0-100)"
).action(async (directory, options) => {
  await contextAction(directory, options);
});
program.command("consistency").description("Check naming conventions and architectural consistency").argument("[directory]", "Directory to analyze", ".").option("--naming", "Check naming conventions (default: true)").option("--no-naming", "Skip naming analysis").option("--patterns", "Check code patterns (default: true)").option("--no-patterns", "Skip pattern analysis").option(
  "--min-severity <level>",
  "Minimum severity: info|minor|major|critical",
  "info"
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option(
  "-o, --output <format>",
  "Output format: console, json, markdown",
  "console"
).option("--output-file <path>", "Output file path (for json/markdown)").option(
  "--score",
  "Calculate and display AI Readiness Score for consistency (0-100)"
).action(async (directory, options) => {
  await consistencyAction(directory, options);
});
program.command("visualise").description("Alias for visualize (British spelling)").argument("[directory]", "Directory to analyze", ".").option(
  "--report <path>",
  "Report path (auto-detects latest .aiready/aiready-report-*.json if not provided)"
).option(
  "-o, --output <path>",
  "Output HTML path (relative to directory)",
  "packages/visualizer/visualization.html"
).option("--open", "Open generated HTML in default browser").option(
  "--serve [port]",
  "Start a local static server to serve the visualization (optional port number)",
  false
).option(
  "--dev",
  "Start Vite dev server (live reload) for interactive development",
  true
).addHelpText("after", visualiseHelpText).action(async (directory, options) => {
  await visualizeAction(directory, options);
});
program.command("visualize").description("Generate interactive visualization from an AIReady report").argument("[directory]", "Directory to analyze", ".").option(
  "--report <path>",
  "Report path (auto-detects latest .aiready/aiready-report-*.json if not provided)"
).option(
  "-o, --output <path>",
  "Output HTML path (relative to directory)",
  "packages/visualizer/visualization.html"
).option("--open", "Open generated HTML in default browser").option(
  "--serve [port]",
  "Start a local static server to serve the visualization (optional port number)",
  false
).option(
  "--dev",
  "Start Vite dev server (live reload) for interactive development",
  false
).addHelpText("after", visualizeHelpText).action(async (directory, options) => {
  await visualizeAction(directory, options);
});
program.command("change-amplification").description("Analyze graph metrics for change amplification").argument("[directory]", "Directory to analyze", ".").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").action(async (directory, options) => {
  await changeAmplificationAction(directory, options);
});
program.command("upload").description("Upload an AIReady report JSON to the platform").argument("<file>", "Report JSON file to upload").option("--api-key <key>", "Platform API key").option("--repo-id <id>", "Platform repository ID (optional)").option("--server <url>", "Custom platform URL").addHelpText("after", uploadHelpText).action(async (file, options) => {
  await uploadAction(file, options);
});
program.parse();
