import {
  DomainPackManifestSchema,
  PACK_MANIFEST_FILE_NAME,
  UTF8_ENCODING,
  computeDeterministicPackHash,
  isBroadWildcardScopePattern,
  resolvePackToolEntryPath,
  validateDomainPackToolSafety,
  validatePackImportBoundaries
} from "./chunk-HANJXVKW.js";
import {
  WU_OPTIONS,
  createWUParser,
  runCLI
} from "./chunk-2GXVIN57.js";

// src/pack-validate.ts
import { readFile } from "fs/promises";
import { join, resolve } from "path";
import YAML from "yaml";
var LOG_PREFIX = "[pack:validate]";
var DEFAULT_PACKS_ROOT = "packages/@lumenflow/packs";
var HTTPS_PROTOCOL = "https:";
var NETWORK_URL_PROPERTY = "url";
var SECURITY_LINT_ERROR = {
  PERMISSION_SCOPE_READ_WRITE: "permission/scope mismatch: read-permission tool cannot request write path access.",
  PERMISSION_SCOPE_WRITE_MISSING: "permission/scope mismatch: write-permission tool must include at least one write path scope.",
  WILDCARD_WRITE: "forbidden wildcard write scope. Replace with constrained path pattern (for example reports/**/*.md).",
  NETWORK_URL_REQUIRED: "network-scoped tools must constrain input_schema.properties.url via const/enum https URL allow-list.",
  NETWORK_URL_INVALID: "network-scoped tool has invalid URL in input_schema.properties.url.",
  NETWORK_URL_SCHEME: "network-scoped tool URL must use https:// in input_schema.properties.url."
};
async function validatePack(options) {
  const { packRoot, hashExclusions } = options;
  const absolutePackRoot = resolve(packRoot);
  let manifest;
  const manifestResult = await validateManifest(absolutePackRoot);
  if (manifestResult.status === "pass" && manifestResult.manifest) {
    manifest = manifestResult.manifest;
  }
  const toolEntriesResult = manifest ? validateToolEntries(absolutePackRoot, manifest) : { status: "skip", error: "Skipped: manifest validation failed" };
  const importBoundariesResult = await checkImportBoundaries(absolutePackRoot, hashExclusions);
  const securityLintResult = manifest ? runSecurityLint(manifest) : { status: "skip", error: "Skipped: manifest validation failed" };
  const integrityResult = await computeIntegrity(absolutePackRoot, hashExclusions);
  const allPassed = manifestResult.status === "pass" && toolEntriesResult.status === "pass" && importBoundariesResult.status === "pass" && securityLintResult.status === "pass" && integrityResult.status === "pass";
  return {
    manifest: manifestResult,
    importBoundaries: importBoundariesResult,
    toolEntries: toolEntriesResult,
    securityLint: securityLintResult,
    integrity: integrityResult,
    allPassed
  };
}
async function validateManifest(packRoot) {
  try {
    const manifestPath = join(packRoot, PACK_MANIFEST_FILE_NAME);
    const manifestRaw = await readFile(manifestPath, UTF8_ENCODING);
    const parsed = YAML.parse(manifestRaw);
    const manifest = DomainPackManifestSchema.parse(parsed);
    return { status: "pass", manifest };
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err);
    return { status: "fail", error: message };
  }
}
function validateToolEntries(packRoot, manifest) {
  try {
    for (const tool of manifest.tools) {
      resolvePackToolEntryPath(packRoot, tool.entry);
    }
    return { status: "pass" };
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err);
    return { status: "fail", error: message };
  }
}
async function checkImportBoundaries(packRoot, hashExclusions) {
  try {
    await validatePackImportBoundaries(packRoot, hashExclusions);
    return { status: "pass" };
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err);
    return { status: "fail", error: message };
  }
}
async function computeIntegrity(packRoot, hashExclusions) {
  try {
    const hash = await computeDeterministicPackHash({
      packRoot,
      exclusions: hashExclusions
    });
    return { status: "pass", hash };
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err);
    return { status: "fail", error: message };
  }
}
function isObjectRecord(value) {
  return typeof value === "object" && value !== null;
}
function extractNetworkUrls(tool) {
  const inputSchema = tool.input_schema;
  if (!isObjectRecord(inputSchema)) {
    return [];
  }
  const properties = inputSchema.properties;
  if (!isObjectRecord(properties)) {
    return [];
  }
  const urlSchema = properties[NETWORK_URL_PROPERTY];
  if (!isObjectRecord(urlSchema)) {
    return [];
  }
  if (typeof urlSchema.const === "string") {
    return [urlSchema.const];
  }
  if (!Array.isArray(urlSchema.enum)) {
    return [];
  }
  return urlSchema.enum.filter((candidate) => typeof candidate === "string");
}
function lintPermissionScopeConsistency(tool) {
  const pathScopes = tool.required_scopes.filter(
    (scope) => scope.type === "path"
  );
  const hasWritePathScope = pathScopes.some((scope) => scope.access === "write");
  const issues = [];
  if (tool.permission === "read" && hasWritePathScope) {
    issues.push(SECURITY_LINT_ERROR.PERMISSION_SCOPE_READ_WRITE);
  }
  if (tool.permission === "write" && pathScopes.length > 0 && !hasWritePathScope) {
    issues.push(SECURITY_LINT_ERROR.PERMISSION_SCOPE_WRITE_MISSING);
  }
  return issues;
}
function runSecurityLint(manifest) {
  const issues = /* @__PURE__ */ new Set();
  for (const tool of manifest.tools) {
    for (const issue of lintPermissionScopeConsistency(tool)) {
      issues.add(`Tool "${tool.name}": ${issue}`);
    }
    for (const issue of validateDomainPackToolSafety(tool)) {
      issues.add(`Tool "${tool.name}": ${issue}`);
    }
    const hasNetworkScope = tool.required_scopes.some((scope) => scope.type === "network");
    for (const scope of tool.required_scopes) {
      if (scope.type !== "path") {
        continue;
      }
      if ((tool.permission === "write" || tool.permission === "admin") && scope.access === "write" && isBroadWildcardScopePattern(scope.pattern)) {
        issues.add(`Tool "${tool.name}": ${SECURITY_LINT_ERROR.WILDCARD_WRITE}`);
      }
    }
    if (!hasNetworkScope) {
      continue;
    }
    const allowedUrls = extractNetworkUrls(tool);
    if (allowedUrls.length === 0) {
      issues.add(`Tool "${tool.name}": ${SECURITY_LINT_ERROR.NETWORK_URL_REQUIRED}`);
      continue;
    }
    for (const allowedUrl of allowedUrls) {
      let parsedUrl;
      try {
        parsedUrl = new URL(allowedUrl);
      } catch {
        issues.add(
          `Tool "${tool.name}" URL "${allowedUrl}": ${SECURITY_LINT_ERROR.NETWORK_URL_INVALID}`
        );
        continue;
      }
      if (parsedUrl.protocol !== HTTPS_PROTOCOL) {
        issues.add(
          `Tool "${tool.name}" URL "${allowedUrl}": ${SECURITY_LINT_ERROR.NETWORK_URL_SCHEME}`
        );
      }
    }
  }
  if (issues.size > 0) {
    return {
      status: "fail",
      error: [...issues].join("\n")
    };
  }
  return { status: "pass" };
}
var CHECK_LABELS = {
  manifest: "Manifest schema",
  importBoundaries: "Import boundaries",
  toolEntries: "Tool entry resolution",
  securityLint: "Security lint",
  integrity: "Integrity hash"
};
var STATUS_INDICATORS = {
  pass: "PASS",
  fail: "FAIL",
  skip: "SKIP"
};
function formatValidationReport(result) {
  const lines = [];
  lines.push("Pack Validation Report");
  lines.push("=====================");
  lines.push("");
  const checks = [
    ["manifest", result.manifest],
    ["importBoundaries", result.importBoundaries],
    ["toolEntries", result.toolEntries],
    ["securityLint", result.securityLint],
    ["integrity", result.integrity]
  ];
  for (const [key, check] of checks) {
    const label = CHECK_LABELS[key];
    const indicator = STATUS_INDICATORS[check.status];
    lines.push(`  [${indicator}] ${label}`);
    if (check.status === "fail" && check.error) {
      lines.push(`         Error: ${check.error}`);
    }
    if (key === "integrity" && "hash" in check && check.hash) {
      lines.push(`         Hash: sha256:${check.hash}`);
    }
  }
  lines.push("");
  lines.push(`Result: ${result.allPassed ? "ALL CHECKS PASSED" : "VALIDATION FAILED"}`);
  return lines.join("\n");
}
var PACK_VALIDATE_OPTIONS = {
  packId: {
    name: "id",
    flags: "--id <packId>",
    description: "Pack ID to validate (resolves under --packs-root)"
  },
  packsRoot: {
    name: "packsRoot",
    flags: "--packs-root <dir>",
    description: `Root directory containing packs (default: "${DEFAULT_PACKS_ROOT}")`
  },
  packRoot: {
    name: "packRoot",
    flags: "--pack-root <dir>",
    description: "Direct path to pack directory (overrides --id and --packs-root)"
  }
};
async function main() {
  const opts = createWUParser({
    name: "pack-validate",
    description: "Validate a LumenFlow domain pack for integrity",
    options: [
      PACK_VALIDATE_OPTIONS.packId,
      PACK_VALIDATE_OPTIONS.packsRoot,
      PACK_VALIDATE_OPTIONS.packRoot,
      WU_OPTIONS.force
    ]
  });
  const packId = opts.id;
  const packsRoot = opts.packsRoot ?? DEFAULT_PACKS_ROOT;
  const directPackRoot = opts.packRoot;
  let resolvedPackRoot;
  if (directPackRoot) {
    resolvedPackRoot = resolve(directPackRoot);
  } else if (packId) {
    resolvedPackRoot = resolve(packsRoot, packId);
  } else {
    console.error(`${LOG_PREFIX} Error: Provide --id <packId> or --pack-root <dir>`);
    process.exit(1);
  }
  console.log(`${LOG_PREFIX} Validating pack at: ${resolvedPackRoot}`);
  const result = await validatePack({ packRoot: resolvedPackRoot });
  const report = formatValidationReport(result);
  console.log(report);
  if (!result.allPassed) {
    process.exit(1);
  }
}
if (import.meta.main) {
  void runCLI(main);
}

export {
  LOG_PREFIX,
  validatePack,
  formatValidationReport,
  main
};
