import {
  scaffoldProject
} from "./chunk-A624LFLB.js";
import {
  runLaneHealthCheck
} from "./chunk-XKY65P2T.js";
import {
  LOG_TAIL_MAX_BYTES,
  LOG_TAIL_MAX_LINES
} from "./chunk-Y4CQZY65.js";
import {
  createWUParser,
  runCLI,
  validateClaimValidation
} from "./chunk-2GXVIN57.js";
import {
  createGitForPath,
  getGitForCwd
} from "./chunk-2UFQ3A3C.js";
import {
  emitGateEvent,
  getCurrentLane,
  getCurrentWU,
  syncNdjsonTelemetryToCloud
} from "./chunk-6XYXI2NQ.js";
import {
  runInvariants
} from "./chunk-EZ6ZBYBM.js";
import {
  readWURaw
} from "./chunk-NRIZR3A7.js";
import {
  createWuPaths
} from "./chunk-6HO4GWJE.js";
import {
  BRANCHES,
  CACHE_STRATEGIES,
  DIRECTORIES,
  EMOJI,
  ESLINT_COMMANDS,
  ESLINT_DEFAULTS,
  ESLINT_FLAGS,
  EXIT_CODES,
  FILE_SYSTEM,
  GATE_COMMANDS,
  GATE_NAMES,
  GIT_REFS,
  PACKAGES,
  PKG_MANAGER,
  PRETTIER_ARGS,
  PRETTIER_FLAGS,
  SCRIPTS,
  STRING_LITERALS
} from "./chunk-DWMLTXKQ.js";
import {
  CoChangeRuleConfigSchema,
  DEFAULT_MIN_COVERAGE,
  WORKSPACE_CONFIG_FILE_NAME,
  WORKSPACE_V2_KEYS,
  getGatesSection,
  loadLaneHealthConfig,
  resolveGatesCommands,
  resolveTestPolicy,
  resolveTestRunner
} from "./chunk-V6OJGLBA.js";
import {
  ErrorCodes,
  createError,
  die
} from "./chunk-RXRKBBSM.js";

// src/gates.ts
import { writeSync as writeSync3 } from "fs";

// ../core/dist/gates-agent-mode.js
import path from "path";
import { existsSync, unlinkSync, symlinkSync } from "fs";
function shouldUseGatesAgentMode({ argv, env, stdout } = {}) {
  const isVerbose = Array.isArray(argv) && argv.includes("--verbose");
  if (isVerbose) {
    return false;
  }
  const hasClaudeProjectDir = Boolean(env?.CLAUDE_PROJECT_DIR);
  if (hasClaudeProjectDir) {
    return true;
  }
  const isCI = Boolean(env?.CI);
  if (isCI) {
    return false;
  }
  const stdoutStream = stdout ?? process.stdout;
  const isTTY = stdoutStream?.isTTY ?? false;
  return !isTTY;
}
function getGatesLogDir({ cwd, env }) {
  const configured = env?.LUMENFLOW_LOG_DIR;
  return path.resolve(cwd, configured || ".logs");
}
function buildGatesLogPath({ cwd, env, wuId, lane, now = /* @__PURE__ */ new Date() }) {
  const logDir = getGatesLogDir({ cwd, env });
  const safeLane = (lane || "unknown").toLowerCase().replace(/[^a-z0-9]+/g, "-");
  const safeWu = (wuId || "unknown").toLowerCase().replace(/[^a-z0-9]+/g, "-");
  const stamp = now.toISOString().replace(/[:.]/g, "-");
  return path.join(logDir, `gates-${safeLane}-${safeWu}-${stamp}.log`);
}
function getGatesLatestSymlinkPath({ cwd, env }) {
  const logDir = getGatesLogDir({ cwd, env });
  return path.join(logDir, "gates-latest.log");
}
function updateGatesLatestSymlink({ logPath, cwd, env }) {
  const symlinkPath = getGatesLatestSymlinkPath({ cwd, env });
  try {
    if (existsSync(symlinkPath)) {
      unlinkSync(symlinkPath);
    }
    const logDir = path.dirname(symlinkPath);
    const relativePath = path.relative(logDir, logPath);
    symlinkSync(relativePath, symlinkPath);
    return true;
  } catch {
    return false;
  }
}
var WU_DONE_PRE_COMMIT_GATE_DECISION_REASONS = {
  SKIP_GATES_FLAG: "skip-gates-flag",
  REUSE_STEP_ZERO: "reuse-step-zero",
  REUSE_CHECKPOINT: "reuse-checkpoint",
  RUN_REQUIRED: "run-required"
};
function resolveWuDonePreCommitGateDecision(input) {
  if (input.skipGates) {
    return {
      runPreCommitFullSuite: false,
      reason: WU_DONE_PRE_COMMIT_GATE_DECISION_REASONS.SKIP_GATES_FLAG,
      message: "Pre-flight hook validation skipped because --skip-gates is active."
    };
  }
  if (input.fullGatesRanInCurrentRun) {
    return {
      runPreCommitFullSuite: false,
      reason: WU_DONE_PRE_COMMIT_GATE_DECISION_REASONS.REUSE_STEP_ZERO,
      message: "Pre-flight hook validation reuses Step 0 gate results; duplicate full-suite run skipped."
    };
  }
  if (input.skippedByCheckpoint) {
    const checkpointSuffix = input.checkpointId ? ` (${input.checkpointId})` : "";
    return {
      runPreCommitFullSuite: false,
      reason: WU_DONE_PRE_COMMIT_GATE_DECISION_REASONS.REUSE_CHECKPOINT,
      message: `Pre-flight hook validation reuses checkpoint gate attestation${checkpointSuffix}; duplicate full-suite run skipped.`
    };
  }
  return {
    runPreCommitFullSuite: true,
    reason: WU_DONE_PRE_COMMIT_GATE_DECISION_REASONS.RUN_REQUIRED,
    message: "No gate attestation found for this wu:done run; executing pre-flight hook gate suite."
  };
}

// ../core/dist/coverage-gate.js
import { readFileSync, existsSync as existsSync2 } from "fs";
var COVERAGE_GATE_MODES = Object.freeze({
  /** Log warnings but don't fail the gate */
  WARN: "warn",
  /** Fail the gate if thresholds not met */
  BLOCK: "block"
});
var HEX_CORE_PATTERNS = Object.freeze([
  "packages/@lumenflow/core/",
  "packages/@lumenflow/cli/"
]);
var COVERAGE_THRESHOLD = DEFAULT_MIN_COVERAGE;
var DEFAULT_COVERAGE_PATH = "coverage/coverage-summary.json";
function isHexCoreFile(filePath) {
  if (!filePath || typeof filePath !== "string") {
    return false;
  }
  const normalizedPath = filePath.replace(/\\/g, "/");
  return HEX_CORE_PATTERNS.some((pattern) => normalizedPath.includes(pattern));
}
function parseCoverageJson(coveragePath) {
  if (!existsSync2(coveragePath)) {
    return null;
  }
  try {
    const content = readFileSync(coveragePath, { encoding: "utf-8" });
    const data = JSON.parse(content);
    const files = {};
    for (const [key, value] of Object.entries(data)) {
      if (key === "total")
        continue;
      files[key] = value;
    }
    return {
      total: data.total,
      files
    };
  } catch {
    return null;
  }
}
function checkCoverageThresholds(coverageData, threshold) {
  if (!coverageData || !coverageData.files) {
    return { pass: true, failures: [] };
  }
  const effectiveThreshold = threshold ?? COVERAGE_THRESHOLD;
  const failures = [];
  for (const [file, metricsValue] of Object.entries(coverageData.files)) {
    if (!isHexCoreFile(file)) {
      continue;
    }
    const metrics = metricsValue;
    const linesCoverage = metrics.lines?.pct ?? 0;
    if (linesCoverage < effectiveThreshold) {
      failures.push({
        file,
        actual: linesCoverage,
        threshold: effectiveThreshold,
        metric: "lines"
      });
    }
  }
  return {
    pass: failures.length === 0,
    failures
  };
}
function formatCoverageDelta(coverageData) {
  if (!coverageData) {
    return "";
  }
  const lines = [];
  const totalPct = coverageData.total?.lines?.pct ?? 0;
  lines.push(`${STRING_LITERALS.NEWLINE}Coverage Summary: ${totalPct.toFixed(1)}% lines${STRING_LITERALS.NEWLINE}`);
  const hexCoreFiles = Object.entries(coverageData.files || {}).filter(([file]) => isHexCoreFile(file));
  if (hexCoreFiles.length > 0) {
    lines.push("Hex Core Files:");
    for (const [file, metricsValue] of hexCoreFiles) {
      const metrics = metricsValue;
      const pct = metrics.lines?.pct ?? 0;
      const status = pct >= COVERAGE_THRESHOLD ? EMOJI.SUCCESS : EMOJI.FAILURE;
      const shortFile = file.replace("packages/@lumenflow/", "");
      lines.push(`  ${status} ${shortFile}: ${pct.toFixed(1)}%`);
    }
  }
  return lines.join(STRING_LITERALS.NEWLINE);
}
async function runCoverageGate(options = {}) {
  const start = Date.now();
  const mode = options.mode || COVERAGE_GATE_MODES.WARN;
  const coveragePath = options.coveragePath || DEFAULT_COVERAGE_PATH;
  const logger = options.logger && typeof options.logger.log === "function" ? options.logger : console;
  const threshold = options.threshold ?? COVERAGE_THRESHOLD;
  const coverageData = parseCoverageJson(coveragePath);
  if (!coverageData) {
    const duration2 = Date.now() - start;
    logger.log(`
${EMOJI.WARNING} Coverage gate: No coverage data found at ${coveragePath}`);
    logger.log("  Run tests with coverage first: pnpm test:coverage\n");
    return { ok: true, mode, duration: duration2, message: "No coverage data" };
  }
  const { pass, failures } = checkCoverageThresholds(coverageData, threshold);
  const output = formatCoverageDelta(coverageData);
  logger.log(output);
  const duration = Date.now() - start;
  if (!pass) {
    logger.log(`
${EMOJI.FAILURE} Coverage below ${threshold}% for hex core files:`);
    for (const failure of failures) {
      const shortFile = failure.file.replace("packages/@lumenflow/", "");
      logger.log(`  - ${shortFile}: ${failure.actual.toFixed(1)}% (requires ${failure.threshold}%)`);
    }
    if (mode === COVERAGE_GATE_MODES.BLOCK) {
      logger.log(`
${EMOJI.FAILURE} Coverage gate FAILED (mode: block)
`);
      return { ok: false, mode, duration, message: "Coverage threshold not met" };
    } else {
      logger.log(`
${EMOJI.WARNING} Coverage gate WARNING (mode: warn)
`);
      logger.log("  Note: This will become blocking in future. Fix coverage now.\n");
      return { ok: true, mode, duration, message: "Coverage warning" };
    }
  }
  logger.log(`
${EMOJI.SUCCESS} Coverage gate passed
`);
  return { ok: true, mode, duration, message: "Coverage OK" };
}

