// @bun
// packages/runtime/src/broker-process-manager.ts
import { spawnSync } from "child_process";
import { chmodSync, existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
import { homedir as homedir3 } from "os";
import { dirname as dirname2, join as join3, resolve as resolve2 } from "path";
import { fileURLToPath } from "url";

// packages/runtime/src/broker-api.ts
import { request as httpRequest } from "http";
var DEFAULT_BROKER_JSON_REQUEST_TIMEOUT_MS = 30000;
function normalizeBaseUrl(baseUrl) {
  const trimmed = baseUrl.trim();
  if (!trimmed) {
    return trimmed;
  }
  try {
    return new URL(trimmed).toString();
  } catch {
    return trimmed;
  }
}
function requestHeaders(options) {
  const headers = {
    accept: "application/json",
    ...options.headers ?? {}
  };
  if (options.body !== undefined && !("content-type" in lowercaseKeys(headers))) {
    headers["content-type"] = "application/json";
  }
  return headers;
}
function lowercaseKeys(value) {
  const result = {};
  for (const key of Object.keys(value)) {
    result[key.toLowerCase()] = value[key] ?? "";
  }
  return result;
}
function requestBody(options) {
  return options.body === undefined ? undefined : JSON.stringify(options.body);
}
async function requestBrokerOverHttp(baseUrl, path, options) {
  const response = await fetch(new URL(path, normalizeBaseUrl(baseUrl)), {
    method: options.method ?? (options.body === undefined ? "GET" : "POST"),
    headers: requestHeaders(options),
    body: requestBody(options),
    signal: options.signal
  });
  return {
    ok: response.ok,
    status: response.status,
    text: await response.text()
  };
}
function shouldFallbackFromUnixSocket(error) {
  const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
  return code === "ENOENT" || code === "ECONNREFUSED" || code === "ENOTSOCK" || code === "EACCES" || code === "FailedToOpenSocket";
}
function errorMessage(error) {
  return error instanceof Error ? error.message : String(error);
}
function requestBrokerOverUnixSocket(socketPath, baseUrl, path, options) {
  return new Promise((resolve, reject) => {
    const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
    const url = new URL(path, normalizedBaseUrl);
    const body = requestBody(options);
    const headers = requestHeaders(options);
    if (body !== undefined) {
      headers["content-length"] = Buffer.byteLength(body).toString();
    }
    const request = httpRequest({
      socketPath,
      path: `${url.pathname}${url.search}`,
      method: options.method ?? (body === undefined ? "GET" : "POST"),
      headers
    }, (response) => {
      let text = "";
      response.setEncoding("utf8");
      response.on("data", (chunk) => {
        text += String(chunk);
      });
      response.on("end", () => {
        options.signal?.removeEventListener("abort", handleAbort);
        resolve({
          ok: Boolean(response.statusCode && response.statusCode >= 200 && response.statusCode < 300),
          status: response.statusCode ?? 0,
          text
        });
      });
    });
    const handleAbort = () => {
      request.destroy(options.signal?.reason instanceof Error ? options.signal.reason : new Error("Scout broker request aborted"));
    };
    request.on("error", (error) => {
      options.signal?.removeEventListener("abort", handleAbort);
      reject(error);
    });
    if (options.signal) {
      if (options.signal.aborted) {
        handleAbort();
        return;
      }
      options.signal.addEventListener("abort", handleAbort, { once: true });
    }
    if (body !== undefined) {
      request.write(body);
    }
    request.end();
  });
}
function defaultBrokerRequestSignal(options) {
  return options.signal ?? AbortSignal.timeout(DEFAULT_BROKER_JSON_REQUEST_TIMEOUT_MS);
}
async function requestBrokerWire(baseUrl, path, options) {
  const requestOptions = {
    ...options,
    signal: defaultBrokerRequestSignal(options)
  };
  const socketPath = options.socketPath?.trim();
  if (socketPath) {
    try {
      return {
        response: await requestBrokerOverUnixSocket(socketPath, baseUrl, path, requestOptions),
        trace: {
          transport: "unix_socket",
          socketPath
        }
      };
    } catch (error) {
      if (!shouldFallbackFromUnixSocket(error)) {
        throw error;
      }
      return {
        response: await requestBrokerOverHttp(baseUrl, path, requestOptions),
        trace: {
          transport: "http",
          socketPath,
          socketFallbackError: `${socketPath}: ${errorMessage(error)}`
        }
      };
    }
  }
  return {
    response: await requestBrokerOverHttp(baseUrl, path, requestOptions),
    trace: {
      transport: "http"
    }
  };
}
async function requestScoutBrokerJsonWithTrace(baseUrl, path, options = {}) {
  const { response, trace } = await requestBrokerWire(baseUrl, path, options);
  let parsed;
  let parsedJson = false;
  if (response.text.length > 0) {
    try {
      parsed = JSON.parse(response.text);
      parsedJson = true;
    } catch {
      parsedJson = false;
    }
  }
  if (!response.ok) {
    if (parsedJson && options.acceptErrorJson?.(parsed)) {
      return { value: parsed, trace };
    }
    throw new Error(`${path} returned ${response.status}: ${response.text}`);
  }
  if (parsedJson) {
    return { value: parsed, trace };
  }
  return { value: undefined, trace };
}

// packages/runtime/src/support-paths.ts
import { existsSync, mkdirSync, rmSync, writeFileSync } from "fs";
import { homedir } from "os";
import { join } from "path";
var OPENSCOUT_RPC_CUTOVER_MARKER = "rpc-runtime-cutover-v1";
function resolveOpenScoutSupportPaths() {
  const home = homedir();
  const supportDirectory = process.env.OPENSCOUT_SUPPORT_DIRECTORY ?? join(home, "Library", "Application Support", "OpenScout");
  const logsDirectory = join(supportDirectory, "logs");
  const runtimeDirectory = join(supportDirectory, "runtime");
  const catalogDirectory = join(supportDirectory, "catalog");
  const controlHome = process.env.OPENSCOUT_CONTROL_HOME ?? join(home, ".openscout", "control-plane");
  const knowledgeDirectory = join(controlHome, "knowledge");
  return {
    supportDirectory,
    logsDirectory,
    appLogsDirectory: join(logsDirectory, "app"),
    brokerLogsDirectory: join(logsDirectory, "broker"),
    runtimeDirectory,
    catalogDirectory,
    relayAgentsDirectory: join(runtimeDirectory, "agents"),
    settingsPath: join(supportDirectory, "settings.json"),
    harnessCatalogPath: join(catalogDirectory, "harness-catalog.json"),
    relayAgentsRegistryPath: join(supportDirectory, "relay-agents.json"),
    managedInstallsPath: join(supportDirectory, "managed-installs.json"),
    relayHubDirectory: process.env.OPENSCOUT_RELAY_HUB ?? join(home, ".openscout", "relay"),
    controlHome,
    knowledgeDirectory,
    knowledgeQmdDirectory: join(knowledgeDirectory, "qmd"),
    knowledgeSqlitePath: join(knowledgeDirectory, "knowledge.sqlite"),
    desktopStatusPath: join(supportDirectory, "agent-status.json"),
    workspaceStatePath: join(supportDirectory, "workspace-state.json"),
    cutoverMarkerPath: join(supportDirectory, OPENSCOUT_RPC_CUTOVER_MARKER)
  };
}
function ensureOpenScoutCleanSlateSync() {
  const paths = resolveOpenScoutSupportPaths();
  if (existsSync(paths.cutoverMarkerPath)) {
    return;
  }
  rmSync(paths.supportDirectory, { recursive: true, force: true });
  rmSync(paths.controlHome, { recursive: true, force: true });
  rmSync(paths.relayHubDirectory, { recursive: true, force: true });
  mkdirSync(paths.supportDirectory, { recursive: true });
  writeFileSync(paths.cutoverMarkerPath, `${Date.now()}
`, "utf8");
}

// packages/runtime/src/tool-resolution.ts
import { accessSync, constants, existsSync as existsSync2 } from "fs";
import { homedir as homedir2 } from "os";
import { basename, dirname, join as join2, resolve } from "path";
var DEFAULT_COMMON_EXECUTABLE_DIRECTORIES = [
  join2(homedir2(), ".bun", "bin"),
  "/opt/homebrew/bin",
  "/usr/local/bin"
];
function expandHomePath(value, env = process.env) {
  const home = env.HOME ?? homedir2();
  if (value === "~") {
    return home;
  }
  if (value.startsWith("~/")) {
    return join2(home, value.slice(2));
  }
  return value;
}
function isExecutablePath(candidate) {
  if (!candidate) {
    return false;
  }
  try {
    accessSync(candidate, constants.X_OK);
    return true;
  } catch {
    return false;
  }
}
function splitPathEntries(env = process.env) {
  const separator = process.platform === "win32" ? ";" : ":";
  return (env.PATH ?? "").split(separator).filter(Boolean);
}
function dedupeDirectories(values, env) {
  const seen = new Set;
  const resolvedEntries = [];
  for (const value of values) {
    const normalized = resolve(expandHomePath(value, env));
    if (seen.has(normalized)) {
      continue;
    }
    seen.add(normalized);
    resolvedEntries.push(normalized);
  }
  return resolvedEntries;
}
function resolveExecutableFromSearch(options) {
  const env = options.env ?? process.env;
  const envKeys = options.envKeys ?? [];
  for (const envKey of envKeys) {
    const explicit = env[envKey]?.trim();
    if (!explicit) {
      continue;
    }
    const expanded = expandHomePath(explicit, env);
    if (isExecutablePath(expanded)) {
      return { path: resolve(expanded), source: "env" };
    }
    const foundOnPath = findExecutableOnSearchPath(explicit, env);
    if (foundOnPath) {
      return { path: foundOnPath.path, source: "env" };
    }
  }
  const commonDirectories = dedupeDirectories([...options.commonDirectories ?? DEFAULT_COMMON_EXECUTABLE_DIRECTORIES], env);
  const searchDirectories = dedupeDirectories([
    ...splitPathEntries(env),
    ...options.extraDirectories ?? [],
    ...commonDirectories
  ], env);
  for (const directory of searchDirectories) {
    for (const name of options.names) {
      const candidate = join2(directory, name);
      if (isExecutablePath(candidate)) {
        return {
          path: candidate,
          source: commonDirectories.includes(directory) ? "common-path" : "path"
        };
      }
    }
  }
  return null;
}
function resolveBunExecutable(env = process.env) {
  return resolveExecutableFromSearch({
    env,
    envKeys: ["OPENSCOUT_BUN_BIN", "SCOUT_BUN_BIN", "BUN_BIN"],
    names: ["bun"]
  });
}
function findExecutableOnSearchPath(name, env) {
  const searchDirectories = dedupeDirectories([
    ...splitPathEntries(env),
    ...DEFAULT_COMMON_EXECUTABLE_DIRECTORIES
  ], env);
  for (const directory of searchDirectories) {
    const candidate = join2(directory, name);
    if (isExecutablePath(candidate)) {
      return { path: candidate, source: "path" };
    }
  }
  return null;
}

// packages/runtime/src/broker-process-manager.ts
function isTmpPath(p) {
  return /^\/(?:private\/)?tmp\//.test(p);
}
var DEFAULT_BROKER_HOST = "127.0.0.1";
var DEFAULT_BROKER_HOST_MESH = "0.0.0.0";
var DEFAULT_BROKER_PORT = 65535;
var DEFAULT_ADVERTISE_SCOPE = "local";
function resolveAdvertiseScope() {
  const raw = (process.env.OPENSCOUT_ADVERTISE_SCOPE ?? "").trim().toLowerCase();
  if (raw === "mesh")
    return "mesh";
  if (raw === "local")
    return "local";
  return DEFAULT_ADVERTISE_SCOPE;
}
function resolveBrokerHost(scope = resolveAdvertiseScope()) {
  const explicit = process.env.OPENSCOUT_BROKER_HOST;
  if (typeof explicit === "string" && explicit.trim().length > 0) {
    return explicit;
  }
  return scope === "mesh" ? DEFAULT_BROKER_HOST_MESH : DEFAULT_BROKER_HOST;
}
function isLoopbackHost(host) {
  const trimmed = host.trim();
  return trimmed === "127.0.0.1" || trimmed === "::1" || trimmed === "localhost";
}
var BROKER_SERVICE_POLL_INTERVAL_MS = 100;
var DEFAULT_BROKER_START_TIMEOUT_MS = 15000;
var DEFAULT_BROKER_STOP_TIMEOUT_MS = 20000;
function buildDefaultBrokerUrl(host = DEFAULT_BROKER_HOST, port = DEFAULT_BROKER_PORT) {
  return `http://${host}:${port}`;
}
function buildDefaultBrokerSocketPath(runtimeDirectory) {
  return join3(runtimeDirectory, "broker.sock");
}
var DEFAULT_BROKER_URL = buildDefaultBrokerUrl();
function normalizeBrokerUrl(value) {
  try {
    return new URL(value).toString();
  } catch {
    return value.trim();
  }
}
function resolveBrokerSocketPathForBaseUrl(baseUrl, config = resolveBrokerServiceConfig()) {
  return normalizeBrokerUrl(baseUrl) === normalizeBrokerUrl(config.brokerUrl) ? config.brokerSocketPath : null;
}
function runtimePackageDir() {
  const explicit = process.env.OPENSCOUT_RUNTIME_PACKAGE_DIR?.trim();
  if (explicit)
    return explicit;
  const fromBundledPackage = findBundledRuntimeDir();
  if (fromBundledPackage)
    return fromBundledPackage;
  const fromCwd = findWorkspaceRuntimeDir(process.cwd());
  if (fromCwd)
    return fromCwd;
  const fromGlobal = findGlobalRuntimeDir();
  if (fromGlobal)
    return fromGlobal;
  const moduleDir = dirname2(fileURLToPath(import.meta.url));
  return resolve2(moduleDir, "..");
}
function isInstalledRuntimePackageDir(candidate) {
  return existsSync3(join3(candidate, "package.json")) && existsSync3(join3(candidate, "bin", "openscout-runtime.mjs"));
}
function findGlobalRuntimeDir() {
  const candidates = [
    join3(homedir3(), ".bun", "node_modules", "@openscout", "runtime"),
    join3(homedir3(), ".bun", "install", "global", "node_modules", "@openscout", "runtime"),
    join3(homedir3(), ".bun", "install", "global", "node_modules", "@openscout", "scout", "node_modules", "@openscout", "runtime")
  ];
  for (const c of candidates) {
    if (isInstalledRuntimePackageDir(c))
      return c;
  }
  try {
    const result = spawnSync("which", ["scout"], { encoding: "utf8", timeout: 3000 });
    const scoutBin = result.stdout?.trim();
    if (scoutBin) {
      const scoutPkg = resolve2(scoutBin, "..", "..");
      if (isInstalledRuntimePackageDir(scoutPkg))
        return scoutPkg;
      const nested = join3(scoutPkg, "node_modules", "@openscout", "runtime");
      if (isInstalledRuntimePackageDir(nested))
        return nested;
      const sibling = resolve2(scoutPkg, "..", "runtime");
      if (isInstalledRuntimePackageDir(sibling))
        return sibling;
    }
  } catch {}
  return null;
}
function findBundledRuntimeDir() {
  const moduleDir = dirname2(fileURLToPath(import.meta.url));
  const candidate = resolve2(moduleDir, "..");
  return isInstalledRuntimePackageDir(candidate) ? candidate : null;
}
function findWorkspaceRuntimeDir(startDir) {
  let current = resolve2(startDir);
  while (true) {
    const candidate = join3(current, "packages", "runtime");
    if (existsSync3(join3(candidate, "package.json")) && existsSync3(join3(candidate, "src"))) {
      return candidate;
    }
    const parent = dirname2(current);
    if (parent === current)
      return null;
    current = parent;
  }
}
function resolveBunExecutable2() {
  const bun = resolveBunExecutable(process.env);
  if (bun) {
    return bun.path;
  }
  throw new Error("Unable to locate Bun for broker service management. Install Bun or set OPENSCOUT_BUN_BIN.");
}
function resolveBrokerServiceMode() {
  const explicit = (process.env.OPENSCOUT_BROKER_SERVICE_MODE ?? "").trim().toLowerCase();
  if (explicit === "prod" || explicit === "production") {
    return "prod";
  }
  if (explicit === "custom") {
    return "custom";
  }
  return "dev";
}
function resolveBrokerStartTimeoutMs() {
  const explicit = Number.parseInt(process.env.OPENSCOUT_BROKER_START_TIMEOUT_MS ?? "", 10);
  if (Number.isFinite(explicit) && explicit > 0) {
    return Math.max(explicit, BROKER_SERVICE_POLL_INTERVAL_MS);
  }
  return DEFAULT_BROKER_START_TIMEOUT_MS;
}
function resolveBrokerStopTimeoutMs() {
  const explicit = Number.parseInt(process.env.OPENSCOUT_BROKER_STOP_TIMEOUT_MS ?? "", 10);
  if (Number.isFinite(explicit) && explicit > 0) {
    return Math.max(explicit, BROKER_SERVICE_POLL_INTERVAL_MS);
  }
  return DEFAULT_BROKER_STOP_TIMEOUT_MS;
}
function resolveBrokerServiceLabel(mode) {
  const explicit = process.env.OPENSCOUT_SERVICE_LABEL?.trim() || process.env.OPENSCOUT_BROKER_SERVICE_LABEL?.trim();
  if (explicit) {
    return explicit;
  }
  switch (mode) {
    case "prod":
      return "com.openscout";
    case "custom":
      return "com.openscout.custom";
    case "dev":
    default:
      return "dev.openscout";
  }
}
function legacyBrokerServiceLabel(mode) {
  switch (mode) {
    case "prod":
      return "com.openscout.broker";
    case "custom":
      return "com.openscout.broker.custom";
    case "dev":
    default:
      return "dev.openscout.broker";
  }
}
function resolveBrokerServiceConfig() {
  const mode = resolveBrokerServiceMode();
  const label = resolveBrokerServiceLabel(mode);
  const uid = typeof process.getuid === "function" ? process.getuid() : Number.parseInt(process.env.UID ?? "0", 10);
  const supportPaths = resolveOpenScoutSupportPaths();
  const defaultSupportDir = join3(homedir3(), "Library", "Application Support", "OpenScout");
  const supportDirectory = isTmpPath(supportPaths.supportDirectory) ? defaultSupportDir : supportPaths.supportDirectory;
  const runtimeDirectory = join3(supportDirectory, "runtime");
  const logsDirectory = join3(supportDirectory, "logs", "broker");
  const controlHome = isTmpPath(supportPaths.controlHome) ? join3(homedir3(), ".openscout", "control-plane") : supportPaths.controlHome;
  const advertiseScope = resolveAdvertiseScope();
  const brokerHost = resolveBrokerHost(advertiseScope);
  const brokerPort = Number.parseInt(process.env.OPENSCOUT_BROKER_PORT ?? String(DEFAULT_BROKER_PORT), 10);
  const brokerUrl = process.env.OPENSCOUT_BROKER_URL ?? buildDefaultBrokerUrl(brokerHost, brokerPort);
  const brokerSocketPath = process.env.OPENSCOUT_BROKER_SOCKET_PATH ?? buildDefaultBrokerSocketPath(runtimeDirectory);
  const launchAgentPath = join3(homedir3(), "Library", "LaunchAgents", `${label}.plist`);
  return {
    label,
    mode,
    uid,
    domainTarget: `gui/${uid}`,
    serviceTarget: `gui/${uid}/${label}`,
    launchAgentPath,
    supportDirectory,
    runtimeDirectory,
    logsDirectory,
    stdoutLogPath: join3(logsDirectory, "stdout.log"),
    stderrLogPath: join3(logsDirectory, "stderr.log"),
    controlHome,
    runtimePackageDir: runtimePackageDir(),
    bunExecutable: resolveBunExecutable2(),
    brokerHost,
    brokerPort,
    brokerUrl,
    brokerSocketPath,
    advertiseScope,
    coreAgents: readCoreAgentsSync()
  };
}
function renderLaunchAgentPlist(config) {
  const launchPath = resolveLaunchAgentPATH();
  const coreAgentsValue = (config.coreAgents ?? []).join(",");
  const envEntries = {
    OPENSCOUT_BROKER_HOST: config.brokerHost,
    OPENSCOUT_BROKER_PORT: String(config.brokerPort),
    OPENSCOUT_BROKER_URL: config.brokerUrl,
    OPENSCOUT_BROKER_SOCKET_PATH: config.brokerSocketPath,
    OPENSCOUT_CONTROL_HOME: config.controlHome,
    OPENSCOUT_BROKER_SERVICE_MODE: config.mode,
    OPENSCOUT_BROKER_SERVICE_LABEL: config.label,
    OPENSCOUT_SERVICE_LABEL: config.label,
    OPENSCOUT_ADVERTISE_SCOPE: config.advertiseScope,
    HOME: homedir3(),
    PATH: launchPath,
    ...collectOptionalEnvVars([
      "OPENSCOUT_MESH_ID",
      "OPENSCOUT_MESH_SEEDS",
      "OPENSCOUT_MESH_DISCOVERY_INTERVAL_MS",
      "OPENSCOUT_NODE_NAME",
      "OPENSCOUT_NODE_ID",
      "OPENSCOUT_NODE_QUALIFIER",
      "OPENSCOUT_TAILSCALE_BIN",
      "OPENSCOUT_TAILSCALE_STATUS_JSON",
      "OPENSCOUT_SSE_KEEPALIVE_MS",
      "OPENSCOUT_WEB_EDGE_SCHEME",
      "OPENSCOUT_WEB_PUBLIC_ORIGIN",
      "OPENSCOUT_WEB_PORTAL_HOST",
      "OPENSCOUT_WEB_LOCAL_NAME",
      "OPENSCOUT_WEB_ADVERTISED_HOST",
      "OPENSCOUT_WEB_TRUSTED_HOSTS",
      "OPENSCOUT_WEB_TRUSTED_ORIGINS",
      "OPENSCOUT_WEB_PORT",
      "OPENSCOUT_WEB_FLAG_BUNDLE",
      "OPENSCOUT_WEB_EXPERIENCE",
      "OPENSCOUT_WEB_AB_VARIANT"
    ])
  };
  if (coreAgentsValue) {
    envEntries["OPENSCOUT_CORE_AGENTS"] = coreAgentsValue;
  }
  const envBlock = Object.entries(envEntries).map(([key, value]) => `
    <key>${xmlEscape(key)}</key>
    <string>${xmlEscape(value)}</string>`).join("");
  return `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>${xmlEscape(config.label)}</string>
  <key>ProgramArguments</key>
  <array>
    <string>${xmlEscape(config.bunExecutable)}</string>
    <string>${xmlEscape(join3(config.runtimePackageDir, "bin", "openscout-runtime.mjs"))}</string>
    <string>base</string>
  </array>
  <key>WorkingDirectory</key>
  <string>${xmlEscape(config.runtimePackageDir)}</string>
  <key>RunAtLoad</key>
  <true/>
  <key>KeepAlive</key>
  <dict>
    <key>SuccessfulExit</key>
    <false/>
  </dict>
  <key>StandardOutPath</key>
  <string>${xmlEscape(config.stdoutLogPath)}</string>
  <key>StandardErrorPath</key>
  <string>${xmlEscape(config.stderrLogPath)}</string>
  <key>EnvironmentVariables</key>
  <dict>${envBlock}
  </dict>
</dict>
</plist>
`;
}
function readCoreAgentsSync() {
  try {
    const settingsPath = resolveOpenScoutSupportPaths().settingsPath;
    const raw = readFileSync(settingsPath, "utf8");
    const settings = JSON.parse(raw);
    const raw_agents = settings?.agents?.coreAgents;
    if (Array.isArray(raw_agents)) {
      return raw_agents.filter((v) => typeof v === "string" && v.trim().length > 0);
    }
  } catch {}
  return [];
}
function collectOptionalEnvVars(keys) {
  const entries = {};
  for (const key of keys) {
    const value = process.env[key];
    if (typeof value === "string" && value.trim().length > 0) {
      entries[key] = value;
    }
  }
  return entries;
}
function resolveLaunchAgentPATH() {
  const entries = [
    join3(homedir3(), ".bun", "bin"),
    ...(process.env.PATH ?? "").split(":").filter(Boolean),
    "/opt/homebrew/bin",
    "/usr/local/bin",
    "/usr/bin",
    "/bin",
    "/usr/sbin",
    "/sbin"
  ];
  return Array.from(new Set(entries)).filter((e) => !isTmpPath(e)).join(":");
}
function xmlEscape(value) {
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
}
function ensureParentDirectory(filePath) {
  mkdirSync2(dirname2(filePath), { recursive: true });
}
function ensureServiceDirectories(config) {
  ensureOpenScoutCleanSlateSync();
  mkdirSync2(config.supportDirectory, { recursive: true });
  mkdirSync2(config.runtimeDirectory, { recursive: true, mode: 448 });
  chmodSync(config.runtimeDirectory, 448);
  mkdirSync2(config.logsDirectory, { recursive: true });
  mkdirSync2(config.controlHome, { recursive: true });
  ensureParentDirectory(config.launchAgentPath);
}
function writeLaunchAgentPlist(config) {
  ensureServiceDirectories(config);
  writeFileSync2(config.launchAgentPath, renderLaunchAgentPlist(config), "utf8");
}
function bootoutCommand(config) {
  return `${launchctlPath()} bootout ${config.serviceTarget}`;
}
function legacyLaunchAgentPath(config) {
  return join3(homedir3(), "Library", "LaunchAgents", `${legacyBrokerServiceLabel(config.mode)}.plist`);
}
function legacyServiceTarget(config) {
  return `${config.domainTarget}/${legacyBrokerServiceLabel(config.mode)}`;
}
function bootoutLegacyBrokerService(config) {
  const legacyTarget = legacyServiceTarget(config);
  if (legacyTarget === config.serviceTarget) {
    return;
  }
  runCommand(launchctlPath(), ["bootout", legacyTarget], { allowFailure: true });
}
function runCommand(command, args, options) {
  const result = spawnSync(command, args, {
    env: {
      ...process.env,
      ...options?.env ?? {}
    },
    encoding: "utf8"
  });
  const stdout = (result.stdout ?? "").trim();
  const stderr = (result.stderr ?? "").trim();
  const exitCode = result.status ?? 1;
  if (exitCode !== 0 && !options?.allowFailure) {
    throw new Error(stderr || stdout || `${command} exited with status ${exitCode}`);
  }
  return { exitCode, stdout, stderr };
}
function launchctlPath() {
  return "/bin/launchctl";
}
function readLogLines(path) {
  if (!existsSync3(path)) {
    return [];
  }
  return readFileSync(path, "utf8").split(`
`).map((line) => line.trim()).filter(Boolean);
}
function isPackageScriptBanner(line) {
  return /^\$\s*(bun run|npm run|pnpm\b|yarn\b)/.test(line);
}
function selectLastRelevantLogLine(lines) {
  for (let index = lines.length - 1;index >= 0; index -= 1) {
    const line = lines[index];
    if (!isPackageScriptBanner(line)) {
      return line;
    }
  }
  return lines.at(-1) ?? null;
}
function readLastLogLine(paths) {
  let fallback = null;
  for (const path of paths) {
    const lines = readLogLines(path);
    if (lines.length === 0) {
      continue;
    }
    const relevantLine = selectLastRelevantLogLine(lines);
    if (!relevantLine) {
      continue;
    }
    if (!isPackageScriptBanner(relevantLine)) {
      return relevantLine;
    }
    fallback ??= relevantLine;
  }
  return fallback;
}
function parseLaunchctlPrint(output) {
  const pidMatch = output.match(/\bpid = (\d+)/);
  const stateMatch = output.match(/\bstate = ([^\n]+)/);
  const lastExitMatch = output.match(/\blast exit code = (-?\d+)/i) || output.match(/\blast exit status = (-?\d+)/i);
  return {
    pid: pidMatch ? Number.parseInt(pidMatch[1] ?? "0", 10) : null,
    launchdState: stateMatch?.[1]?.trim() ?? null,
    lastExitStatus: lastExitMatch ? Number.parseInt(lastExitMatch[1] ?? "0", 10) : null
  };
}
function inspectLaunchctl(config) {
  const printResult = runCommand(launchctlPath(), ["print", config.serviceTarget], { allowFailure: true });
  if (printResult.exitCode !== 0) {
    return {
      loaded: false,
      pid: null,
      launchdState: null,
      lastExitStatus: null,
      raw: printResult.stderr || printResult.stdout
    };
  }
  return {
    loaded: true,
    raw: printResult.stdout,
    ...parseLaunchctlPrint(printResult.stdout)
  };
}
async function fetchHealthSnapshot(config) {
  const controller = new AbortController;
  const timeout = setTimeout(() => controller.abort(), 1000);
  const checkedAt = Date.now();
  try {
    const { value: payload, trace } = await requestScoutBrokerJsonWithTrace(config.brokerUrl, "/health", {
      signal: controller.signal,
      socketPath: config.brokerSocketPath
    });
    return {
      reachable: true,
      ok: Boolean(payload.ok),
      checkedAt,
      transport: trace.transport,
      socketPath: trace.socketPath,
      socketFallbackError: trace.socketFallbackError,
      nodeId: payload.nodeId,
      meshId: payload.meshId,
      counts: payload.counts ? {
        nodes: payload.counts.nodes ?? 0,
        actors: payload.counts.actors ?? 0,
        agents: payload.counts.agents ?? 0,
        agentRecords: payload.counts.agentRecords,
        rawAgentRecords: payload.counts.rawAgentRecords,
        configuredAgents: payload.counts.configuredAgents,
        scoutManagedAgents: payload.counts.scoutManagedAgents,
        currentAgentRegistrations: payload.counts.currentAgentRegistrations,
        localAgentRegistrations: payload.counts.localAgentRegistrations,
        remoteAgentRegistrations: payload.counts.remoteAgentRegistrations,
        staleAgentRegistrations: payload.counts.staleAgentRegistrations,
        retiredAgentRegistrations: payload.counts.retiredAgentRegistrations,
        oneTimeAgentCards: payload.counts.oneTimeAgentCards,
        persistentAgentCards: payload.counts.persistentAgentCards,
        conversations: payload.counts.conversations ?? 0,
        messages: payload.counts.messages ?? 0,
        flights: payload.counts.flights ?? 0,
        collaborationRecords: payload.counts.collaborationRecords ?? 0
      } : undefined
    };
  } catch (error) {
    return {
      reachable: false,
      ok: false,
      checkedAt,
      socketPath: config.brokerSocketPath,
      error: error instanceof Error ? error.message : String(error)
    };
  } finally {
    clearTimeout(timeout);
  }
}
async function brokerServiceStatus(config = resolveBrokerServiceConfig()) {
  ensureServiceDirectories(config);
  const launchctl = inspectLaunchctl(config);
  const health = await fetchHealthSnapshot(config);
  const installed = existsSync3(config.launchAgentPath);
  const lastLogLine = health.reachable ? readLastLogLine([config.stdoutLogPath, config.stderrLogPath]) : readLastLogLine([config.stderrLogPath, config.stdoutLogPath]);
  return {
    label: config.label,
    mode: config.mode,
    launchAgentPath: config.launchAgentPath,
    bootoutCommand: bootoutCommand(config),
    brokerUrl: config.brokerUrl,
    brokerSocketPath: config.brokerSocketPath,
    supportDirectory: config.supportDirectory,
    runtimeDirectory: config.runtimeDirectory,
    controlHome: config.controlHome,
    stdoutLogPath: config.stdoutLogPath,
    stderrLogPath: config.stderrLogPath,
    installed,
    loaded: launchctl.loaded,
    pid: launchctl.pid,
    launchdState: launchctl.launchdState,
    lastExitStatus: launchctl.lastExitStatus,
    usesLaunchAgent: installed || launchctl.loaded,
    reachable: health.reachable,
    health,
    lastLogLine
  };
}
async function installBrokerService(config = resolveBrokerServiceConfig()) {
  bootoutLegacyBrokerService(config);
  writeLaunchAgentPlist(config);
  return brokerServiceStatus(config);
}
async function startBrokerService(config = resolveBrokerServiceConfig()) {
  bootoutLegacyBrokerService(config);
  writeLaunchAgentPlist(config);
  runCommand(launchctlPath(), ["bootout", config.serviceTarget], { allowFailure: true });
  await waitForBrokerServiceStopped(config);
  runCommand(launchctlPath(), ["bootstrap", config.domainTarget, config.launchAgentPath], { allowFailure: true });
  runCommand(launchctlPath(), ["kickstart", "-k", config.serviceTarget], { allowFailure: true });
  const attempts = Math.ceil(resolveBrokerStartTimeoutMs() / BROKER_SERVICE_POLL_INTERVAL_MS);
  for (let attempt = 0;attempt < attempts; attempt += 1) {
    const status2 = await brokerServiceStatus(config);
    if (status2.health.reachable) {
      return status2;
    }
    await sleep(BROKER_SERVICE_POLL_INTERVAL_MS);
  }
  const status = await brokerServiceStatus(config);
  throw new Error(status.lastLogLine ?? status.health.error ?? "Broker service did not become healthy.");
}
function sleep(ms) {
  return new Promise((resolve3) => setTimeout(resolve3, ms));
}
async function waitForBrokerServiceStopped(config) {
  let status = await brokerServiceStatus(config);
  const attempts = Math.ceil(resolveBrokerStopTimeoutMs() / BROKER_SERVICE_POLL_INTERVAL_MS);
  for (let attempt = 0;attempt < attempts; attempt += 1) {
    status = await brokerServiceStatus(config);
    if (!status.loaded && !status.health.reachable) {
      return status;
    }
    await sleep(BROKER_SERVICE_POLL_INTERVAL_MS);
  }
  return status;
}
async function stopBrokerService(config = resolveBrokerServiceConfig()) {
  runCommand(launchctlPath(), ["bootout", config.serviceTarget], { allowFailure: true });
  return waitForBrokerServiceStopped(config);
}
async function restartBrokerService(config = resolveBrokerServiceConfig()) {
  await stopBrokerService(config);
  return startBrokerService(config);
}
async function uninstallBrokerService(config = resolveBrokerServiceConfig()) {
  await stopBrokerService(config);
  if (existsSync3(config.launchAgentPath)) {
    rmSync2(config.launchAgentPath, { force: true });
  }
  const legacyPath = legacyLaunchAgentPath(config);
  bootoutLegacyBrokerService(config);
  if (existsSync3(legacyPath)) {
    rmSync2(legacyPath, { force: true });
  }
  return brokerServiceStatus(config);
}
async function main() {
  const command = process.argv[2] ?? "status";
  const json = process.argv.includes("--json");
  const config = resolveBrokerServiceConfig();
  let status;
  switch (command) {
    case "install":
      status = await installBrokerService(config);
      break;
    case "start":
      status = await startBrokerService(config);
      break;
    case "stop":
      status = await stopBrokerService(config);
      break;
    case "restart":
      status = await restartBrokerService(config);
      break;
    case "uninstall":
      status = await uninstallBrokerService(config);
      break;
    case "status":
      status = await brokerServiceStatus(config);
      break;
    default:
      console.error(`Unknown broker service command: ${command}`);
      process.exit(1);
  }
  if (json) {
    console.log(JSON.stringify(status, null, 2));
    return;
  }
  console.log(formatBrokerServiceStatus(status));
}
function formatBrokerServiceStatus(status) {
  const lines = [
    `label: ${status.label}`,
    `mode: ${status.mode}`,
    `launch agent: ${status.installed ? status.launchAgentPath : "not installed"}`,
    `bootout: ${status.bootoutCommand}`,
    `loaded: ${status.loaded ? "yes" : "no"}`,
    `pid: ${status.pid ?? "\u2014"}`,
    `launchd state: ${status.launchdState ?? "\u2014"}`,
    `broker url: ${status.brokerUrl}`,
    `broker socket: ${status.brokerSocketPath}`,
    `reachable: ${status.reachable ? "yes" : "no"}`,
    `health: ${status.health.ok ? "ok" : status.health.error ?? "unreachable"}`,
    `health transport: ${status.health.transport ?? "unknown"}`,
    `logs: ${status.stdoutLogPath}`
  ];
  if (status.health.socketFallbackError) {
    lines.push(`socket fallback: ${status.health.socketFallbackError}`);
  }
  if (status.lastLogLine) {
    lines.push(`last log: ${status.lastLogLine}`);
  }
  return lines.join(`
`);
}
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1] && !process.argv[1].endsWith("/main.mjs")) {
  main().catch((error) => {
    console.error(error instanceof Error ? error.message : String(error));
    process.exit(1);
  });
}
export {
  uninstallBrokerService,
  stopBrokerService,
  startBrokerService,
  selectLastRelevantLogLine,
  restartBrokerService,
  resolveBrokerSocketPathForBaseUrl,
  resolveBrokerServiceConfig,
  resolveBrokerHost,
  resolveAdvertiseScope,
  renderLaunchAgentPlist,
  parseLaunchctlPrint,
  isLoopbackHost,
  installBrokerService,
  buildDefaultBrokerUrl,
  buildDefaultBrokerSocketPath,
  brokerServiceStatus,
  DEFAULT_BROKER_URL,
  DEFAULT_BROKER_PORT,
  DEFAULT_BROKER_HOST_MESH,
  DEFAULT_BROKER_HOST,
  DEFAULT_ADVERTISE_SCOPE
};
