{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "detect",
  "title": "detect",
  "description": "Environment detection helpers: `isWsl`, `isCi`, `isHeadlessLinux`, `hasCommand`, `detectMode`, `shouldColor`. Shared across platform and agent blocks. Auto-installed as dependency.",
  "files": [
    {
      "path": "registry/platform/detect.ts",
      "content": "// cligentic block: detect\n//\n// Environment detection helpers shared across platform blocks.\n// Detects WSL, CI, headless environments, and binary availability.\n//\n// Usage:\n//   import { isWsl, isCi, hasCommand } from \"./platform/detect\";\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { platform } from \"node:os\";\n\n/**\n * Detects WSL (Windows Subsystem for Linux). Reads /proc/version once\n * and caches the result for the lifetime of the process.\n */\nlet wslCache: boolean | null = null;\nexport function isWsl(): boolean {\n  if (wslCache !== null) return wslCache;\n  if (platform() !== \"linux\") {\n    wslCache = false;\n    return false;\n  }\n  try {\n    const version = readFileSync(\"/proc/version\", \"utf8\").toLowerCase();\n    wslCache = version.includes(\"microsoft\") || version.includes(\"wsl\");\n  } catch {\n    wslCache = false;\n  }\n  return wslCache;\n}\n\n/**\n * Detects CI environments. Checks standard CI env vars.\n */\nexport function isCi(): boolean {\n  return Boolean(\n    process.env.CI ||\n      process.env.CONTINUOUS_INTEGRATION ||\n      process.env.GITHUB_ACTIONS ||\n      process.env.GITLAB_CI ||\n      process.env.CIRCLECI ||\n      process.env.BUILDKITE,\n  );\n}\n\n/**\n * Detects headless Linux (no graphical display).\n * WSL is NOT headless because it can open browsers on the Windows host.\n */\nexport function isHeadlessLinux(): boolean {\n  if (platform() !== \"linux\") return false;\n  if (isWsl()) return false;\n  return !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY;\n}\n\n/**\n * Checks if a command exists in PATH. Handles Windows .exe/.cmd/.bat\n * extensions automatically.\n */\nexport function hasCommand(cmd: string): boolean {\n  const separator = platform() === \"win32\" ? \";\" : \":\";\n  const paths = (process.env.PATH || \"\").split(separator);\n  const exts = platform() === \"win32\" ? [\".exe\", \".cmd\", \".bat\", \"\"] : [\"\"];\n  for (const p of paths) {\n    for (const ext of exts) {\n      if (existsSync(`${p}/${cmd}${ext}`)) return true;\n    }\n  }\n  return false;\n}\n\n// --- Output mode detection (shared by json-mode + next-steps) ---\n\nexport type OutputMode = \"human\" | \"json\";\n\nexport type EmitOptions = {\n  json?: boolean;\n  quiet?: boolean;\n};\n\n/**\n * Detects whether the CLI should emit structured JSON or human output.\n * Precedence: explicit --json flag > NO_JSON env > TTY detection > default human.\n */\nexport function detectMode(opts: EmitOptions = {}): OutputMode {\n  if (opts.json === true) return \"json\";\n  if (process.env.NO_JSON === \"1\") return \"human\";\n  if (!process.stdout.isTTY) return \"json\";\n  return \"human\";\n}\n\n/**\n * Detects whether colors should be used. Respects NO_COLOR and FORCE_COLOR.\n */\nexport function shouldColor(): boolean {\n  if (process.env.NO_COLOR) return false;\n  if (process.env.FORCE_COLOR) return true;\n  return Boolean(process.stdout.isTTY);\n}\n",
      "type": "registry:file",
      "target": "src/cli/platform/detect.ts"
    }
  ],
  "type": "registry:file"
}