// src/gates-graceful-degradation.ts
import { readFileSync as readFileSync2, existsSync as existsSync3 } from "fs";
import path2 from "path";
var NON_SKIPPABLE_GATES = ["invariants"];
function checkScriptExists(scriptName, scripts) {
  if (!scripts) return false;
  return Object.prototype.hasOwnProperty.call(scripts, scriptName);
}
function loadPackageJsonScripts(projectRoot) {
  const packageJsonPath = path2.join(projectRoot, "package.json");
  if (!existsSync3(packageJsonPath)) return void 0;
  try {
    const content = readFileSync2(packageJsonPath, "utf8");
    const pkg = JSON.parse(content);
    return pkg.scripts;
  } catch {
    return void 0;
  }
}
function buildMissingScriptWarning(scriptName) {
  const suggestions = {
    "format:check": '"format:check": "prettier --check ."',
    lint: '"lint": "eslint ."',
    typecheck: '"typecheck": "tsc --noEmit"',
    "spec:linter": '"spec:linter": "node tools/spec-linter.js"'
  };
  const suggestion = suggestions[scriptName] ?? `"${scriptName}": "<your-command>"`;
  return [
    `Warning: "${scriptName}" script not found in package.json - skipping gate.`,
    `  To enable this gate, add to your package.json scripts:`,
    `    ${suggestion}`
  ].join("\n");
}
function resolveGateAction(gateName, scriptName, scripts, strict) {
  if (NON_SKIPPABLE_GATES.includes(gateName)) {
    return "run";
  }
  if (!scriptName) {
    return "run";
  }
  if (checkScriptExists(scriptName, scripts)) {
    return "run";
  }
  if (strict) {
    return "fail";
  }
  return "skip";
}
function formatGateSummary(results) {
  if (results.length === 0) {
    return "No gates were executed.";
  }
  const passed = results.filter((r) => r.status === "passed");
  const skipped = results.filter((r) => r.status === "skipped");
  const failed = results.filter((r) => r.status === "failed");
  const warned = results.filter((r) => r.status === "warned");
  const lines = [];
  lines.push("Gate Summary:");
  lines.push("");
  for (const result of results) {
    const statusIcon = result.status === "passed" ? "PASS" : result.status === "skipped" ? "SKIP" : result.status === "warned" ? "WARN" : "FAIL";
    const duration = result.durationMs > 0 ? ` (${result.durationMs}ms)` : "";
    const reason = result.reason ? ` - ${result.reason}` : "";
    lines.push(`  [${statusIcon}] ${result.name}${duration}${reason}`);
  }
  lines.push("");
  const parts = [];
  if (passed.length > 0) parts.push(`${passed.length} passed`);
  if (skipped.length > 0) parts.push(`${skipped.length} skipped`);
  if (warned.length > 0) parts.push(`${warned.length} warned`);
  if (failed.length > 0) parts.push(`${failed.length} failed`);
  lines.push(parts.join(", "));
  return lines.join("\n");
}

// src/gates.ts
import chalk from "chalk";

// src/gate-registry.ts
var GateRegistry = class {
  gates = [];
  nameIndex = /* @__PURE__ */ new Map();
  /**
   * Register a single gate definition.
   *
   * @param gate - Gate definition to register
   * @throws Error if a gate with the same name is already registered
   */
  register(gate) {
    if (this.nameIndex.has(gate.name)) {
      throw createError(
        ErrorCodes.TOOL_ALREADY_REGISTERED,
        `Gate "${gate.name}" is already registered`
      );
    }
    this.nameIndex.set(gate.name, this.gates.length);
    this.gates.push(gate);
  }
  /**
   * Register multiple gate definitions at once.
   *
   * @param gates - Array of gate definitions to register
   */
  registerAll(gates) {
    for (const gate of gates) {
      this.register(gate);
    }
  }
  /**
   * Get all registered gates in insertion order.
   *
   * @returns Copy of the gates array
   */
  getAll() {
    return [...this.gates];
  }
  /**
   * Get a gate by name.
   *
   * @param name - Gate name to look up
   * @returns Gate definition or undefined if not found
   */
  get(name) {
    const index = this.nameIndex.get(name);
    if (index === void 0) return void 0;
    return this.gates[index];
  }
  /**
   * Check if a gate with the given name is registered.
   *
   * @param name - Gate name to check
   * @returns true if the gate exists
   */
  has(name) {
    return this.nameIndex.has(name);
  }
  /**
   * Remove all registered gates.
   */
  clear() {
    this.gates.length = 0;
    this.nameIndex.clear();
  }
};

// src/gates-runners.ts
import { spawnSync as spawnSync2 } from "child_process";
import { writeSync as writeSync2 } from "fs";
import { access as access2 } from "fs/promises";
import { createRequire } from "module";
import path7 from "path";

// ../core/dist/incremental-lint.js
function ensureTrailingSlash(value) {
  const normalized = value.replace(/\\/g, "/");
  return normalized.endsWith("/") ? normalized : `${normalized}/`;
}
function getConfiguredWorktreesDir() {
  return ensureTrailingSlash(createWuPaths({ projectRoot: process.cwd() }).WORKTREES_DIR());
}
var LINTABLE_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx"];
var IGNORED_DIRECTORIES = [
  "node_modules/",
  ".next/",
  ".expo/",
  "dist/",
  "build/",
  ".turbo/",
  "coverage/"
];
function isLintableFile(filePath) {
  const ignoredDirectories = [...IGNORED_DIRECTORIES, getConfiguredWorktreesDir()];
  for (const ignored of ignoredDirectories) {
    if (filePath.includes(ignored)) {
      return false;
    }
  }
  for (const ext of LINTABLE_EXTENSIONS) {
    if (filePath.endsWith(ext)) {
      return true;
    }
  }
  return false;
}
function parseGitFileList(output) {
  return output.split(STRING_LITERALS.NEWLINE).map((f) => f.trim()).filter((f) => f.length > 0);
}
async function getChangedLintableFiles(options = {}) {
  const { git = getGitForCwd(), baseBranch = GIT_REFS.ORIGIN_MAIN, filterPath } = options;
  const mergeBase = await git.mergeBase("HEAD", baseBranch);
  const committedOutput = await git.raw(["diff", "--name-only", `${mergeBase}...HEAD`]);
  const committedFiles = parseGitFileList(committedOutput);
  const unstagedOutput = await git.raw(["diff", "--name-only"]);
  const unstagedFiles = parseGitFileList(unstagedOutput);
  const untrackedOutput = await git.raw(["ls-files", "--others", "--exclude-standard"]);
  const untrackedFiles = parseGitFileList(untrackedOutput);
  const allFiles = [.../* @__PURE__ */ new Set([...committedFiles, ...unstagedFiles, ...untrackedFiles])];
  let lintableFiles = allFiles.filter(isLintableFile);
  if (filterPath) {
    lintableFiles = lintableFiles.filter((f) => f.startsWith(filterPath));
  }
  return lintableFiles;
}

// ../core/dist/incremental-test.js
var VITEST_CHANGED_EXCLUDES = Object.freeze(["**/*.integration.*", "**/golden-*.test.*"]);
var CODE_FILE_EXTENSIONS = Object.freeze([
  ".ts",
  ".tsx",
  ".js",
  ".jsx",
  ".js",
  ".cjs",
  ".mts",
  ".cts"
]);
function isCodeFilePath(filePath) {
  if (!filePath || typeof filePath !== "string") {
    return false;
  }
  const normalized = filePath.replace(/\\/g, "/").toLowerCase();
  return CODE_FILE_EXTENSIONS.some((ext) => normalized.endsWith(ext));
}
function buildVitestChangedArgs(options = {}) {
  const { baseBranch = GIT_REFS.ORIGIN_MAIN } = options;
  const args = [
    "--changed",
    baseBranch,
    "--run",
    "--passWithNoTests",
    "--maxWorkers=1",
    "--teardownTimeout=30000"
  ];
  for (const pattern of VITEST_CHANGED_EXCLUDES) {
    args.push(`--exclude='${pattern}'`);
  }
  return args;
}

// ../core/dist/validators/backlog-sync.js
import { existsSync as existsSync4, readFileSync as readFileSync3, readdirSync } from "fs";
import path3 from "path";
function extractWUIDsFromBacklog(content) {
  const wuIds = [];
  const pattern = /WU-\d+/gi;
  let match;
  while ((match = pattern.exec(content)) !== null) {
    const wuId = match[0].toUpperCase();
    if (!wuIds.includes(wuId)) {
      wuIds.push(wuId);
    }
  }
  return wuIds;
}
function getWUIDsFromFiles(wuDir) {
  if (!existsSync4(wuDir)) {
    return [];
  }
  return readdirSync(wuDir).filter((f) => f.endsWith(".yaml")).map((f) => f.replace(".yaml", "").toUpperCase());
}
async function validateBacklogSync(options = {}) {
  const { cwd = process.cwd() } = options;
  const errors = [];
  const warnings = [];
  const paths = createWuPaths({ projectRoot: cwd });
  const backlogPath = path3.join(cwd, paths.BACKLOG());
  const wuDir = path3.join(cwd, paths.WU_DIR());
  if (!existsSync4(backlogPath)) {
    errors.push(`Backlog file not found: ${backlogPath}`);
    return { valid: false, errors, warnings, wuCount: 0, backlogCount: 0 };
  }
  const wuIdsFromFiles = getWUIDsFromFiles(wuDir);
  const backlogContent = readFileSync3(backlogPath, {
    encoding: FILE_SYSTEM.UTF8
  });
  const wuIdsFromBacklog = extractWUIDsFromBacklog(backlogContent);
  for (const wuId of wuIdsFromFiles) {
    if (!wuIdsFromBacklog.includes(wuId)) {
      errors.push(`${wuId} not found in backlog.md (exists as ${wuId}.yaml)`);
    }
  }
  for (const wuId of wuIdsFromBacklog) {
    if (!wuIdsFromFiles.includes(wuId)) {
      warnings.push(`${wuId} referenced in backlog.md but ${wuId}.yaml not found`);
    }
  }
  return {
    valid: errors.length === 0,
    errors,
    warnings,
    wuCount: wuIdsFromFiles.length,
    backlogCount: wuIdsFromBacklog.length
  };
}

// ../core/dist/validators/supabase-docs-linter.js
import { existsSync as existsSync5 } from "fs";
import path4 from "path";
import { pathToFileURL } from "url";
async function runSupabaseDocsLinter(options = {}) {
  const { cwd = process.cwd(), logger = console } = options;
  const linterPath = path4.join(cwd, "packages", "linters", "supabase-docs-linter.js");
  if (!existsSync5(linterPath)) {
    return {
      ok: true,
      skipped: true,
      message: "Supabase docs linter not found; skipping."
    };
  }
  const moduleUrl = pathToFileURL(linterPath).href;
  const module = await import(moduleUrl);
  const runFn = module.runSupabaseDocsLinter ?? module.default;
  if (typeof runFn !== "function") {
    return {
      ok: false,
      skipped: false,
      errors: ["Supabase docs linter does not export runSupabaseDocsLinter."]
    };
  }
  const result = await runFn({ cwd, logger });
  if (result && typeof result === "object" && "ok" in result) {
    return {
      ok: Boolean(result.ok),
      skipped: Boolean(result.skipped),
      message: result.message,
      errors: result.errors
    };
  }
  return {
    ok: true,
    skipped: false,
    message: "Supabase docs linter completed."
  };
}

