Ctrl K
ComunidadGuías…

electron/cua-hyprland.cjs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// Omarchy (Arch + Hyprland) support for "This computer". Every other Wayland desktop stays blocked: only Hyprland with
// Cua's own compositor plugin gives the agent seats of its own, so the person's pointer and keyboard are never shared.
// https://cua.ai/docs/cua-sdk/guides/omarchy
const { spawn } = require("node:child_process");
const fs = require("node:fs");

const OMARCHY_GUIDE_URL = "https://cua.ai/docs/cua-sdk/guides/omarchy";
const HYPRCTL = "/usr/bin/hyprctl";
const PACMAN = "/usr/bin/pacman";
const SYSTEM_DRIVER = "/usr/bin/cua-driver";
const SYSTEM_DRIVER_PACKAGE = "cua-driver-bin";
const PROBE_TIMEOUT_MS = 2_000;
const MAX_OUTPUT_BYTES = 64 * 1024;

const PLUGIN_REQUIRED_MESSAGE =
  "To use This computer on Omarchy, install and enable cua-hyprland-plugin, reload Hyprland, then try again " +
  `(Cua's Omarchy guide: ${OMARCHY_GUIDE_URL}).`;

function desktopNames(env) {
  return [env.XDG_CURRENT_DESKTOP, env.XDG_SESSION_DESKTOP]
    .flatMap((value) => String(value ?? "").toLowerCase().split(":"))
    .filter(Boolean);
}

/** A Hyprland session: Hyprland's own instance signature, and the desktop names it as Hyprland. */
function isHyprlandSession(env = process.env) {
  const signature = String(env.HYPRLAND_INSTANCE_SIGNATURE ?? "");
  return /^[A-Za-z0-9_.-]{1,200}$/.test(signature) && desktopNames(env).includes("hyprland");
}

const isObject = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);

/**
 * Read `hyprctl -j cua:status`. Active only when the input build of the plugin is loaded into this compositor (ABI
 * match), configured on, and its input transport is up. A loaded discovery-only module, a disabled plugin, a stale
 * module after a Hyprland update, or anything unreadable is not active.
 */
function parseCuaPluginStatus(stdout) {
  let status;
  try {
    status = JSON.parse(String(stdout ?? ""));
  } catch {
    return "inactive";
  }
  if (!isObject(status) || status.name !== "cua-hyprland-plugin") return "inactive";
  const input = status.input;
  const active =
    status.state === "input_v3_candidate" &&
    status.configured === true &&
    isObject(status.abi) && status.abi.match === true &&
    isObject(status.transport) && status.transport.ready === true &&
    isObject(input) && input.transport_ready === true && input.test_only !== true &&
    Number.isSafeInteger(input.protocol) && input.protocol >= 3;
  return active ? "active" : "inactive";
}

/** Run a fixed system binary with no shell, a short deadline and bounded output. */
function runBounded(command, args, { env, timeoutMs = PROBE_TIMEOUT_MS } = {}) {
  return new Promise((resolve) => {
    let child;
    try {
      child = spawn(command, args, { env, shell: false, stdio: ["ignore", "pipe", "ignore"], windowsHide: true });
    } catch {
      resolve({ exitCode: null, stdout: "" });
      return;
    }
    let stdout = "";
    let settled = false;
    const finish = (exitCode) => {
      if (settled) return;
      settled = true;
      clearTimeout(timer);
      resolve({ exitCode, stdout });
    };
    child.stdout.setEncoding("utf8");
    child.stdout.on("data", (chunk) => {
      stdout += chunk;
      if (stdout.length > MAX_OUTPUT_BYTES) {
        child.kill("SIGKILL");
        stdout = "";
        finish(null);
      }
    });
    child.once("error", () => finish(null));
    child.once("close", (code) => finish(code));
    const timer = setTimeout(() => {
      child.kill("SIGKILL");
      finish(null);
    }, timeoutMs);
    timer.unref?.();
  });
}

/** Whether Cua's Hyprland plugin is active in this session. Uses the system hyprctl only, never one from PATH. */
async function probeCuaHyprlandPlugin({ env = process.env, run = runBounded, exists = fs.existsSync } = {}) {
  if (!isHyprlandSession(env) || !exists(HYPRCTL)) return "inactive";
  const result = await run(HYPRCTL, ["-j", "cua:status"], {
    env: { ...env, LANG: "C", LC_ALL: "C" },
  });
  return result.exitCode === 0 ? parseCuaPluginStatus(result.stdout) : "inactive";
}

const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");

/**
 * Whether pacman's database says the cua-driver-bin package owns `file`. Returns that package version, or null.
 * pacman prints `/usr/bin/cua-driver is owned by cua-driver-bin 0.41.3-1`.
 */
async function systemDriverPackageVersion(file = SYSTEM_DRIVER, { run = runBounded, exists = fs.existsSync } = {}) {
  if (typeof file !== "string" || !file.startsWith("/") || !exists(PACMAN) || !exists(file)) return null;
  const result = await run(PACMAN, ["-Qo", file], {
    env: { PATH: "/usr/bin:/bin", LANG: "C", LC_ALL: "C" },
  });
  if (result.exitCode !== 0) return null;
  const owned = new RegExp(`^${escapeRegExp(file)} is owned by ${SYSTEM_DRIVER_PACKAGE} (\\S+)$`);
  return owned.exec(String(result.stdout).trim())?.[1] ?? null;
}

module.exports = {
  HYPRCTL,
  OMARCHY_GUIDE_URL,
  PACMAN,
  PLUGIN_REQUIRED_MESSAGE,
  SYSTEM_DRIVER,
  SYSTEM_DRIVER_PACKAGE,
  isHyprlandSession,
  parseCuaPluginStatus,
  probeCuaHyprlandPlugin,
  runBounded,
  systemDriverPackageVersion,
};