// 重构前 index.ts 只读参考：commit 6a04144d3f5103014f75b637d7e6bc2f45bf007f，blob 56e590c1a6b5ca7ad128bf2c992f60e46c355a58；可用 `git show 6a04144d3f5103014f75b637d7e6bc2f45bf007f:src/components/microservices/code-queue/src/index.ts` 查看。

import { spawnSync } from "node:child_process";
import type { JsonValue } from "./types";
import { collectSkillAvailability, collectSkillSyncPreflight, type SkillAvailabilityReport, type SkillSyncPreflightReport } from "./skill-availability";

export type RuntimePreflightAgentPort = "codex" | "opencode";

export interface RuntimePreflightOptions {
  includeRemote?: boolean;
  includePushDryRun?: boolean;
  pushDryRunRef?: string;
  includePrCreateDryRun?: boolean;
  prCreateDryRunHead?: string;
  issueNumber?: number;
}

export interface RuntimeCommandProbe {
  command: string;
  args: string[];
  ok: boolean;
  exitCode: number | null;
  signal: string | null;
  error: string | null;
  stdout: string;
  stderr: string;
}

export interface RuntimePreflightPortStatus {
  agentPort: RuntimePreflightAgentPort;
  ok: boolean;
  path: string;
  commandPath: string | null;
  version: string | null;
  appServerDryRun?: RuntimeCommandProbe;
  probes: {
    commandV: RuntimeCommandProbe;
    version: RuntimeCommandProbe;
  };
  errors: string[];
  checkedAt: string;
}

export interface RuntimePreflightReport {
  ok: boolean;
  checkedAt: string;
  cwd: string;
  pid: number;
  node: {
    platform: NodeJS.Platform;
    arch: string;
    version: string;
  };
  path: string;
  skills: SkillAvailabilityReport;
  skillsSync: SkillSyncPreflightReport;
  ports: Record<RuntimePreflightAgentPort, RuntimePreflightPortStatus>;
  pullRequestDelivery: PullRequestDeliveryPreflight;
}

export interface UniDeskGhCliStatus {
  ok: boolean;
  path: string;
  present: boolean;
}

export interface PullRequestDeliveryPreflight {
  ok: boolean;
  checkedAt: string;
  tools: Record<string, RuntimeToolStatus>;
  unideskGhCli: UniDeskGhCliStatus;
  authBroker: RuntimeAuthBrokerStatus;
  credentials: {
    ghTokenPresent: boolean;
    githubTokenPresent: boolean;
    ghHostPresent: boolean;
    githubApiUrlPresent: boolean;
    ghRepoPresent: boolean;
    sshAuthSockPresent: boolean;
    gitAskpassPresent: boolean;
    ghHostsConfigPresent: boolean;
    gitCredentialsPresent: boolean;
  };
  githubContext: {
    host: string;
    apiBaseUrl: string;
    repo: string | null;
    issueProbeNumber: number;
  };
  egress: {
    proxy: {
      httpProxy: string | null;
      httpsProxy: string | null;
      allProxy: string | null;
      noProxy: string | null;
      selectedProxyHost: string | null;
      selectedProxyPort: string | null;
      selectedProxyHostProbe: RuntimeCommandProbe | null;
      selectedProxyHostResolvable: boolean | null;
    };
    githubDefault: RuntimeCommandProbe;
    githubDirect: RuntimeCommandProbe;
    apiDefault: RuntimeCommandProbe;
    apiDirect: RuntimeCommandProbe;
    issueApi: RuntimeCommandProbe | null;
  };
  git: {
    insideWorktree: boolean;
    branch: string | null;
    head: string | null;
    originMaster: string | null;
    remoteOrigin: string | null;
    userName: string | null;
    userEmail: string | null;
    home: string | null;
    homeWritable: boolean;
    knownHostsPresent: boolean;
    privateKeyPresent: boolean;
  };
  remote?: {
    gitLsRemote: RuntimeCommandProbe;
    gitHttpsLsRemote: RuntimeCommandProbe | null;
    githubSshAuth: RuntimeCommandProbe;
    githubSshAuthenticated: boolean;
    ghAuthStatus: RuntimeCommandProbe | null;
    ghRepoView: RuntimeCommandProbe | null;
    ghIssueView: RuntimeCommandProbe | null;
    ghPrReadOnly: RuntimeCommandProbe | null;
  };
  pushDryRun?: RuntimeCommandProbe;
  prCreateDryRun?: RuntimeCommandProbe;
  limitations: string[];
  risks: string[];
}