// src/gates-utils.ts
import { execSync, spawnSync } from "child_process";
import { closeSync, mkdirSync, openSync, readSync, statSync, writeSync } from "fs";
import { access } from "fs/promises";
import path5 from "path";
function pnpmCmd(...parts) {
  return `${PKG_MANAGER} ${parts.join(" ")}`;
}
function pnpmRun(script, ...args) {
  const argsStr = args.length > 0 ? ` ${args.join(" ")}` : "";
  return `${PKG_MANAGER} ${SCRIPTS.RUN} ${script}${argsStr}`;
}
function normalizePath(filePath) {
  return filePath.replace(/\\/g, "/");
}
function getBasename(filePath) {
  const normalized = normalizePath(filePath);
  const parts = normalized.split("/");
  return parts[parts.length - 1] || normalized;
}
function quoteShellArgs(files) {
  return files.map((file) => `"${file}"`).join(" ");
}
var PRETTIER_NON_FILE_OUTPUT_MARKERS = [
  "code style issues found",
  "all matched files use prettier",
  "checking formatting",
  "is a symbolic link"
];
function isNonFilePrettierOutputLine(line) {
  const normalizedLine = line.toLowerCase();
  return PRETTIER_NON_FILE_OUTPUT_MARKERS.some((marker) => normalizedLine.includes(marker));
}
function parsePrettierListOutput(output) {
  if (!output) return [];
  return output.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => line.replace(/^\[error\]\s*/i, "").trim()).filter((line) => !isNonFilePrettierOutputLine(line));
}
function buildPrettierWriteCommand(files) {
  const quotedFiles = files.map((file) => `"${file}"`).join(" ");
  const base = pnpmCmd(SCRIPTS.PRETTIER, PRETTIER_FLAGS.WRITE);
  return quotedFiles ? `${base} ${quotedFiles}` : base;
}
function buildPrettierCheckCommand(files) {
  const filesArg = files.length > 0 ? quoteShellArgs(files) : ".";
  return pnpmCmd(SCRIPTS.PRETTIER, PRETTIER_ARGS.CHECK, filesArg);
}
function formatFormatCheckGuidance(files) {
  if (!files.length) return [];
  const command = buildPrettierWriteCommand(files);
  return [
    "",
    "\u274C format:check failed",
    "Fix with:",
    `  ${command}`,
    "",
    "Affected files:",
    ...files.map((file) => `  - ${file}`),
    ""
  ];
}
function collectPrettierListDifferent(cwd, files = []) {
  const filesArg = files.length > 0 ? quoteShellArgs(files) : ".";
  const cmd = pnpmCmd(SCRIPTS.PRETTIER, PRETTIER_ARGS.LIST_DIFFERENT, filesArg);
  const result = spawnSync(cmd, [], {
    shell: true,
    cwd,
    encoding: FILE_SYSTEM.ENCODING
  });
  const output = `${result.stdout || ""}
${result.stderr || ""}`;
  return parsePrettierListOutput(output);
}
function emitFormatCheckGuidance({
  agentLog,
  useAgentMode,
  files,
  cwd
}) {
  const formattedFiles = collectPrettierListDifferent(cwd, files ?? []);
  if (!formattedFiles.length) return;
  const lines = formatFormatCheckGuidance(formattedFiles);
  const logLine = useAgentMode && agentLog ? (line) => writeSync(agentLog.logFd, `${line}
`) : (line) => console.log(line);
  for (const line of lines) {
    logLine(line);
  }
}
function run(cmd, {
  agentLog,
  cwd = process.cwd()
} = {}) {
  const start = Date.now();
  if (!agentLog) {
    console.log(`
> ${cmd}
`);
    try {
      execSync(cmd, {
        stdio: "inherit",
        encoding: FILE_SYSTEM.ENCODING,
        cwd
      });
      return { ok: true, duration: Date.now() - start };
    } catch {
      return { ok: false, duration: Date.now() - start };
    }
  }
  writeSync(agentLog.logFd, `
> ${cmd}

`);
  const result = spawnSync(cmd, [], {
    shell: true,
    stdio: ["ignore", agentLog.logFd, agentLog.logFd],
    cwd,
    encoding: FILE_SYSTEM.ENCODING
  });
  return { ok: result.status === EXIT_CODES.SUCCESS, duration: Date.now() - start };
}
function makeGateLogger({ agentLog, useAgentMode }) {
  return (line) => {
    if (!useAgentMode) {
      console.log(line);
      return;
    }
    if (agentLog) {
      writeSync(agentLog.logFd, `${line}
`);
    }
  };
}
function readLogTail(logPath, { maxLines = LOG_TAIL_MAX_LINES, maxBytes = LOG_TAIL_MAX_BYTES } = {}) {
  try {
    const stats = statSync(logPath);
    const startPos = Math.max(0, stats.size - maxBytes);
    const bytesToRead = stats.size - startPos;
    const fd = openSync(logPath, "r");
    try {
      const buffer = Buffer.alloc(bytesToRead);
      readSync(fd, buffer, 0, bytesToRead, startPos);
      const text = buffer.toString(FILE_SYSTEM.ENCODING);
      const lines = text.split(/\r?\n/).filter(Boolean);
      return lines.slice(-maxLines).join("\n");
    } finally {
      closeSync(fd);
    }
  } catch {
    return "";
  }
}
function createAgentLogContext({
  wuId,
  lane,
  cwd
}) {
  const logPath = buildGatesLogPath({
    cwd,
    env: process.env,
    wuId: wuId ?? void 0,
    lane: lane ?? void 0
  });
  mkdirSync(path5.dirname(logPath), { recursive: true });
  const logFd = openSync(logPath, "a");
  const header = `# gates log
# lane: ${lane || "unknown"}
# wu: ${wuId || "unknown"}
# started: ${(/* @__PURE__ */ new Date()).toISOString()}

`;
  writeSync(logFd, header);
  process.on("exit", () => {
    try {
      closeSync(logFd);
    } catch {
    }
  });
  return { logPath, logFd };
}
async function filterExistingFiles(files, cwd = process.cwd()) {
  const existingFiles = await Promise.all(
    files.map(async (file) => {
      const filePath = path5.isAbsolute(file) ? file : path5.resolve(cwd, file);
      try {
        await access(filePath);
        return file;
      } catch {
        return null;
      }
    })
  );
  return existingFiles.filter((file) => Boolean(file));
}
async function getChangedFilesForIncremental({
  git,
  baseBranch = GIT_REFS.ORIGIN_MAIN
}) {
  const mergeBase = await git.mergeBase("HEAD", baseBranch);
  const committedOutput = await git.raw(["diff", "--name-only", `${mergeBase}...HEAD`]);
  const committedFiles = committedOutput.split("\n").map((f) => f.trim()).filter(Boolean);
  const unstagedOutput = await git.raw(["diff", "--name-only"]);
  const unstagedFiles = unstagedOutput.split("\n").map((f) => f.trim()).filter(Boolean);
  const untrackedOutput = await git.raw(["ls-files", "--others", "--exclude-standard"]);
  const untrackedFiles = untrackedOutput.split("\n").map((f) => f.trim()).filter(Boolean);
  return [.../* @__PURE__ */ new Set([...committedFiles, ...unstagedFiles, ...untrackedFiles])];
}
function parseWUFromBranchName(branchName) {
  if (!branchName) {
    return null;
  }
  const match = branchName.match(/wu-(\d+)/i);
  if (!match) {
    return null;
  }
  return `WU-${match[1]}`.toUpperCase();
}
async function detectCurrentWUForCwd(cwd) {
  const workingDir = cwd ?? process.cwd();
  try {
    const branch = await createGitForPath(workingDir).getCurrentBranch();
    const parsed = parseWUFromBranchName(branch);
    if (parsed) {
      return parsed;
    }
  } catch {
  }
  return getCurrentWU();
}
function extractPackageFromPath(codePath) {
  if (!codePath || typeof codePath !== "string") {
    return null;
  }
  const normalized = codePath.replace(/\\/g, "/");
  if (normalized.startsWith("packages/")) {
    const parts = normalized.slice("packages/".length).split("/");
    if (parts[0]?.startsWith("@") && parts[1]) {
      return `${parts[0]}/${parts[1]}`;
    }
    if (parts[0]) {
      return parts[0];
    }
  }
  return null;
}
function extractPackagesFromCodePaths(codePaths) {
  if (!codePaths || !Array.isArray(codePaths) || codePaths.length === 0) {
    return [];
  }
  const packages = /* @__PURE__ */ new Set();
  for (const codePath of codePaths) {
    const pkg = extractPackageFromPath(codePath);
    if (pkg) {
      packages.add(pkg);
    }
  }
  return Array.from(packages);
}
function loadCurrentWUCodePaths(options = {}) {
  const cwd = options.cwd ?? process.cwd();
  const wuId = getCurrentWU();
  if (!wuId) {
    return [];
  }
  try {
    const wuPaths = createWuPaths({ projectRoot: cwd });
    const wuYamlPath = wuPaths.WU(wuId);
    const wuDoc = readWURaw(wuYamlPath);
    if (wuDoc && Array.isArray(wuDoc.code_paths)) {
      return wuDoc.code_paths.filter((p) => typeof p === "string");
    }
  } catch {
  }
  return [];
}

// src/gates-plan-resolvers.ts
import { existsSync as existsSync6 } from "fs";
import path6 from "path";
var PRETTIER_CONFIG_FILES = /* @__PURE__ */ new Set([
  ".prettierrc",
  ".prettierrc.json",
  ".prettierrc.yaml",
  ".prettierrc.yml",
  ".prettierrc.js",
  ".prettierrc.cjs",
  ".prettierrc.ts",
  "prettier.config.js",
  "prettier.config.cjs",
  "prettier.config.ts",
  "prettier.config.mjs",
  ".prettierignore"
]);
var WORKSPACE_ARTIFACT_ROOT_PREFIXES = ["packages/", "apps/", "tools/"];
var DIST_ARTIFACT_ROOT_SUFFIX = "/dist";
var DIST_ARTIFACT_PATH_SEGMENT = "/dist/";
var TEST_CONFIG_BASENAMES = /* @__PURE__ */ new Set([
  "turbo.json",
  // Turborepo
  "nx.json",
  // Nx
  "lerna.json",
  // Lerna
  "pnpm-lock.yaml",
  "package-lock.json",
  "yarn.lock",
  "bun.lockb",
  "package.json"
]);
var TEST_CONFIG_PATTERNS = [
  /^vitest\.config\.(ts|mts|js|mjs|cjs)$/i,
  /^jest\.config\.(ts|js|mjs|cjs|json)$/i,
  /^\.mocharc\.(js|json|yaml|yml)$/i,
  // eslint-disable-next-line security/detect-unsafe-regex -- static tsconfig pattern; no backtracking risk
  /^tsconfig(\..+)?\.json$/i
];
function isPrettierConfigFile(filePath) {
  if (!filePath) return false;
  const basename = getBasename(filePath);
  return PRETTIER_CONFIG_FILES.has(basename);
}
function trimTrailingPathSeparators(filePath) {
  let trimmed = filePath;
  while (trimmed.endsWith("/")) {
    trimmed = trimmed.slice(0, -1);
  }
  return trimmed;
}
function isWorkspaceDistArtifactRoot(filePath) {
  if (!filePath) {
    return false;
  }
  const normalizedPath = trimTrailingPathSeparators(normalizePath(filePath));
  if (!normalizedPath) {
    return false;
  }
  const hasWorkspacePrefix = WORKSPACE_ARTIFACT_ROOT_PREFIXES.some(
    (prefix) => normalizedPath.startsWith(prefix)
  );
  const isDistArtifactPath = normalizedPath.endsWith(DIST_ARTIFACT_ROOT_SUFFIX) || normalizedPath.includes(DIST_ARTIFACT_PATH_SEGMENT);
  return hasWorkspacePrefix && isDistArtifactPath;
}
function filterFormatCheckChangedFiles(changedFiles) {
  return changedFiles.filter((filePath) => !isWorkspaceDistArtifactRoot(filePath));
}
function filterExistingFormatCheckFiles(changedFiles, cwd) {
  return changedFiles.filter((filePath) => {
    const resolvedPath = path6.isAbsolute(filePath) ? filePath : path6.resolve(cwd, filePath);
    return existsSync6(resolvedPath);
  });
}
function isTestConfigFile(filePath) {
  if (!filePath) return false;
  const basename = getBasename(filePath);
  if (TEST_CONFIG_BASENAMES.has(basename)) {
    return true;
  }
  return TEST_CONFIG_PATTERNS.some((pattern) => pattern.test(basename));
}
function resolveFormatCheckPlan({
  changedFiles,
  fileListError = false,
  cwd
}) {
  const filteredChangedFiles = filterFormatCheckChangedFiles(changedFiles);
  if (fileListError) {
    return { mode: "full", files: [], reason: "file-list-error" };
  }
  if (filteredChangedFiles.some(isPrettierConfigFile)) {
    return { mode: "full", files: [], reason: "prettier-config" };
  }
  const existingChangedFiles = cwd ? filterExistingFormatCheckFiles(filteredChangedFiles, cwd) : filteredChangedFiles;
  if (existingChangedFiles.length === 0) {
    return { mode: "skip", files: [] };
  }
  return { mode: "incremental", files: existingChangedFiles };
}
function resolveLintPlan({
  isMainBranch,
  changedFiles
}) {
  if (isMainBranch) {
    return { mode: "full", files: [] };
  }
  const lintTargets = changedFiles.filter((filePath) => {
    const normalized = normalizePath(filePath);
    return (normalized.startsWith("apps/") || normalized.startsWith("packages/")) && isLintableFile(normalized);
  });
  if (lintTargets.length === 0) {
    return { mode: "skip", files: [] };
  }
  return { mode: "incremental", files: lintTargets };
}
function resolveTestPlan({
  isMainBranch,
  hasUntrackedCode,
  hasConfigChange,
  fileListError
}) {
  if (fileListError) {
    return { mode: "full", reason: "file-list-error" };
  }
  if (hasUntrackedCode) {
    return { mode: "full", reason: "untracked-code" };
  }
  if (hasConfigChange) {
    return { mode: "full", reason: "test-config" };
  }
  if (isMainBranch) {
    return { mode: "full" };
  }
  return { mode: "incremental" };
}
function resolveDocsOnlyTestPlan({ codePaths }) {
  const packages = extractPackagesFromCodePaths(codePaths);
  if (packages.length === 0) {
    return {
      mode: "skip",
      packages: [],
      reason: "no-code-packages"
    };
  }
  return {
    mode: "filtered",
    packages
  };
}
function formatDocsOnlySkipMessage(plan) {
  if (plan.mode === "skip") {
    return "\u{1F4DD} docs-only mode: skipping all tests (no code packages in code_paths)";
  }
  const packageList = plan.packages.join(", ");
  return `\u{1F4DD} docs-only mode: running tests only for packages in code_paths: ${packageList}`;
}
function resolveSpecLinterPlan(wuId) {
  if (wuId) {
    return {
      scopedWuId: wuId,
      runGlobal: false
    };
  }
  return {
    scopedWuId: null,
    runGlobal: true
  };
}