export interface RuntimeAuthBrokerStatus {
  ok: boolean;
  configured: boolean;
  source: "auth-broker" | "broker/auth-broker-needed";
  endpointEnvKey: string | null;
  runnerEnvTokenRequired: boolean;
  credentialSource: string | null;
  failureKind: "auth-missing" | null;
  degradedReason: "auth-broker-needed" | null;
  capability: {
    source: "broker-issued-token" | "missing-token";
    githubRestAuth: boolean;
    operations: string[];
    systemGhBinaryRequiredForWrites: false;
    preflightWritesRemote: false;
    preflightCreatesPr: false;
    preflightMergesPr: false;
    realPrCreateRequiresCommanderAuthorization: true;
    valuesPrinted: false;
  };
  nextAction: "use-auth-broker" | "configure-auth-broker-or-env-token";
  next: string[];
  valuesRead: false;
  valuesPrinted: false;
}

export interface RuntimeToolStatus {
  name: string;
  ok: boolean;
  path: string | null;
  version: string | null;
  probe: RuntimeCommandProbe;
}

const AUTH_BROKER_ENV_KEYS = ["UNIDESK_AUTH_BROKER_URL", "AUTH_BROKER_URL"] as const;
const AUTH_BROKER_OPERATIONS = ["github.auth.status", "github.issue.read", "github.pr.read", "github.pr.create"] as const;

function redactSensitive(value: string): string {
  return value
    .replace(/gh[pousr]_[A-Za-z0-9_]{20,}/gu, "***")
    .replace(/github_pat_[A-Za-z0-9_]+/gu, "***")
    .replace(/(https?:\/\/)([^/\s:@]+):([^/\s@]+)@/giu, "$1***:***@")
    .replace(/(https?:\/\/)([^/\s@]+)@/giu, "$1***@")
    .replace(/([?&](?:access_token|token)=)[^&\s]+/giu, "$1***");
}