// src/gates-runners.ts
var require2 = createRequire(import.meta.url);
var micromatch = require2("micromatch");
var CO_CHANGE_SEVERITY = {
  WARN: "warn",
  ERROR: "error",
  OFF: "off"
};
async function runFormatCheckGate({ agentLog, useAgentMode, cwd }) {
  const start = Date.now();
  const effectiveCwd = cwd ?? process.cwd();
  const logLine = makeGateLogger({ agentLog, useAgentMode });
  let git;
  let isMainBranch;
  try {
    git = createGitForPath(effectiveCwd);
    const currentBranch = await git.getCurrentBranch();
    isMainBranch = currentBranch === BRANCHES.MAIN || currentBranch === BRANCHES.MASTER;
  } catch (error) {
    logLine(`\u26A0\uFE0F  Failed to determine branch for format check: ${error.message}`);
    const result2 = run(pnpmCmd(SCRIPTS.FORMAT_CHECK), { agentLog, cwd: effectiveCwd });
    return { ...result2, duration: Date.now() - start, fileCount: -1 };
  }
  if (isMainBranch) {
    logLine("\u{1F4CB} On main branch - running full format check");
    const result2 = run(pnpmCmd(SCRIPTS.FORMAT_CHECK), { agentLog, cwd: effectiveCwd });
    return { ...result2, duration: Date.now() - start, fileCount: -1 };
  }
  let changedFiles = [];
  let fileListError = false;
  try {
    changedFiles = await getChangedFilesForIncremental({ git });
  } catch (error) {
    fileListError = true;
    logLine(`\u26A0\uFE0F  Failed to determine changed files for format check: ${error.message}`);
  }
  const plan = resolveFormatCheckPlan({ changedFiles, fileListError, cwd: effectiveCwd });
  if (plan.mode === "skip") {
    logLine("\n> format:check (incremental)\n");
    logLine("\u2705 No files changed - skipping format check");
    return { ok: true, duration: Date.now() - start, fileCount: 0, filesChecked: [] };
  }
  if (plan.mode === "full") {
    const reason = plan.reason === "prettier-config" ? " (prettier config changed)" : plan.reason === "file-list-error" ? " (file list unavailable)" : "";
    logLine(`\u{1F4CB} Running full format check${reason}`);
    const result2 = run(pnpmCmd(SCRIPTS.FORMAT_CHECK), { agentLog, cwd: effectiveCwd });
    return { ...result2, duration: Date.now() - start, fileCount: -1 };
  }
  const existingFiles = await filterExistingFiles(plan.files, effectiveCwd);
  if (existingFiles.length === 0) {
    logLine("\n> format:check (incremental)\n");
    logLine("\u2705 All changed files were deleted - skipping format check");
    return { ok: true, duration: Date.now() - start, fileCount: 0, filesChecked: [] };
  }
  logLine(`
> format:check (incremental: ${existingFiles.length} files)
`);
  const result = run(buildPrettierCheckCommand(existingFiles), { agentLog, cwd: effectiveCwd });
  return {
    ...result,
    duration: Date.now() - start,
    fileCount: existingFiles.length,
    filesChecked: existingFiles
  };
}
async function runIncrementalLint({
  agentLog,
  cwd
}) {
  const start = Date.now();
  const logLine = (line) => {
    if (!agentLog) {
      console.log(line);
      return;
    }
    writeSync2(agentLog.logFd, `${line}
`);
  };
  try {
    const git = createGitForPath(cwd);
    const currentBranch = await git.getCurrentBranch();
    const isMainBranch = currentBranch === BRANCHES.MAIN || currentBranch === BRANCHES.MASTER;
    if (isMainBranch) {
      logLine("\u{1F4CB} On main branch - running full lint");
      const result2 = run(pnpmCmd(SCRIPTS.LINT), { agentLog, cwd });
      return { ...result2, fileCount: -1 };
    }
    const changedFiles = await getChangedLintableFiles({ git });
    const plan = resolveLintPlan({ isMainBranch, changedFiles });
    if (plan.mode === "skip") {
      logLine("\n> ESLint (incremental)\n");
      logLine("\u2705 No lintable files changed - skipping lint");
      return { ok: true, duration: Date.now() - start, fileCount: 0 };
    }
    if (plan.mode === "full") {
      logLine("\u{1F4CB} Running full lint (incremental plan forced full)");
      const result2 = run(pnpmCmd(SCRIPTS.LINT), { agentLog, cwd });
      return { ...result2, fileCount: -1 };
    }
    const existingFiles = await filterExistingFiles(plan.files, cwd);
    if (existingFiles.length === 0) {
      logLine("\n> ESLint (incremental)\n");
      logLine("\u2705 All changed files were deleted - skipping lint");
      return { ok: true, duration: Date.now() - start, fileCount: 0 };
    }
    logLine(`
> ESLint (incremental: ${existingFiles.length} files)
`);
    logLine(`Files to lint:
  ${existingFiles.join("\n  ")}
`);
    const result = spawnSync2(
      PKG_MANAGER,
      [
        ESLINT_COMMANDS.ESLINT,
        ESLINT_FLAGS.MAX_WARNINGS,
        ESLINT_DEFAULTS.MAX_WARNINGS,
        ESLINT_FLAGS.NO_WARN_IGNORED,
        ESLINT_FLAGS.CACHE,
        ESLINT_FLAGS.CACHE_STRATEGY,
        CACHE_STRATEGIES.CONTENT,
        ESLINT_FLAGS.CACHE_LOCATION,
        ".eslintcache",
        ESLINT_FLAGS.PASS_ON_UNPRUNED,
        ...existingFiles
      ],
      agentLog ? {
        stdio: ["ignore", agentLog.logFd, agentLog.logFd],
        encoding: FILE_SYSTEM.ENCODING,
        cwd
      } : {
        stdio: "inherit",
        encoding: FILE_SYSTEM.ENCODING,
        cwd
      }
    );
    const duration = Date.now() - start;
    return {
      ok: result.status === EXIT_CODES.SUCCESS,
      duration,
      fileCount: existingFiles.length
    };
  } catch (error) {
    console.error(
      "\u26A0\uFE0F  Incremental lint failed, falling back to full lint:",
      error.message
    );
    const result = run(pnpmCmd(SCRIPTS.LINT), { agentLog, cwd });
    return { ...result, fileCount: -1 };
  }
}
var DEFAULT_INCREMENTAL_BASE_BRANCH = GIT_REFS.ORIGIN_MAIN;
function buildStableVitestIncrementalCommand(baseBranch = DEFAULT_INCREMENTAL_BASE_BRANCH) {
  return pnpmCmd("vitest", "run", ...buildVitestChangedArgs({ baseBranch }));
}
function resolveIncrementalTestCommand({
  testRunner,
  configuredIncrementalCommand,
  baseBranch = DEFAULT_INCREMENTAL_BASE_BRANCH
}) {
  const normalizedConfiguredCommand = configuredIncrementalCommand?.trim();
  if (testRunner === "vitest") {
    if (!normalizedConfiguredCommand) {
      return buildStableVitestIncrementalCommand(baseBranch);
    }
    const isVitestChangedCommand = normalizedConfiguredCommand.includes("vitest") && normalizedConfiguredCommand.includes("--changed");
    if (isVitestChangedCommand) {
      return buildStableVitestIncrementalCommand(baseBranch);
    }
  }
  return normalizedConfiguredCommand ?? null;
}
async function runChangedTests({
  agentLog,
  cwd,
  scopedTestPaths = []
}) {
  const start = Date.now();
  const logLine = (line) => {
    if (!agentLog) {
      console.log(line);
      return;
    }
    writeSync2(agentLog.logFd, `${line}
`);
  };
  const gatesCommands = resolveGatesCommands(cwd);
  const testRunner = resolveTestRunner(cwd);
  const normalizedScopedTestPaths = scopedTestPaths.filter((testPath) => typeof testPath === "string").map((testPath) => testPath.trim()).filter(Boolean);
  try {
    if (normalizedScopedTestPaths.length > 0) {
      const testPathsArg = quoteShellArgs(normalizedScopedTestPaths);
      logLine(
        `
> Running scoped tests from WU tests.unit (${normalizedScopedTestPaths.length})
`
      );
      const result2 = run(pnpmCmd("vitest", "run", testPathsArg, "--passWithNoTests"), {
        agentLog,
        cwd
      });
      return { ...result2, duration: Date.now() - start, isIncremental: true };
    }
    const git = createGitForPath(cwd);
    const currentBranch = await git.getCurrentBranch();
    const isMainBranch = currentBranch === BRANCHES.MAIN || currentBranch === BRANCHES.MASTER;
    if (isMainBranch) {
      logLine("\u{1F4CB} On main branch - running full test suite");
      const result2 = run(gatesCommands.test_full, { agentLog, cwd });
      return { ...result2, isIncremental: false };
    }
    let changedFiles = [];
    let fileListError = false;
    try {
      changedFiles = await getChangedFilesForIncremental({ git });
    } catch (error) {
      fileListError = true;
      logLine(`\u26A0\uFE0F  Failed to determine changed files for tests: ${error.message}`);
    }
    const hasConfigChange = !fileListError && changedFiles.some(isTestConfigFile);
    const untrackedOutput = await git.raw(["ls-files", "--others", "--exclude-standard"]);
    const untrackedFiles = untrackedOutput.split(/\r?\n/).map((f) => f.trim()).filter(Boolean);
    const untrackedCodeFiles = untrackedFiles.filter(isCodeFilePath);
    const hasUntrackedCode = untrackedCodeFiles.length > 0;
    const plan = resolveTestPlan({
      isMainBranch,
      hasUntrackedCode,
      hasConfigChange,
      fileListError
    });
    if (plan.mode === "full") {
      if (plan.reason === "untracked-code") {
        const preview = untrackedCodeFiles.slice(0, 5).join(", ");
        logLine(
          `\u26A0\uFE0F  Untracked code files detected (${untrackedCodeFiles.length}): ${preview}${untrackedCodeFiles.length > 5 ? "..." : ""}`
        );
      } else if (plan.reason === "test-config") {
        logLine("\u26A0\uFE0F  Test config changes detected - running full test suite");
      } else if (plan.reason === "file-list-error") {
        logLine("\u26A0\uFE0F  Changed file list unavailable - running full test suite");
      }
      logLine("\u{1F4CB} Running full test suite to avoid missing coverage");
      const result2 = run(gatesCommands.test_full, { agentLog, cwd });
      return { ...result2, duration: Date.now() - start, isIncremental: false };
    }
    logLine(`
> Running tests (${testRunner} --changed)
`);
    const incrementalCommand = resolveIncrementalTestCommand({
      testRunner,
      configuredIncrementalCommand: gatesCommands.test_incremental
    });
    if (incrementalCommand) {
      if (testRunner === "vitest" && incrementalCommand !== gatesCommands.test_incremental?.trim()) {
        logLine("\u2139\uFE0F  Using hardened vitest incremental command for worker stability");
      }
      const result2 = run(incrementalCommand, { agentLog, cwd });
      return { ...result2, duration: Date.now() - start, isIncremental: true };
    }
    logLine("\u26A0\uFE0F  No incremental test command configured, running full suite");
    const result = run(gatesCommands.test_full, { agentLog, cwd });
    return { ...result, duration: Date.now() - start, isIncremental: false };
  } catch (error) {
    console.error("\u26A0\uFE0F  Changed tests failed, falling back to full suite:", error.message);
    const result = run(gatesCommands.test_full, { agentLog, cwd });
    return { ...result, isIncremental: false };
  }
}
var SAFETY_CRITICAL_TEST_FILES = [
  // Privacy detection tests
  "src/lib/llm/__tests__/privacyDetector.test.ts",
  // Escalation trigger tests
  "src/lib/llm/__tests__/escalationTrigger.test.ts",
  "src/components/escalation/__tests__/EscalationHistory.test.tsx",
  // Constitutional enforcer tests
  "src/lib/llm/__tests__/constitutionalEnforcer.test.ts",
  // Safe prompt wrapper tests
  "src/lib/llm/__tests__/safePromptWrapper.test.ts",
  // Crisis/emergency handling tests
  "src/lib/prompts/__tests__/golden-crisis.test.ts"
];
async function runSafetyCriticalTests({
  agentLog,
  cwd
}) {
  const start = Date.now();
  const logLine = (line) => {
    if (!agentLog) {
      console.log(line);
      return;
    }
    writeSync2(agentLog.logFd, `${line}
`);
  };
  const webDir = path7.join(cwd, DIRECTORIES.APPS_WEB);
  try {
    await access2(webDir);
  } catch {
    logLine("\n> Safety-critical tests skipped (apps/web not present)\n");
    return { ok: true, duration: Date.now() - start, testCount: 0 };
  }
  try {
    logLine("\n> Safety-critical tests (always run)\n");
    logLine(`Test files: ${SAFETY_CRITICAL_TEST_FILES.length} files
`);
    const result = spawnSync2(
      PKG_MANAGER,
      [
        "vitest",
        "run",
        "--project",
        PACKAGES.WEB,
        "--reporter=verbose",
        ...SAFETY_CRITICAL_TEST_FILES,
        "--passWithNoTests"
      ],
      agentLog ? {
        stdio: ["ignore", agentLog.logFd, agentLog.logFd],
        encoding: FILE_SYSTEM.ENCODING,
        cwd
      } : {
        stdio: "inherit",
        encoding: FILE_SYSTEM.ENCODING,
        cwd
      }
    );
    const duration = Date.now() - start;
    return {
      ok: result.status === EXIT_CODES.SUCCESS,
      duration,
      testCount: SAFETY_CRITICAL_TEST_FILES.length
    };
  } catch (error) {
    console.error("\u26A0\uFE0F  Safety-critical tests failed:", error.message);
    return { ok: false, duration: Date.now() - start, testCount: 0 };
  }
}
async function runIntegrationTests({
  agentLog,
  cwd
}) {
  const start = Date.now();
  const logLine = (line) => {
    if (!agentLog) {
      console.log(line);
      return;
    }
    writeSync2(agentLog.logFd, `${line}
`);
  };
  try {
    logLine("\n> Integration tests (high-risk changes detected)\n");
    const result = run(
      `RUN_INTEGRATION_TESTS=1 ${pnpmCmd(
        "vitest",
        "run",
        "'**/*.integration.*'",
        "'**/golden-*.test.*'"
      )}`,
      { agentLog, cwd }
    );
    const duration = Date.now() - start;
    return {
      ok: result.ok,
      duration
    };
  } catch (error) {
    console.error("\u26A0\uFE0F  Integration tests failed:", error.message);
    return { ok: false, duration: Date.now() - start };
  }
}
var CoChangeRulesConfigSchema = CoChangeRuleConfigSchema.array();
function hasPatternMatch(changedFiles, patterns) {
  return changedFiles.some((filePath) => micromatch.isMatch(filePath, patterns));
}
function evaluateCoChangeRules({
  changedFiles,
  rules
}) {
  const errors = [];
  const warnings = [];
  for (const rule of rules) {
    if (rule.severity === CO_CHANGE_SEVERITY.OFF) {
      continue;
    }
    const triggerMatched = hasPatternMatch(changedFiles, rule.trigger_patterns);
    if (!triggerMatched) {
      continue;
    }
    const requireMatched = hasPatternMatch(changedFiles, rule.require_patterns);
    if (requireMatched) {
      continue;
    }
    const message = `co-change "${rule.name}" violated: trigger matched (${rule.trigger_patterns.join(", ")}) but required patterns missing (${rule.require_patterns.join(", ")})`;
    if (rule.severity === CO_CHANGE_SEVERITY.WARN) {
      warnings.push(message);
      continue;
    }
    errors.push(message);
  }
  return { errors, warnings };
}
async function runCoChangeGate({ agentLog, useAgentMode, cwd }) {
  const start = Date.now();
  const effectiveCwd = cwd ?? process.cwd();
  const logLine = makeGateLogger({ agentLog, useAgentMode });
  logLine("\n> Co-change check\n");
  const gatesSection = getGatesSection(effectiveCwd);
  const parsedRules = CoChangeRulesConfigSchema.safeParse(gatesSection?.co_change ?? []);
  if (!parsedRules.success) {
    logLine("\u26A0\uFE0F  Invalid gates.co_change config; skipping check.");
    return { ok: true, duration: Date.now() - start };
  }
  const rules = parsedRules.data;
  if (rules.length === 0) {
    logLine("\u2139\uFE0F  No co-change rules configured; skipping.");
    return { ok: true, duration: Date.now() - start };
  }
  const git = createGitForPath(effectiveCwd);
  const changedFiles = await getChangedFilesForIncremental({ git });
  if (changedFiles.length === 0) {
    logLine("\u2139\uFE0F  No changed files detected; skipping co-change checks.");
    return { ok: true, duration: Date.now() - start };
  }
  const evaluation = evaluateCoChangeRules({ changedFiles, rules });
  for (const warning of evaluation.warnings) {
    logLine(`\u26A0\uFE0F  ${warning}`);
  }
  for (const error of evaluation.errors) {
    logLine(`\u274C ${error}`);
  }
  if (evaluation.errors.length > 0) {
    logLine("co-change check failed.");
    return { ok: false, duration: Date.now() - start };
  }
  logLine("co-change check passed.");
  return { ok: true, duration: Date.now() - start };
}
async function runSpecLinterGate({ agentLog, useAgentMode, cwd }) {
  const start = Date.now();
  const wuId = await detectCurrentWUForCwd(cwd);
  const plan = resolveSpecLinterPlan(wuId);
  if (plan.scopedWuId) {
    const scopedCmd = pnpmCmd("wu:validate", "--id", plan.scopedWuId);
    const scopedResult = run(scopedCmd, { agentLog, cwd });
    if (!scopedResult.ok) {
      return { ok: false, duration: Date.now() - start };
    }
    return { ok: true, duration: Date.now() - start };
  }
  if (!useAgentMode) {
    console.log("\u26A0\uFE0F  Unable to detect current WU; skipping scoped validation.");
  } else if (agentLog) {
    writeSync2(
      agentLog.logFd,
      "\u26A0\uFE0F  Unable to detect current WU; skipping scoped validation.\n"
    );
  }
  if (!plan.runGlobal) {
    return { ok: true, duration: Date.now() - start };
  }
  const fallbackResult = run(pnpmRun(SCRIPTS.SPEC_LINTER), { agentLog, cwd });
  return { ok: fallbackResult.ok, duration: Date.now() - start };
}
async function runClaimValidationGate({ agentLog, useAgentMode, cwd }) {
  const start = Date.now();
  const effectiveCwd = cwd ?? process.cwd();
  const logLine = makeGateLogger({ agentLog, useAgentMode });
  logLine("\n> Claim validation\n");
  const wuId = await detectCurrentWUForCwd(effectiveCwd);
  if (!wuId) {
    logLine("\u26A0\uFE0F  Unable to detect current WU; skipping claim validation.");
    return { ok: true, duration: Date.now() - start };
  }
  const result = await validateClaimValidation({ cwd: effectiveCwd, wuId });
  if (result.warnings.length > 0) {
    for (const warning of result.warnings) {
      logLine(`\u26A0\uFE0F  ${warning}`);
    }
  }
  if (result.ok) {
    logLine(
      `Claim validation passed (${result.checkedClaims} checked claim${result.checkedClaims === 1 ? "" : "s"}).`
    );
    return { ok: true, duration: Date.now() - start };
  }
  logLine("\u274C Claim validation mismatches detected:");
  for (const mismatch of result.mismatches) {
    const specPath = path7.relative(effectiveCwd, mismatch.specReference.filePath).replaceAll(path7.sep, "/");
    logLine(`  - Claim (${mismatch.claimId}): ${mismatch.claimText}`);
    logLine(
      `    Spec: ${specPath}:${mismatch.specReference.line} [${mismatch.specReference.id} ${mismatch.specReference.section}]`
    );
    for (const evidence of mismatch.evidence) {
      logLine(`    Evidence: ${evidence.filePath}:${evidence.line} ${evidence.lineText}`);
    }
    logLine(`    Hint: ${mismatch.remediationHint}`);
  }
  return { ok: false, duration: Date.now() - start };
}
async function runBacklogSyncGate({ agentLog, useAgentMode, cwd }) {
  const start = Date.now();
  const logLine = makeGateLogger({ agentLog, useAgentMode });
  logLine("\n> Backlog sync\n");
  const result = await validateBacklogSync({ cwd });
  if (result.errors.length > 0) {
    logLine("\u274C Backlog sync errors:");
    result.errors.forEach((error) => logLine(`  - ${error}`));
  }
  if (result.warnings.length > 0) {
    logLine("\u26A0\uFE0F  Backlog sync warnings:");
    result.warnings.forEach((warning) => logLine(`  - ${warning}`));
  }
  logLine(`Backlog sync summary: WU files=${result.wuCount}, Backlog refs=${result.backlogCount}`);
  return { ok: result.valid, duration: Date.now() - start };
}
async function runSupabaseDocsGate({ agentLog, useAgentMode, cwd }) {
  const start = Date.now();
  const logLine = makeGateLogger({ agentLog, useAgentMode });
  logLine("\n> Supabase docs linter\n");
  const result = await runSupabaseDocsLinter({ cwd, logger: { log: logLine } });
  if (result.skipped) {
    logLine(`\u26A0\uFE0F  ${result.message ?? "Supabase docs linter skipped."}`);
  } else if (!result.ok) {
    logLine("\u274C Supabase docs linter failed.");
    (result.errors ?? []).forEach((error) => logLine(`  - ${error}`));
  } else {
    logLine(result.message ?? "Supabase docs linter passed.");
  }
  return { ok: result.ok, duration: Date.now() - start };
}
async function runLaneHealthGate({
  agentLog,
  useAgentMode,
  mode,
  cwd
}) {
  const start = Date.now();
  const logLine = makeGateLogger({ agentLog, useAgentMode });
  if (mode === "off") {
    logLine("\n> Lane health check (skipped - mode: off)\n");
    return { ok: true, duration: Date.now() - start };
  }
  logLine(`
> Lane health check (mode: ${mode})
`);
  const report = runLaneHealthCheck({ projectRoot: cwd });
  if (!report.healthy) {
    logLine("\u26A0\uFE0F  Lane health issues detected:");
    if (report.overlaps.hasOverlaps) {
      logLine(`  - ${report.overlaps.overlaps.length} overlapping code_paths`);
    }
    if (report.gaps.hasGaps) {
      logLine(`  - ${report.gaps.uncoveredFiles.length} uncovered files`);
    }
    logLine(`  Run 'pnpm lane:health' for full report.`);
    if (mode === "error") {
      return { ok: false, duration: Date.now() - start };
    }
    logLine("  (mode: warn - not blocking)");
  } else {
    logLine("Lane health check passed.");
  }
  return { ok: true, duration: Date.now() - start };
}
async function runDocsOnlyFilteredTests({
  packages,
  agentLog,
  cwd = process.cwd()
}) {
  const start = Date.now();
  const logLine = makeGateLogger({ agentLog, useAgentMode: !!agentLog, cwd });
  if (packages.length === 0) {
    logLine("\u{1F4DD} docs-only mode: no packages to test, skipping");
    return { ok: true, duration: Date.now() - start };
  }
  logLine(`
> Tests (docs-only filtered: ${packages.join(", ")})
`);
  const gatesCommands = resolveGatesCommands(cwd);
  if (gatesCommands.test_docs_only) {
    const result2 = run(gatesCommands.test_docs_only, { agentLog, cwd });
    return { ok: result2.ok, duration: Date.now() - start };
  }
  const filterArgs = packages.map((pkg) => `--filter=${pkg}`);
  const baseCmd = gatesCommands.test_full;
  const filteredCmd = `${baseCmd} ${filterArgs.join(" ")}`;
  const result = run(filteredCmd, { agentLog });
  return { ok: result.ok, duration: Date.now() - start };
}

// src/gate-defaults.ts
function registerDocsOnlyGates(registry, options) {
  const { laneHealthMode, testsRequired, docsOnlyTestPlan } = options;
  registry.register({
    name: GATE_NAMES.INVARIANTS,
    cmd: GATE_COMMANDS.INVARIANTS
  });
  registry.register({
    name: GATE_NAMES.FORMAT_CHECK,
    scriptName: SCRIPTS.FORMAT_CHECK,
    // run function is injected by the gate runner (runFormatCheckGate)
    // We use a sentinel to indicate this gate needs its run function set
    cmd: void 0,
    run: void 0
  });
  registry.register({
    name: GATE_NAMES.SPEC_LINTER,
    scriptName: SCRIPTS.SPEC_LINTER
  });
  registry.register({
    name: GATE_NAMES.BACKLOG_SYNC
  });
  registry.register({
    name: GATE_NAMES.CLAIM_VALIDATION
  });
  registry.register({
    name: GATE_NAMES.LANE_HEALTH,
    warnOnly: laneHealthMode !== "error"
  });
  registry.register({
    name: GATE_NAMES.ONBOARDING_SMOKE_TEST,
    cmd: GATE_COMMANDS.ONBOARDING_SMOKE_TEST
  });
  if (docsOnlyTestPlan && docsOnlyTestPlan.mode === "filtered") {
    registry.register({
      name: GATE_NAMES.TEST,
      warnOnly: !testsRequired
    });
  }
}
function registerCodeGates(registry, options) {
  const {
    isFullLint,
    isFullTests,
    isFullCoverage,
    laneHealthMode,
    testsRequired,
    shouldRunIntegration,
    configuredTestFullCmd
  } = options;
  registry.register({
    name: GATE_NAMES.INVARIANTS,
    cmd: GATE_COMMANDS.INVARIANTS
  });
  registry.register({
    name: GATE_NAMES.FORMAT_CHECK,
    scriptName: SCRIPTS.FORMAT_CHECK
  });
  registry.register({
    name: GATE_NAMES.LINT,
    cmd: isFullLint ? `pnpm ${SCRIPTS.LINT}` : GATE_COMMANDS.INCREMENTAL,
    scriptName: SCRIPTS.LINT
  });
  registry.register({
    name: GATE_NAMES.CO_CHANGE,
    run: runCoChangeGate
  });
  registry.register({
    name: GATE_NAMES.TYPECHECK,
    cmd: `pnpm ${SCRIPTS.TYPECHECK}`,
    scriptName: SCRIPTS.TYPECHECK
  });
  registry.register({
    name: GATE_NAMES.SPEC_LINTER,
    scriptName: SCRIPTS.SPEC_LINTER
  });
  registry.register({
    name: GATE_NAMES.BACKLOG_SYNC
  });
  registry.register({
    name: GATE_NAMES.CLAIM_VALIDATION
  });
  registry.register({
    name: GATE_NAMES.SUPABASE_DOCS_LINTER
  });
  registry.register({
    name: GATE_NAMES.LANE_HEALTH,
    warnOnly: laneHealthMode !== "error"
  });
  registry.register({
    name: GATE_NAMES.ONBOARDING_SMOKE_TEST,
    cmd: GATE_COMMANDS.ONBOARDING_SMOKE_TEST
  });
  registry.register({
    name: GATE_NAMES.SAFETY_CRITICAL_TEST,
    cmd: GATE_COMMANDS.SAFETY_CRITICAL_TEST,
    warnOnly: !testsRequired
  });
  registry.register({
    name: GATE_NAMES.TEST,
    cmd: isFullTests || isFullCoverage ? configuredTestFullCmd : GATE_COMMANDS.INCREMENTAL_TEST,
    warnOnly: !testsRequired
  });
  if (shouldRunIntegration) {
    registry.register({
      name: GATE_NAMES.INTEGRATION_TEST,
      cmd: GATE_COMMANDS.TIERED_TEST,
      warnOnly: !testsRequired
    });
  }
  registry.register({
    name: GATE_NAMES.COVERAGE,
    cmd: GATE_COMMANDS.COVERAGE_GATE
  });
}