function compactOutput(value: string, maxChars = 4000): string {
  const text = redactSensitive(value).replace(/\u001b\[[0-9;]*m/gu, "").trim();
  return text.length <= maxChars ? text : `${text.slice(0, maxChars)}...`;
}

function commandProbe(command: string, args: string[], options: { timeoutMs?: number } = {}): RuntimeCommandProbe {
  const run = spawnSync(command, args, {
    encoding: "utf8",
    timeout: options.timeoutMs ?? 5000,
    maxBuffer: 256 * 1024,
    env: process.env,
    shell: false,
  });
  const error = run.error instanceof Error ? run.error.message : null;
  const timedOut = run.error instanceof Error && run.error.message.includes("ETIMEDOUT");
  return {
    command,
    args,
    ok: error === null && !timedOut && run.status === 0,
    exitCode: run.status,
    signal: run.signal,
    error,
    stdout: compactOutput(typeof run.stdout === "string" ? run.stdout : ""),
    stderr: compactOutput(typeof run.stderr === "string" ? run.stderr : ""),
  };
}

function shellProbe(script: string, timeoutMs = 5000): RuntimeCommandProbe {
  return commandProbe("sh", ["-lc", script], { timeoutMs });
}

function skippedProbe(name: string): RuntimeCommandProbe {
  return {
    command: "preflight",
    args: [name],
    ok: true,
    exitCode: 0,
    signal: null,
    error: null,
    stdout: "skipped; pass remote=1 to run this probe",
    stderr: "",
  };
}

function firstLine(value: string): string | null {
  const line = value.split(/\r?\n/u).map((item) => item.trim()).find((item) => item.length > 0);
  return line ?? null;
}

function errorSummary(probe: RuntimeCommandProbe): string | null {
  if (probe.ok) return null;
  const detail = firstLine([probe.error ?? "", probe.stderr, probe.stdout].filter(Boolean).join("\n"));
  return `${probe.command} ${probe.args.join(" ")} failed${detail === null ? "" : `: ${detail}`}`;
}

function commandPath(command: string): string | null {
  const probe = shellProbe(`command -v ${shellQuote(command)}`, 2000);
  return probe.ok ? firstLine(probe.stdout) : null;
}

function shellQuote(value: string): string {
  return `'${value.replace(/'/gu, "'\\''")}'`;
}

function toolStatus(name: string, versionArgs: string[] = ["--version"]): RuntimeToolStatus {
  const path = commandPath(name);
  const probe = path === null ? shellProbe(`command -v ${shellQuote(name)}`, 2000) : commandProbe(name, versionArgs, { timeoutMs: 5000 });
  return {
    name,
    ok: path !== null,
    path,
    version: path === null ? null : firstLine(probe.stdout) ?? firstLine(probe.stderr),
    probe,
  };
}

function gitValue(args: string[]): string | null {
  const probe = commandProbe("git", args, { timeoutMs: 5000 });
  return probe.ok ? firstLine(probe.stdout) : null;
}

function homeWritable(): boolean {
  const home = process.env.HOME;
  if (home === undefined || home.trim().length === 0) return false;
  return shellProbe(`test -w ${shellQuote(home)}`, 2000).ok;
}

function boolEnv(name: string): boolean {
  const value = process.env[name];
  return value !== undefined && value.trim().length > 0;
}

function authBrokerEndpointEnvKey(): string | null {
  for (const key of AUTH_BROKER_ENV_KEYS) {
    if (boolEnv(key)) return key;
  }
  return null;
}

function authBrokerStatus(): RuntimeAuthBrokerStatus {
  const endpointEnvKey = authBrokerEndpointEnvKey();
  const configured = endpointEnvKey !== null;
  return {
    ok: configured,
    configured,
    source: configured ? "auth-broker" : "broker/auth-broker-needed",
    endpointEnvKey,
    runnerEnvTokenRequired: false,
    credentialSource: configured ? "broker-held-github-credential" : null,
    failureKind: configured ? null : "auth-missing",
    degradedReason: configured ? null : "auth-broker-needed",
    capability: {
      source: configured ? "broker-issued-token" : "missing-token",
      githubRestAuth: configured,
      operations: [...AUTH_BROKER_OPERATIONS],
      systemGhBinaryRequiredForWrites: false,
      preflightWritesRemote: false,
      preflightCreatesPr: false,
      preflightMergesPr: false,
      realPrCreateRequiresCommanderAuthorization: true,
      valuesPrinted: false,
    },
    nextAction: configured ? "use-auth-broker" : "configure-auth-broker-or-env-token",
    next: configured
      ? ["keep PR preflight read-only; create a real PR only after commander authorization"]
      : [
        "configure UNIDESK_AUTH_BROKER_URL or AUTH_BROKER_URL for broker-backed runner auth",
        "or inject GH_TOKEN/GITHUB_TOKEN into the Code Queue scheduler runtime secret until broker mode is live",
      ],
    valuesRead: false,
    valuesPrinted: false,
  };
}

function fileExistsProbe(path: string): boolean {
  return shellProbe(`test -s ${shellQuote(path)}`, 2000).ok;
}

function unideskGhCliStatus(): UniDeskGhCliStatus {
  const root = gitValue(["rev-parse", "--show-toplevel"]) ?? process.cwd();
  const path = `${root.replace(/\/+$/u, "")}/scripts/cli.ts`;
  const present = fileExistsProbe(path);
  return { ok: present, path, present };
}

function parseGitHubRepo(remote: string | null): string | null {
  const envRepo = process.env.GH_REPO?.trim();
  if (envRepo !== undefined && /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(envRepo)) return envRepo;
  if (remote === null) return null;
  const sshMatch = remote.match(/^git@github\.com:([^/]+\/[^/]+?)(?:\.git)?$/u);
  if (sshMatch !== null) return sshMatch[1] ?? null;
  const httpsMatch = remote.match(/^https:\/\/github\.com\/([^/]+\/[^/]+?)(?:\.git)?(?:\/)?$/u);
  if (httpsMatch !== null) return httpsMatch[1] ?? null;
  return null;
}

function envUrl(name: string): URL | null {
  const raw = process.env[name]?.trim();
  if (raw === undefined || raw.length === 0) return null;
  try {
    return new URL(raw);
  } catch {
    return null;
  }
}

function proxySummary(): PullRequestDeliveryPreflight["egress"]["proxy"] {
  const httpProxy = process.env.HTTP_PROXY || process.env.http_proxy || null;
  const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy || null;
  const allProxy = process.env.ALL_PROXY || process.env.all_proxy || null;
  const noProxy = process.env.NO_PROXY || process.env.no_proxy || null;
  const selected = envUrl("HTTPS_PROXY") ?? envUrl("https_proxy") ?? envUrl("HTTP_PROXY") ?? envUrl("http_proxy") ?? envUrl("ALL_PROXY") ?? envUrl("all_proxy");
  const selectedProxyHost = selected?.hostname ?? null;
  const selectedProxyPort = selected === null ? null : selected.port || (selected.protocol === "https:" ? "443" : "80");
  const selectedProxyHostProbe = selectedProxyHost === null ? null : commandProbe("getent", ["ahosts", selectedProxyHost], { timeoutMs: 5000 });
  return {
    httpProxy: httpProxy === null ? null : compactOutput(httpProxy, 1000),
    httpsProxy: httpsProxy === null ? null : compactOutput(httpsProxy, 1000),
    allProxy: allProxy === null ? null : compactOutput(allProxy, 1000),
    noProxy: noProxy === null ? null : compactOutput(noProxy, 1000),
    selectedProxyHost,
    selectedProxyPort,
    selectedProxyHostProbe,
    selectedProxyHostResolvable: selectedProxyHostProbe === null ? null : selectedProxyHostProbe.ok,
  };
}

function authCurlProbe(url: string): RuntimeCommandProbe {
  const script = [
    "set -eu",
    "status_file=/tmp/unidesk-github-api-probe.status",
    "body_file=/tmp/unidesk-github-api-probe.json",
    "rm -f \"$status_file\" \"$body_file\"",
    "if [ -n \"${GH_TOKEN:-}\" ]; then",
    `  curl -sS -o "$body_file" -w 'http_status=%{http_code}\\n' -H "Authorization: Bearer \${GH_TOKEN}" ${shellQuote(url)} > "$status_file"`,
    "elif [ -n \"${GITHUB_TOKEN:-}\" ]; then",
    `  curl -sS -o "$body_file" -w 'http_status=%{http_code}\\n' -H "Authorization: Bearer \${GITHUB_TOKEN}" ${shellQuote(url)} > "$status_file"`,
    "else",
    `  curl -sS -o "$body_file" -w 'http_status=%{http_code}\\n' ${shellQuote(url)} > "$status_file"`,
    "fi",
    "cat \"$status_file\"",
    "status=$(sed -n 's/^http_status=//p' \"$status_file\" | tail -1)",
    "rm -f /tmp/unidesk-github-api-probe.json",
    "rm -f \"$status_file\"",
    "case \"$status\" in 2*) exit 0 ;; *) exit 1 ;; esac",
  ].join("\n");
  return shellProbe(script, 15_000);
}

function issueApiUrl(apiBaseUrl: string, repo: string | null, issueNumber: number): string | null {
  if (repo === null) return null;
  return `${apiBaseUrl.replace(/\/+$/u, "")}/repos/${repo}/issues/${issueNumber}`;
}

function ghRepoArgs(repo: string | null): string[] {
  return repo === null ? ["repo", "view", "--json", "nameWithOwner,visibility,isPrivate"] : ["repo", "view", repo, "--json", "nameWithOwner,visibility,isPrivate"];
}

function httpsGitUrl(repo: string | null, host: string): string | null {
  return repo === null ? null : `https://${host}/${repo}.git`;
}

function prCreateDryRunProbe(repo: string | null, issueNumber: number, head: string | null): RuntimeCommandProbe {
  if (repo === null) {
    return shellProbe("echo 'cannot run PR create dry-run: GitHub repo is unknown' >&2; exit 2", 2000);
  }
  const headRef = head?.trim() || "probe/code-queue-pr-capability";
  const body = [
    "# Code Queue PR preflight",
    "",
    `Related issue: #${issueNumber}`,
    "",
    "Validation:",
    "- runtime PR create dry-run only",
    "",
    "Risk:",
    "- no remote PR is created by this probe",
    "",
  ].join("\n");
  const script = [
    "set -eu",
    "root=$(git rev-parse --show-toplevel 2>/dev/null || pwd)",
    "body_file=$(mktemp /tmp/unidesk-pr-create-dry-run.XXXXXX.md)",
    "trap 'rm -f \"$body_file\"' EXIT",
    `cat > "$body_file" <<'EOF_PR_PREFLIGHT_BODY'`,
    body,
    "EOF_PR_PREFLIGHT_BODY",
    "cd \"$root\"",
    "test -f scripts/cli.ts",
    [
      "bun",
      "scripts/cli.ts",
      "gh",
      "pr",
      "create",
      "--repo",
      shellQuote(repo),
      "--title",
      shellQuote("Code Queue PR preflight dry run"),
      "--body-file",
      "\"$body_file\"",
      "--base",
      "master",
      "--head",
      shellQuote(headRef),
      "--dry-run",
    ].join(" "),
  ].join("\n");
  return shellProbe(script, 20_000);
}

function collectPullRequestDeliveryPreflight(options: RuntimePreflightOptions, checkedAt: string): PullRequestDeliveryPreflight {
  const tools = {
    git: toolStatus("git", ["--version"]),
    gh: toolStatus("gh", ["--version"]),
    hub: toolStatus("hub", ["version"]),
    jq: toolStatus("jq", ["--version"]),
    ssh: toolStatus("ssh", ["-V"]),
    curl: toolStatus("curl", ["--version"]),
  };
  const unideskGhCli = unideskGhCliStatus();
  const insideProbe = commandProbe("git", ["rev-parse", "--is-inside-work-tree"], { timeoutMs: 5000 });
  const insideWorktree = insideProbe.ok && firstLine(insideProbe.stdout) === "true";
  const home = process.env.HOME ?? null;
  const remoteOrigin = gitValue(["remote", "get-url", "origin"]);
  const githubHost = process.env.GH_HOST?.trim() || "github.com";
  const githubApiBaseUrl = (process.env.GITHUB_API_URL?.trim() || "https://api.github.com").replace(/\/+$/u, "");
  const githubRepo = parseGitHubRepo(remoteOrigin);
  const issueProbeNumberRaw = Number(options.issueNumber ?? process.env.CODE_QUEUE_PR_PREFLIGHT_ISSUE_NUMBER ?? 20);
  const issueProbeNumber = Number.isInteger(issueProbeNumberRaw) && issueProbeNumberRaw > 0 ? issueProbeNumberRaw : 20;
  const privateKeyProbe = shellProbe("test -d \"$HOME/.ssh\" && find \"$HOME/.ssh\" -maxdepth 1 -type f \\( -name 'id_*' ! -name '*.pub' -o -name '*.pem' \\) -print -quit", 2000);
  const knownHostsProbe = shellProbe("test -s \"$HOME/.ssh/known_hosts\"", 2000);
  const gitInfo = {
    insideWorktree,
    branch: gitValue(["branch", "--show-current"]),
    head: gitValue(["rev-parse", "--short", "HEAD"]),
    originMaster: gitValue(["rev-parse", "--short", "origin/master"]),
    remoteOrigin: remoteOrigin === null ? null : compactOutput(remoteOrigin, 800),
    userName: gitValue(["config", "--get", "user.name"]),
    userEmail: gitValue(["config", "--get", "user.email"]),
    home,
    homeWritable: homeWritable(),
    knownHostsPresent: knownHostsProbe.ok,
    privateKeyPresent: privateKeyProbe.ok && privateKeyProbe.stdout.trim().length > 0,
  };
  const credentials = {
    ghTokenPresent: boolEnv("GH_TOKEN"),
    githubTokenPresent: boolEnv("GITHUB_TOKEN"),
    ghHostPresent: boolEnv("GH_HOST"),
    githubApiUrlPresent: boolEnv("GITHUB_API_URL"),
    ghRepoPresent: boolEnv("GH_REPO"),
    sshAuthSockPresent: boolEnv("SSH_AUTH_SOCK"),
    gitAskpassPresent: boolEnv("GIT_ASKPASS"),
    ghHostsConfigPresent: fileExistsProbe(`${home ?? "/root"}/.config/gh/hosts.yml`),
    gitCredentialsPresent: fileExistsProbe(`${home ?? "/root"}/.git-credentials`),
  };
  const authBroker = authBrokerStatus();
  const egressProxy = proxySummary();
  const issueUrl = issueApiUrl(githubApiBaseUrl, githubRepo, issueProbeNumber);
  const egress = {
    proxy: egressProxy,
    githubDefault: options.includeRemote === true ? commandProbe("curl", ["-IsS", "--max-time", "10", `https://${githubHost}`], { timeoutMs: 15_000 }) : skippedProbe("github-default-network"),
    githubDirect: options.includeRemote === true ? commandProbe("curl", ["--noproxy", "*", "-IsS", "--max-time", "10", `https://${githubHost}`], { timeoutMs: 15_000 }) : skippedProbe("github-direct-network"),
    apiDefault: options.includeRemote === true ? commandProbe("curl", ["-IsS", "--max-time", "10", githubApiBaseUrl], { timeoutMs: 15_000 }) : skippedProbe("github-api-default-network"),
    apiDirect: options.includeRemote === true ? commandProbe("curl", ["--noproxy", "*", "-IsS", "--max-time", "10", githubApiBaseUrl], { timeoutMs: 15_000 }) : skippedProbe("github-api-direct-network"),
    issueApi: options.includeRemote === true && issueUrl !== null ? authCurlProbe(issueUrl) : null,
  };
  const githubSshAuthProbe = options.includeRemote === true
    ? commandProbe("ssh", ["-o", "BatchMode=yes", "-o", "StrictHostKeyChecking=accept-new", "-T", `git@${githubHost}`], { timeoutMs: 20_000 })
    : null;
  const githubSshAuthenticated = githubSshAuthProbe !== null
    && (githubSshAuthProbe.ok || /successfully authenticated/iu.test(`${githubSshAuthProbe.stdout}\n${githubSshAuthProbe.stderr}`));
  const ghRepoView = options.includeRemote === true && tools.gh.ok
    ? commandProbe("gh", ghRepoArgs(githubRepo), { timeoutMs: 15_000 })
    : null;
  const ghIssueView = options.includeRemote === true && tools.gh.ok && githubRepo !== null
    ? commandProbe("gh", ["issue", "view", String(issueProbeNumber), "--repo", githubRepo, "--json", "number,title,state"], { timeoutMs: 15_000 })
    : null;
  const ghPrReadOnly = options.includeRemote === true && tools.gh.ok && githubRepo !== null
    ? commandProbe("gh", ["pr", "list", "--repo", githubRepo, "--limit", "1", "--json", "number,title,state,headRefName,baseRefName"], { timeoutMs: 15_000 })
    : null;
  const gitHttpsUrl = httpsGitUrl(githubRepo, githubHost);
  const remote = options.includeRemote === true ? {
    gitLsRemote: commandProbe("git", ["ls-remote", "--heads", "origin", "master"], { timeoutMs: 20_000 }),
    gitHttpsLsRemote: gitHttpsUrl === null ? null : commandProbe("git", ["-c", "credential.helper=", "ls-remote", "--heads", gitHttpsUrl, "master"], { timeoutMs: 20_000 }),
    githubSshAuth: githubSshAuthProbe ?? shellProbe("exit 1", 1000),
    githubSshAuthenticated,
    ghAuthStatus: tools.gh.ok ? commandProbe("gh", ["auth", "status", "-h", githubHost], { timeoutMs: 10_000 }) : null,
    ghRepoView,
    ghIssueView,
    ghPrReadOnly,
  } : undefined;
  const pushDryRunRef = options.pushDryRunRef?.trim() || "refs/heads/probe/code-queue-pr-capability-dryrun";
  const pushDryRun = options.includePushDryRun === true
    ? commandProbe("git", ["push", "--dry-run", "origin", `HEAD:${pushDryRunRef}`], { timeoutMs: 30_000 })
    : undefined;
  const prCreateDryRunHead = options.prCreateDryRunHead?.trim() || gitInfo.branch || "probe/code-queue-pr-capability";
  const prCreateDryRun = options.includePrCreateDryRun === true
    ? prCreateDryRunProbe(githubRepo, issueProbeNumber, prCreateDryRunHead)
    : undefined;
  const limitations: string[] = [];
  const risks: string[] = [];
  if (!tools.git.ok) limitations.push("missing git CLI");
  if (!tools.jq.ok) limitations.push("missing jq CLI");
  if (!tools.gh.ok) risks.push("system gh binary is missing; UniDesk REST gh CLI remains the supported PR create/comment path when scripts/cli.ts and GH_TOKEN/GITHUB_TOKEN or auth-broker are available");
  if (!unideskGhCli.ok) limitations.push("UniDesk gh CLI is missing at scripts/cli.ts; runner cannot use the repo-native REST PR create/comment path");
  if (!credentials.ghTokenPresent && !credentials.githubTokenPresent && !authBroker.ok) limitations.push("GH_TOKEN/GITHUB_TOKEN is not present and auth-broker is not configured; PR create requires broker, env token, or another gh credential store");
  if (!credentials.ghHostsConfigPresent && !credentials.gitCredentialsPresent && !credentials.ghTokenPresent && !credentials.githubTokenPresent && !authBroker.ok) limitations.push("no auth-broker, gh hosts config, git credentials file, GH_TOKEN, or GITHUB_TOKEN is visible for GitHub API/issue/PR access");
  if (!gitInfo.insideWorktree) limitations.push("current directory is not a Git worktree");
  if (gitInfo.remoteOrigin === null) limitations.push("git remote origin is not configured");
  if (githubRepo === null) limitations.push("cannot infer GitHub owner/repo from GH_REPO or git remote origin");
  if (!gitInfo.homeWritable) limitations.push("HOME is not writable");
  if (!gitInfo.knownHostsPresent) risks.push("GitHub known_hosts is not pre-seeded; first SSH use may need accept-new behavior");
  if (!gitInfo.privateKeyPresent && !credentials.sshAuthSockPresent && !credentials.ghTokenPresent && !credentials.githubTokenPresent && !authBroker.ok) limitations.push("no SSH key, SSH agent, GitHub token credential, or auth-broker credential is visible");
  if (egress.proxy.selectedProxyHost !== null && egress.proxy.selectedProxyHostResolvable === false) limitations.push(`configured GitHub egress proxy host is not resolvable: ${egress.proxy.selectedProxyHost}`);
  if (options.includeRemote === true && !egress.githubDefault.ok) limitations.push("GitHub HTTPS probe failed with the default environment/proxy");
  if (options.includeRemote === true && !egress.apiDefault.ok) limitations.push("GitHub API probe failed with the default environment/proxy");
  if (options.includeRemote === true && egress.issueApi !== null && !egress.issueApi.ok) {
    if (authBroker.ok) risks.push(`direct GitHub issue API probe for #${issueProbeNumber} failed without runner env token; auth-broker is the intended REST auth source`);
    else limitations.push(`GitHub issue API probe for #${issueProbeNumber} failed; private repo access likely lacks token or egress`);
  }
  if (remote !== undefined) {
    if (!remote.gitLsRemote.ok) limitations.push("git ls-remote origin master failed");
    if (remote.gitHttpsLsRemote !== null && !remote.gitHttpsLsRemote.ok) limitations.push("anonymous HTTPS git ls-remote failed; HTTPS Git access likely needs token credentials");
    if (!remote.githubSshAuthenticated) limitations.push("GitHub SSH auth probe did not authenticate");
    if (remote.ghAuthStatus !== null && !remote.ghAuthStatus.ok) {
      if (authBroker.ok) risks.push("system gh auth status failed; broker-backed UniDesk REST path remains the intended PR preflight auth source");
      else limitations.push("gh auth status failed");
    }
    if (tools.gh.ok && remote.ghRepoView !== null && !remote.ghRepoView.ok) {
      if (authBroker.ok) risks.push("system gh repo view failed; broker-backed UniDesk REST path remains the intended repo read path");
      else limitations.push("gh repo view failed");
    }
    if (tools.gh.ok && remote.ghIssueView !== null && !remote.ghIssueView.ok) {
      if (authBroker.ok) risks.push(`system gh issue read|view #${issueProbeNumber} failed; broker-backed UniDesk REST path remains the intended issue read path`);
      else limitations.push(`gh issue read|view #${issueProbeNumber} failed`);
    }
    if (tools.gh.ok && remote.ghPrReadOnly !== null && !remote.ghPrReadOnly.ok) {
      if (authBroker.ok) risks.push("system gh pr read-only probe failed; broker-backed UniDesk REST path remains the intended PR read path");
      else limitations.push("gh pr read-only probe failed");
    }
  }
  if (pushDryRun !== undefined && !pushDryRun.ok) limitations.push("git push --dry-run failed for probe branch");
  if (prCreateDryRun !== undefined && !prCreateDryRun.ok) limitations.push("PR create dry-run body/command guard failed");
  const prCliReady = unideskGhCli.ok;
  const tokenOrGhStore = authBroker.ok || credentials.ghTokenPresent || credentials.githubTokenPresent || credentials.ghHostsConfigPresent || (remote?.ghAuthStatus?.ok === true);
  const remoteReady = remote === undefined || (egress.githubDefault.ok && egress.apiDefault.ok && remote.gitLsRemote.ok && remote.githubSshAuthenticated);
  const pushReady = pushDryRun === undefined || pushDryRun.ok;
  const prCreateDryRunReady = prCreateDryRun === undefined || prCreateDryRun.ok;
  return {
    ok: tools.git.ok && tools.jq.ok && prCliReady && tokenOrGhStore && gitInfo.insideWorktree && gitInfo.remoteOrigin !== null && gitInfo.homeWritable && remoteReady && pushReady && prCreateDryRunReady,
    checkedAt,
    tools,
    unideskGhCli,
    authBroker,
    credentials,
    githubContext: {
      host: githubHost,
      apiBaseUrl: githubApiBaseUrl,
      repo: githubRepo,
      issueProbeNumber,
    },
    egress,
    git: gitInfo,
    remote,
    pushDryRun,
    prCreateDryRun,
    limitations,
    risks,
  };
}

function codexStatus(path: string, checkedAt: string): RuntimePreflightPortStatus {
  const commandV = shellProbe("command -v codex");
  const version = commandProbe("codex", ["--version"]);
  const appServerDryRun = commandProbe("codex", ["app-server", "--help"]);
  const errors = [commandV, version, appServerDryRun].map(errorSummary).filter((value): value is string => value !== null);
  return {
    agentPort: "codex",
    ok: errors.length === 0,
    path,
    commandPath: firstLine(commandV.stdout),
    version: firstLine(version.stdout) ?? firstLine(version.stderr),
    appServerDryRun,
    probes: { commandV, version },
    errors,
    checkedAt,
  };
}

function opencodeStatus(path: string, checkedAt: string): RuntimePreflightPortStatus {
  const commandV = shellProbe("command -v opencode");
  const version = commandProbe("opencode", ["--version"]);
  const errors = [commandV, version].map(errorSummary).filter((value): value is string => value !== null);
  return {
    agentPort: "opencode",
    ok: errors.length === 0,
    path,
    commandPath: firstLine(commandV.stdout),
    version: firstLine(version.stdout) ?? firstLine(version.stderr),
    probes: { commandV, version },
    errors,
    checkedAt,
  };
}

export function collectRuntimePreflight(options: RuntimePreflightOptions = {}): RuntimePreflightReport {
  const checkedAt = new Date().toISOString();
  const path = process.env.PATH ?? "";
  const skills = collectSkillAvailability({ target: process.env.UNIDESK_SKILLS_PATH || "/root/.agents/skills" });
  const skillsSync = collectSkillSyncPreflight({ target: process.env.UNIDESK_SKILLS_PATH || "/root/.agents/skills" });
  const ports = {
    codex: codexStatus(path, checkedAt),
    opencode: opencodeStatus(path, checkedAt),
  };
  const pullRequestDelivery = collectPullRequestDeliveryPreflight(options, checkedAt);
  return {
    ok: skills.contractOk && ports.codex.ok && ports.opencode.ok && pullRequestDelivery.ok,
    checkedAt,
    cwd: process.cwd(),
    pid: process.pid,
    node: {
      platform: process.platform,
      arch: process.arch,
      version: process.version,
    },
    path,
    skills,
    skillsSync,
    ports,
    pullRequestDelivery,
  };
}

export function runtimePreflightJson(report: RuntimePreflightReport): JsonValue {
  return report as unknown as JsonValue;
}