// src/onboarding-smoke-test.ts
import * as fs from "fs";
import * as path8 from "path";
import * as os from "os";
import * as yaml from "yaml";
import { execFileSync } from "child_process";
var PACKAGE_JSON_FILE = "package.json";
var WORKSPACE_CONFIG_FILE = WORKSPACE_CONFIG_FILE_NAME;
var SOFTWARE_DELIVERY_KEY = WORKSPACE_V2_KEYS.SOFTWARE_DELIVERY;
var GIT_BINARY = "git";
var REQUIRED_SCRIPTS = ["wu:claim", "wu:done", "wu:create", "gates"];
function asRecord(value) {
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
}
function validateInitScripts(options) {
  const { projectDir } = options;
  const packageJsonPath = path8.join(projectDir, PACKAGE_JSON_FILE);
  if (!fs.existsSync(packageJsonPath)) {
    return {
      valid: false,
      missingScripts: [],
      invalidScripts: [],
      error: `${PACKAGE_JSON_FILE} not found in ${projectDir}`
    };
  }
  let packageJson;
  try {
    packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
  } catch (err) {
    return {
      valid: false,
      missingScripts: [],
      invalidScripts: [],
      error: `Failed to parse ${PACKAGE_JSON_FILE}: ${err instanceof Error ? err.message : String(err)}`
    };
  }
  const scripts = packageJson.scripts ?? {};
  const missingScripts = [];
  const invalidScripts = [];
  for (const script of REQUIRED_SCRIPTS) {
    if (!scripts[script]) {
      missingScripts.push(script);
    } else {
      const value = scripts[script];
      if (value.includes("pnpm exec") || value.includes("npx lumenflow")) {
        invalidScripts.push(script);
      }
    }
  }
  return {
    valid: missingScripts.length === 0 && invalidScripts.length === 0,
    missingScripts,
    invalidScripts
  };
}
function validateWorkspaceLaneScaffold(options) {
  const { projectDir } = options;
  const configPath = path8.join(projectDir, WORKSPACE_CONFIG_FILE);
  if (!fs.existsSync(configPath)) {
    return {
      valid: false,
      errors: [],
      error: `${WORKSPACE_CONFIG_FILE} not found in ${projectDir}`
    };
  }
  const legacyLaneInferencePath = path8.join(projectDir, ".lumenflow.lane-inference.yaml");
  if (fs.existsSync(legacyLaneInferencePath)) {
    return {
      valid: false,
      errors: [],
      error: `.lumenflow.lane-inference.yaml should not be scaffolded in ${projectDir}`
    };
  }
  let content;
  try {
    const rawContent = fs.readFileSync(configPath, "utf-8");
    content = yaml.parse(rawContent) ?? {};
  } catch (err) {
    return {
      valid: false,
      errors: [],
      error: `Failed to parse ${WORKSPACE_CONFIG_FILE}: ${err instanceof Error ? err.message : String(err)}`
    };
  }
  const errors = [];
  const lifecycleStatus = content?.software_delivery?.lanes?.lifecycle?.status;
  if (lifecycleStatus !== "unconfigured") {
    errors.push(
      `Expected ${WORKSPACE_CONFIG_FILE} lane lifecycle to remain "unconfigured" after init.`
    );
  }
  return {
    valid: errors.length === 0,
    errors
  };
}
function initializeGitRepo(projectDir) {
  execFileSync(GIT_BINARY, ["init"], { cwd: projectDir, stdio: "pipe" });
  execFileSync(GIT_BINARY, ["config", "user.email", "test@example.com"], {
    cwd: projectDir,
    stdio: "pipe"
  });
  execFileSync(GIT_BINARY, ["config", "user.name", "Test User"], {
    cwd: projectDir,
    stdio: "pipe"
  });
  execFileSync(GIT_BINARY, ["add", "-A"], { cwd: projectDir, stdio: "pipe" });
  execFileSync(GIT_BINARY, ["commit", "-m", "Initial commit", "--allow-empty"], {
    cwd: projectDir,
    stdio: "pipe"
  });
}
function createSampleWuYaml(projectDir) {
  const wuDir = path8.join(projectDir, createWuPaths({ projectRoot: projectDir }).WU_DIR());
  fs.mkdirSync(wuDir, { recursive: true });
  const wuYaml = `id: WU-TEST-001
title: Test WU
lane: 'Framework: Core'
type: feature
status: ready
priority: P3
created: 2026-02-02
code_paths:
  - 'src/**'
acceptance:
  - Test passes
`;
  fs.writeFileSync(path8.join(wuDir, "WU-TEST-001.yaml"), wuYaml);
}
async function validateWuCreate(options) {
  const { projectDir } = options;
  const configPath = path8.join(projectDir, WORKSPACE_CONFIG_FILE);
  const existingWorkspace = fs.existsSync(configPath) ? asRecord(yaml.parse(fs.readFileSync(configPath, "utf-8"))) : null;
  const workspace = existingWorkspace ?? {};
  const softwareDelivery = asRecord(workspace[SOFTWARE_DELIVERY_KEY]) ?? {};
  const gitConfig = asRecord(softwareDelivery.git) ?? {};
  gitConfig.requireRemote = false;
  softwareDelivery.git = gitConfig;
  workspace[SOFTWARE_DELIVERY_KEY] = softwareDelivery;
  fs.writeFileSync(configPath, yaml.stringify(workspace));
  try {
    initializeGitRepo(projectDir);
  } catch (err) {
    return {
      success: false,
      error: `Failed to initialize git repo: ${err instanceof Error ? err.message : String(err)}`
    };
  }
  createSampleWuYaml(projectDir);
  return { success: true };
}
function collectScriptsErrors(scriptsResult) {
  const errors = [];
  if (scriptsResult.error) {
    errors.push(`Init scripts validation error: ${scriptsResult.error}`);
  }
  if (scriptsResult.missingScripts.length > 0) {
    errors.push(`Missing scripts: ${scriptsResult.missingScripts.join(", ")}`);
  }
  if (scriptsResult.invalidScripts.length > 0) {
    errors.push(`Invalid script format: ${scriptsResult.invalidScripts.join(", ")}`);
  }
  return errors;
}
function collectLaneErrors(laneResult) {
  const errors = [];
  if (laneResult.error) {
    errors.push(`Workspace lane validation error: ${laneResult.error}`);
  }
  errors.push(...laneResult.errors);
  return errors;
}
async function runValidations(tempDir, skipWuCreate) {
  const errors = [];
  await scaffoldProject(tempDir, { force: true, full: true });
  const scriptsResult = validateInitScripts({ projectDir: tempDir });
  if (!scriptsResult.valid) {
    errors.push(...collectScriptsErrors(scriptsResult));
  }
  const laneResult = validateWorkspaceLaneScaffold({ projectDir: tempDir });
  if (!laneResult.valid) {
    errors.push(...collectLaneErrors(laneResult));
  }
  let wuResult;
  if (!skipWuCreate) {
    wuResult = await validateWuCreate({ projectDir: tempDir });
    if (!wuResult.success && wuResult.error) {
      errors.push(`wu:create validation error: ${wuResult.error}`);
    }
  }
  return { scriptsResult, laneResult, wuResult, errors };
}
function cleanupTempDir(tempDir) {
  if (tempDir && fs.existsSync(tempDir)) {
    try {
      fs.rmSync(tempDir, { recursive: true, force: true });
    } catch {
    }
  }
}
async function runOnboardingSmokeTest(options = {}) {
  const { cleanup = true, skipWuCreate = false } = options;
  let { tempDir } = options;
  const result = {
    success: false,
    errors: []
  };
  if (!tempDir) {
    tempDir = fs.mkdtempSync(path8.join(os.tmpdir(), "lumenflow-smoke-test-"));
    result.tempDir = tempDir;
  }
  if (!fs.existsSync(tempDir)) {
    try {
      fs.mkdirSync(tempDir, { recursive: true });
    } catch (err) {
      return {
        success: false,
        errors: [
          `Failed to create temp directory: ${err instanceof Error ? err.message : String(err)}`
        ]
      };
    }
  }
  try {
    const { scriptsResult, laneResult, wuResult, errors } = await runValidations(
      tempDir,
      skipWuCreate
    );
    result.initScriptsValidation = scriptsResult;
    result.workspaceLaneValidation = laneResult;
    result.wuCreateValidation = wuResult;
    result.errors = errors;
    result.success = errors.length === 0;
  } catch (err) {
    result.errors = [`Smoke test failed: ${err instanceof Error ? err.message : String(err)}`];
    result.success = false;
  } finally {
    if (cleanup) {
      cleanupTempDir(tempDir);
    }
  }
  return result;
}
async function runOnboardingSmokeTestGate(options) {
  const start = Date.now();
  const logger = options.logger ?? console;
  logger.log("Running onboarding smoke test...");
  const result = await runOnboardingSmokeTest({ cleanup: true });
  if (result.success) {
    logger.log("Onboarding smoke test passed.");
  } else {
    logger.log("Onboarding smoke test failed:");
    for (const error of result.errors) {
      logger.log(`  - ${error}`);
    }
  }
  return {
    ok: result.success,
    duration: Date.now() - start
  };
}

// src/gates.ts
var GATES_OPTIONS = {
  docsOnly: {
    name: "docsOnly",
    flags: "--docs-only",
    description: "Run docs-only gates (format, spec-linter, backlog-sync)"
  },
  fullLint: {
    name: "fullLint",
    flags: "--full-lint",
    description: "Run full lint instead of incremental"
  },
  fullTests: {
    name: "fullTests",
    flags: "--full-tests",
    description: "Run full test suite instead of incremental"
  },
  fullCoverage: {
    name: "fullCoverage",
    flags: "--full-coverage",
    description: "Force full test suite and coverage gate (implies --full-tests)"
  },
  coverageMode: {
    name: "coverageMode",
    flags: "--coverage-mode <mode>",
    description: 'Coverage gate mode: "warn" logs warnings, "block" fails gate',
    default: "block"
  },
  verbose: {
    name: "verbose",
    flags: "--verbose",
    description: "Stream output in agent mode instead of logging to file"
  },
  // WU-1520: --strict flag makes missing scripts a hard failure for CI
  strict: {
    name: "strict",
    flags: "--strict",
    description: "Fail on missing gate scripts instead of skipping (for CI enforcement)"
  }
};
function parseGatesOptions() {
  const originalArgv = process.argv;
  const filteredArgv = originalArgv.filter((arg, index, arr) => {
    if (arg === "--") {
      const nextArg = arr[index + 1];
      return Boolean(nextArg && !nextArg.startsWith("-"));
    }
    return true;
  });
  process.argv = filteredArgv;
  try {
    const opts = createWUParser({
      name: "gates",
      description: "Run quality gates with support for docs-only mode, incremental linting, and tiered testing",
      options: Object.values(GATES_OPTIONS)
    });
    return {
      docsOnly: opts.docsOnly,
      fullLint: opts.fullLint,
      fullTests: opts.fullTests,
      fullCoverage: opts.fullCoverage,
      coverageMode: opts.coverageMode ?? "block",
      verbose: opts.verbose,
      strict: opts.strict
    };
  } finally {
    process.argv = originalArgv;
  }
}
async function runGates(options = {}) {
  try {
    return await executeGates({
      ...options,
      cwd: options.cwd ?? process.cwd(),
      coverageMode: options.coverageMode ?? COVERAGE_GATE_MODES.BLOCK
    });
  } catch {
    return false;
  }
}
async function syncGatesTelemetryToCloud(input = {}) {
  return syncNdjsonTelemetryToCloud({
    workspaceRoot: input.cwd ?? process.cwd(),
    fetchFn: input.fetchFn,
    logger: input.logger,
    now: input.now,
    environment: input.environment
  });
}
async function executeGates(opts) {
  const cwd = opts.cwd ?? process.cwd();
  const argv = opts.argv ?? process.argv.slice(2);
  const wu_id = getCurrentWU();
  const lane = getCurrentLane();
  const useAgentMode = shouldUseGatesAgentMode({ argv, env: process.env });
  const agentLog = useAgentMode ? createAgentLogContext({ wuId: wu_id, lane, cwd }) : null;
  if (useAgentMode && !agentLog) {
    die("Failed to initialize agent-mode gate log context");
  }
  const isDocsOnly = opts.docsOnly || false;
  const isFullLint = opts.fullLint || false;
  const isFullTests = opts.fullTests || false;
  const isFullCoverage = opts.fullCoverage || false;
  const resolvedTestPolicy = resolveTestPolicy(cwd);
  const coverageMode = opts.coverageMode || resolvedTestPolicy.mode || COVERAGE_GATE_MODES.BLOCK;
  const coverageThreshold = resolvedTestPolicy.threshold;
  const testsRequired = resolvedTestPolicy.tests_required;
  const laneHealthMode = loadLaneHealthConfig(cwd);
  const configuredGatesCommands = resolveGatesCommands(cwd);
  const isStrict = opts.strict || false;
  const packageJsonScripts = loadPackageJsonScripts(cwd);
  const gateResults = [];
  const telemetrySyncLogger = {
    warn: (message) => {
      if (useAgentMode) {
        writeSync3(agentLog.logFd, `${message}
`);
        return;
      }
      console.warn(message);
    }
  };
  async function flushTelemetryToCloud() {
    try {
      await syncGatesTelemetryToCloud({
        cwd,
        logger: telemetrySyncLogger
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);
      telemetrySyncLogger.warn(`[gates] cloud telemetry sync failed unexpectedly: ${message}`);
    }
  }
  if (useAgentMode) {
    console.log(
      `\u{1F9FE} gates (agent mode): output -> ${agentLog.logPath} (use --verbose for streaming)
`
    );
  }
  let riskTier = null;
  if (!isDocsOnly) {
    riskTier = {
      tier: "standard",
      isDocsOnly: false,
      shouldRunIntegration: false,
      highRiskPaths: []
    };
  }
  const effectiveDocsOnly = isDocsOnly || riskTier && riskTier.isDocsOnly;
  let docsOnlyTestPlan = null;
  if (effectiveDocsOnly) {
    const codePaths = loadCurrentWUCodePaths({ cwd });
    docsOnlyTestPlan = resolveDocsOnlyTestPlan({ codePaths });
  }
  const gateRegistry = new GateRegistry();
  if (effectiveDocsOnly) {
    registerDocsOnlyGates(gateRegistry, {
      laneHealthMode,
      testsRequired,
      docsOnlyTestPlan
    });
  } else {
    registerCodeGates(gateRegistry, {
      isFullLint,
      isFullTests,
      isFullCoverage,
      laneHealthMode,
      testsRequired,
      shouldRunIntegration: !!(riskTier && riskTier.shouldRunIntegration),
      configuredTestFullCmd: configuredGatesCommands.test_full
    });
  }
  const gateRunFunctions = {
    [GATE_NAMES.FORMAT_CHECK]: runFormatCheckGate,
    [GATE_NAMES.SPEC_LINTER]: runSpecLinterGate,
    [GATE_NAMES.CLAIM_VALIDATION]: runClaimValidationGate,
    [GATE_NAMES.BACKLOG_SYNC]: runBacklogSyncGate,
    [GATE_NAMES.SUPABASE_DOCS_LINTER]: runSupabaseDocsGate,
    [GATE_NAMES.LANE_HEALTH]: (ctx) => runLaneHealthGate({ ...ctx, mode: laneHealthMode })
  };
  if (docsOnlyTestPlan && docsOnlyTestPlan.mode === "filtered") {
    gateRunFunctions[GATE_NAMES.TEST] = (ctx) => {
      const pkgs = docsOnlyTestPlan.packages;
      return runDocsOnlyFilteredTests({
        packages: pkgs,
        agentLog: ctx.agentLog,
        cwd: ctx.cwd
      });
    };
  }
  const gates = gateRegistry.getAll().map((gate) => {
    const runFn = gateRunFunctions[gate.name];
    if (runFn && !gate.run) {
      return { ...gate, run: runFn };
    }
    return gate;
  });
  if (effectiveDocsOnly) {
    const docsOnlyMessage = docsOnlyTestPlan && docsOnlyTestPlan.mode === "filtered" ? formatDocsOnlySkipMessage(docsOnlyTestPlan) : "\u{1F4DD} Docs-only mode: skipping lint, typecheck, and all tests (no code packages in code_paths)";
    if (!useAgentMode) {
      console.log(`${docsOnlyMessage}
`);
    } else {
      writeSync3(agentLog.logFd, `${docsOnlyMessage}
`);
    }
  }
  let lastTestResult = null;
  let lastFormatCheckFiles = null;
  for (const gate of gates) {
    let result;
    const gateScriptName = gate.scriptName ?? null;
    const gateAction = resolveGateAction(gate.name, gateScriptName, packageJsonScripts, isStrict);
    if (gateAction === "skip") {
      const logLine = makeGateLogger({ agentLog, useAgentMode, cwd });
      const warningMsg = buildMissingScriptWarning(gateScriptName);
      logLine(`
${warningMsg}
`);
      gateResults.push({
        name: gate.name,
        status: "skipped",
        durationMs: 0,
        reason: "script not found in package.json"
      });
      continue;
    }
    if (gateAction === "fail") {
      const logLine = makeGateLogger({ agentLog, useAgentMode, cwd });
      logLine(`
\u274C "${gateScriptName}" script not found in package.json (--strict mode)
`);
      gateResults.push({
        name: gate.name,
        status: "failed",
        durationMs: 0,
        reason: "script not found in package.json (strict mode)"
      });
      die(
        `${gate.name} failed: missing script "${gateScriptName}" in package.json (--strict mode requires all gate scripts)`
      );
    }
    if (gate.run) {
      result = await gate.run({ agentLog, useAgentMode, cwd });
      if (gate.name === GATE_NAMES.FORMAT_CHECK) {
        lastFormatCheckFiles = result.filesChecked ?? null;
      }
    } else if (gate.cmd === GATE_COMMANDS.INVARIANTS) {
      const logLine = useAgentMode ? (line) => writeSync3(agentLog.logFd, `${line}
`) : (line) => console.log(line);
      logLine("\n> Invariants check\n");
      const invariantsResult = runInvariants({ baseDir: cwd, silent: false });
      result = {
        ok: invariantsResult.success,
        duration: 0
        // runInvariants doesn't track duration
      };
      if (!result.ok) {
        logLine("");
        logLine(invariantsResult.formatted);
      }
    } else if (gate.cmd === GATE_COMMANDS.INCREMENTAL) {
      result = await runIncrementalLint({ agentLog, cwd });
    } else if (gate.cmd === GATE_COMMANDS.SAFETY_CRITICAL_TEST) {
      result = await runSafetyCriticalTests({ agentLog, cwd });
    } else if (gate.cmd === GATE_COMMANDS.INCREMENTAL_TEST) {
      result = await runChangedTests({
        agentLog,
        cwd,
        scopedTestPaths: opts.scopedTestPaths
      });
      lastTestResult = result;
    } else if (gate.cmd === GATE_COMMANDS.TIERED_TEST) {
      result = await runIntegrationTests({ agentLog, cwd });
    } else if (gate.cmd === GATE_COMMANDS.COVERAGE_GATE) {
      if (!isFullCoverage && lastTestResult?.isIncremental) {
        const msg = "\u23ED\uFE0F  Skipping coverage gate (changed tests - coverage is partial)";
        if (!useAgentMode) {
          console.log(`
${msg}
`);
        } else {
          writeSync3(agentLog.logFd, `
${msg}

`);
        }
        gateResults.push({
          name: gate.name,
          status: "skipped",
          durationMs: 0,
          reason: "changed tests - coverage is partial"
        });
        continue;
      }
      if (!useAgentMode) {
        console.log(
          `
> Coverage gate (mode: ${coverageMode}, threshold: ${coverageThreshold}%)
`
        );
      } else {
        writeSync3(
          agentLog.logFd,
          `
> Coverage gate (mode: ${coverageMode}, threshold: ${coverageThreshold}%)

`
        );
      }
      result = await runCoverageGate({
        mode: coverageMode,
        // WU-1262: Pass resolved threshold from methodology policy
        threshold: coverageThreshold,
        logger: useAgentMode ? {
          log: (msg) => {
            writeSync3(agentLog.logFd, `${msg}
`);
          }
        } : console
      });
    } else if (gate.cmd === GATE_COMMANDS.ONBOARDING_SMOKE_TEST) {
      const logLine = useAgentMode ? (line) => writeSync3(agentLog.logFd, `${line}
`) : (line) => console.log(line);
      logLine("\n> Onboarding smoke test\n");
      result = await runOnboardingSmokeTestGate({
        logger: { log: logLine }
      });
    } else {
      if (!gate.cmd) {
        die(`${gate.name} failed: gate command is not configured`);
      }
      result = run(gate.cmd, { agentLog, cwd });
    }
    emitGateEvent({
      wu_id,
      lane,
      gate_name: gate.name,
      passed: result.ok,
      duration_ms: result.duration
    });
    if (!result.ok) {
      if (gate.warnOnly) {
        const warnMsg = `\u26A0\uFE0F  ${gate.name} failed (warn-only, not blocking)`;
        if (!useAgentMode) {
          console.log(`
${warnMsg}
`);
        } else {
          writeSync3(agentLog.logFd, `
${warnMsg}

`);
        }
        gateResults.push({
          name: gate.name,
          status: "warned",
          durationMs: result.duration
        });
        continue;
      }
      if (gate.name === GATE_NAMES.FORMAT_CHECK) {
        emitFormatCheckGuidance({ agentLog, useAgentMode, files: lastFormatCheckFiles, cwd });
      }
      gateResults.push({
        name: gate.name,
        status: "failed",
        durationMs: result.duration
      });
      const logLine = makeGateLogger({ agentLog, useAgentMode, cwd });
      logLine(`
${formatGateSummary(gateResults)}
`);
      if (useAgentMode) {
        const tail = readLogTail(agentLog.logPath);
        console.error(`
\u274C ${gate.name} failed (agent mode). Log: ${agentLog.logPath}
`);
        if (tail) {
          console.error(`Last log lines:
${tail}
`);
        }
      }
      await flushTelemetryToCloud();
      die(`${gate.name} failed`);
    }
    gateResults.push({
      name: gate.name,
      status: "passed",
      durationMs: result.duration
    });
  }
  if (agentLog) {
    updateGatesLatestSymlink({ logPath: agentLog.logPath, cwd, env: process.env });
  }
  const summaryLogLine = makeGateLogger({ agentLog, useAgentMode, cwd });
  summaryLogLine(`
${formatGateSummary(gateResults)}`);
  if (!useAgentMode) {
    console.log(`
${chalk.green("\u2705 All gates passed!")}
`);
  } else {
    console.log(
      `${chalk.green("\u2705 All gates passed")} (agent mode). Log: ${agentLog.logPath}
`
    );
  }
  await flushTelemetryToCloud();
  return true;
}
async function main() {
  const opts = parseGatesOptions();
  const ok = await executeGates({ ...opts, argv: process.argv.slice(2) });
  if (!ok) {
    process.exit(EXIT_CODES.ERROR);
  }
}
if (import.meta.main) {
  void runCLI(main);
}

export {
  resolveWuDonePreCommitGateDecision,
  parsePrettierListOutput,
  buildPrettierWriteCommand,
  formatFormatCheckGuidance,
  parseWUFromBranchName,
  extractPackagesFromCodePaths,
  loadCurrentWUCodePaths,
  isPrettierConfigFile,
  isTestConfigFile,
  resolveFormatCheckPlan,
  resolveLintPlan,
  resolveTestPlan,
  resolveDocsOnlyTestPlan,
  formatDocsOnlySkipMessage,
  resolveSpecLinterPlan,
  GATES_OPTIONS,
  parseGatesOptions,
  runGates,
  syncGatesTelemetryToCloud,
  main
};
