import { spawn } from "node:child_process";
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { type UniDeskConfig } from "./config";
import { type DebugDispatchCommand, isDebugDispatchCommand } from "./debug";
import {
  parseMicroserviceProxyRequest,
  rewriteTodoNoteMisleadingRouteNotFound,
  runTodoNoteCheckPath,
  summarizeMicroserviceHealthResponse,
  summarizeMicroserviceObservation,
  summarizeMicroserviceProxyResponse,
} from "./microservices";
import { parseNetworkPerfOptions, runNetworkPerf } from "./network-perf";
import {
  buildWindowsPowerShellInvocation,
  createPosixApplyPatchFileSystem,
  createWindowsApplyPatchFileSystem,
  createSshStderrForwarder,
  createSshStdoutForwarder,
  formatSshFailureHint,
  formatSshRuntimeTimeoutHint,
  formatSshRuntimeTimingHint,
  normalizeSshOperationArgs,
  parseSshInvocation,
  remoteCommandForRoute,
  sshFailureHint,
  sshRouteSeparatorCompatibilityHint,
  sshRoutePayloadCwd,
  sshRuntimeTimeoutHint,
  sshRuntimeTimeoutMs,
  sshRuntimeTimingHint,
  sshWindowsPlaneHint,
  wrapSshRemoteCommand,
  type SshCaptureResult,
} from "./ssh";
import {
  isSshFileTransferOperation,
  runSshFileTransferOperation,
  type SshRemoteCommandExecutor,
  type SshRemoteCommandStreamHandlers,
} from "./ssh-file-transfer";
import { runApplyPatchV2, type ApplyPatchV2Executor } from "./apply-patch-v2";
import { codexJudgeQueryAsync, codexOutputQueryAsync, codexPrPreflightQueryAsync, codexQueuesQueryAsync, codexTaskQueryAsync, codexTasksQueryAsync, codexUnreadTriageAsync } from "./code-queue";
import { runDecisionCenterCommandAsync } from "./decision-center";
import { runTodoNoteCommandAsync } from "./todo-note";
import {
  artifactRegistryReadonlyResultFromCommand,
  buildArtifactRegistryReadonlyProbe,
  parseArtifactRegistryOptions,
} from "./artifact-registry";
import { runCiPublishBackendCoreDryRunPreflight, runCiPublishUserServiceDryRunPreflight } from "./ci";

export interface RemoteCliOptions {
  host: string | null;
  user: string;
  port: number;
  projectRoot: string;
  identityFile: string | null;
  transport: "auto" | "frontend" | "ssh";
  args: string[];
}

export type RemoteFailureClassification = "auth-missing" | "remote-proxy-missing" | "provider-unreachable" | "local-docker-required";

export interface AutoRemoteCiPublishPlan {
  enabled: boolean;
  host: string | null;
  reason: string;
  failureClassification: RemoteFailureClassification | null;
  transport: "frontend";
  command: string | null;
}

interface FrontendSession {
  baseUrl: string;
  cookie: string;
  sshClientToken: string | null;
}

interface FetchJsonResult {
  ok: boolean;
  status?: number;
  body?: unknown;
  error?: string;
  responseHeaders?: Record<string, string>;
  responseTruncated?: boolean;
  responseBytesRead?: number;
  responseContentLength?: string | null;
}

class RemoteCliFailure extends Error {
  readonly failureClassification: RemoteFailureClassification;
  readonly runnerDisposition = "infra-blocked";
  readonly detail: unknown;

  constructor(failureClassification: RemoteFailureClassification, message: string, detail?: unknown) {
    super(message);
    this.name = "RemoteCliFailure";
    this.failureClassification = failureClassification;
    this.detail = detail ?? null;
  }
}

const hostOptions = new Set(["--main-server-ip", "--main-server", "--server"]);
const userOptions = new Set(["--main-server-user", "--server-user"]);
const portOptions = new Set(["--main-server-port", "--server-port"]);
const rootOptions = new Set(["--main-server-root", "--server-root"]);
const keyOptions = new Set(["--main-server-key", "--server-key"]);
const transportOptions = new Set(["--main-server-transport", "--server-transport"]);
const remoteSshInputChunkBytes = 32 * 1024;

function positivePort(raw: string, option: string): number {
  const value = Number(raw);
  if (!Number.isInteger(value) || value <= 0 || value > 65535) throw new Error(`${option} must be a TCP port from 1 to 65535`);
  return value;
}

function requiredValue(argv: string[], index: number, option: string): string {
  const value = argv[index + 1];
  if (value === undefined || value.length === 0) throw new Error(`${option} requires a non-empty value`);
  return value;
}

function transportValue(raw: string, option: string): RemoteCliOptions["transport"] {
  if (raw === "auto" || raw === "frontend" || raw === "ssh") return raw;
  throw new Error(`${option} must be one of: auto, frontend, ssh`);
}

function truthyDisabled(raw: string | undefined): boolean {
  if (raw === undefined) return false;
  const normalized = raw.trim().toLowerCase();
  return normalized === "0" || normalized === "false" || normalized === "off" || normalized === "disabled";
}

function normalizeRemoteHostHint(raw: string | undefined): string | null {
  const value = raw?.trim() ?? "";
  if (value.length === 0) return null;
  if (value === "localhost" || value === "127.0.0.1" || value === "::1") return null;
  return value.replace(/\/+$/u, "");
}

function remoteHttpClientMode(env: NodeJS.ProcessEnv = process.env): "curl" | "fetch" {
  const explicit = env.UNIDESK_REMOTE_HTTP_CLIENT?.trim().toLowerCase();
  if (explicit === "fetch") return "fetch";
  if (explicit === "curl") return "curl";
  return isCodeQueueRunnerEnv(env) ? "curl" : "fetch";
}

function isCodeQueueRunnerEnv(env: NodeJS.ProcessEnv): boolean {
  return Boolean(env.CODE_QUEUE_SERVICE_ROLE || env.CODE_QUEUE_INSTANCE_ID || env.CODE_QUEUE_DEV_CONTAINER_MASTER_HOST || env.KUBERNETES_SERVICE_HOST);
}

export function autoRemoteCiPublishUserServiceDryRunPlan(
  config: UniDeskConfig,
  args: string[],
  env: NodeJS.ProcessEnv = process.env,
): AutoRemoteCiPublishPlan {
  const [top, sub] = args;
  const isPublishDryRun = top === "ci" && (sub === "publish-user-service" || sub === "publish-backend-core") && args.includes("--dry-run");
  if (!isPublishDryRun) {
    return { enabled: false, host: null, reason: "not ci publish-user-service/publish-backend-core --dry-run", failureClassification: null, transport: "frontend", command: null };
  }
  if (truthyDisabled(env.UNIDESK_CI_PUBLISH_AUTO_REMOTE)) {
    return { enabled: false, host: null, reason: "UNIDESK_CI_PUBLISH_AUTO_REMOTE disables automatic remote preflight", failureClassification: "local-docker-required", transport: "frontend", command: null };
  }
  const explicitHost = normalizeRemoteHostHint(env.CODE_QUEUE_DEV_CONTAINER_MASTER_HOST)
    ?? normalizeRemoteHostHint(env.UNIDESK_MAIN_SERVER_IP)
    ?? normalizeRemoteHostHint(env.UNIDESK_MAIN_SERVER_HOST);
  const host = explicitHost ?? (isCodeQueueRunnerEnv(env) ? normalizeRemoteHostHint(config.network.publicHost) : null);
  if (host === null) {
    return { enabled: false, host: null, reason: "no remote main-server frontend host was detected for this runner", failureClassification: "local-docker-required", transport: "frontend", command: null };
  }
  return {
    enabled: true,
    host,
    reason: explicitHost === null
      ? "Code Queue runner environment detected; using config.network.publicHost as the frontend control-plane"
      : "runner remote main-server frontend host detected",
    failureClassification: null,
    transport: "frontend",
    command: ["bun", "scripts/cli.ts", "--main-server-ip", host, ...args].join(" "),
  };
}

export function extractRemoteCliOptions(argv: string[]): RemoteCliOptions {
  const rest: string[] = [];
  const options: RemoteCliOptions = {
    host: null,
    user: "root",
    port: 22,
    projectRoot: "/root/unidesk",
    identityFile: null,
    transport: "auto",
    args: rest,
  };

  for (let index = 0; index < argv.length; index += 1) {
    const arg = argv[index] ?? "";
    if (arg === "--") {
      if (rest.length === 0) {
        rest.push(...argv.slice(index + 1));
        break;
      }
      rest.push(arg);
      continue;
    }
    if (hostOptions.has(arg)) {
      options.host = requiredValue(argv, index, arg);
      index += 1;
      continue;
    }
    if (userOptions.has(arg)) {
      options.user = requiredValue(argv, index, arg);
      index += 1;
      continue;
    }
    if (portOptions.has(arg)) {
      options.port = positivePort(requiredValue(argv, index, arg), arg);
      index += 1;
      continue;
    }
    if (rootOptions.has(arg)) {
      options.projectRoot = requiredValue(argv, index, arg);
      index += 1;
      continue;
    }
    if (keyOptions.has(arg)) {
      options.identityFile = requiredValue(argv, index, arg);
      index += 1;
      continue;
    }
    if (transportOptions.has(arg)) {
      options.transport = transportValue(requiredValue(argv, index, arg), arg);
      index += 1;
      continue;
    }
    rest.push(arg);
  }

  return options;
}

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

async function runRemoteCliOverSsh(options: RemoteCliOptions): Promise<number> {
  if (options.host === null) throw new Error("runRemoteCli requires --main-server-ip or --server");
  const remoteArgs = options.args.length === 0 ? ["help"] : options.args;
  const remoteCommand = [
    "cd",
    shellQuote(options.projectRoot),
    "&&",
    "exec",
    "bun",
    "scripts/cli.ts",
    ...remoteArgs.map(shellQuote),
  ].join(" ");
  const sshArgs = [
    "-p",
    String(options.port),
    "-o",
    "BatchMode=yes",
    "-o",
    "StrictHostKeyChecking=accept-new",
    "-o",
    "ServerAliveInterval=20",
    "-o",
    "ServerAliveCountMax=3",
  ];
  if (options.identityFile !== null) sshArgs.push("-i", options.identityFile);
  sshArgs.push(`${options.user}@${options.host}`, remoteCommand);

  const child = spawn("ssh", sshArgs, {
    stdio: ["inherit", "inherit", "inherit"],
  });

  return await new Promise<number>((resolve) => {
    child.on("error", (error) => {
      process.stderr.write(`unidesk remote cli failed to start ssh: ${error.message}\n`);
      resolve(127);
    });
    child.on("close", (code) => resolve(code ?? 255));
  });
}

function emitRemoteJson(command: string, data: unknown, ok = true): void {
  process.stdout.write(`${JSON.stringify({ ok, command, data }, null, 2)}\n`);
}

function emitRemoteError(command: string, error: unknown): void {
  const payload = error instanceof Error
    ? { name: error.name, message: error.message, stack: error.stack ?? null }
    : { message: String(error) };
  const classification = error instanceof RemoteCliFailure
    ? {
      failureClassification: error.failureClassification,
      runnerDisposition: error.runnerDisposition,
      retryable: error.failureClassification !== "auth-missing",
      detail: error.detail,
      recoveryHints: remoteFailureRecoveryHints(error.failureClassification),
    }
    : null;
  process.stdout.write(`${JSON.stringify({
    ok: false,
    command,
    ...(classification === null ? {} : classification),
    error: payload,
  }, null, 2)}\n`);
}

function remoteFailureRecoveryHints(classification: RemoteFailureClassification): string[] {
  if (classification === "auth-missing") {
    return [
      "verify config.json frontend auth.username/auth.password against the remote main-server frontend login",
      "retry the same command through --main-server-ip after credentials are restored",
    ];
  }
  if (classification === "remote-proxy-missing") {
    return [
      "verify the remote frontend is reachable on the configured public frontend port",
      "verify frontend can proxy /api to backend-core before retrying artifact publish preflight",
    ];
  }
  if (classification === "provider-unreachable") {
    return [
      "verify backend-core /api/dispatch can create D601 host.ssh tasks",
      "verify the D601 provider-gateway host.ssh capability and artifact registry health",
    ];
  }
  return [
    "run this read-only preflight with --main-server-ip <host> from runner environments without local backend-core/database containers",
  ];
}

function commandName(args: string[]): string {
  return args.join(" ") || "help";
}

function frontendBaseUrl(host: string, config: UniDeskConfig): string {
  if (host.startsWith("http://") || host.startsWith("https://")) return host.replace(/\/+$/, "");
  if (/:\d+$/.test(host)) return `http://${host}`;
  return `http://${host}:${config.network.frontend.port}`;
}

async function readJson(url: string, init?: RequestInit, timeoutMs = 8000, maxResponseBytes = 5_000_000): Promise<FetchJsonResult> {
  if (remoteHttpClientMode() === "curl") return readJsonWithCurl(url, init, timeoutMs, maxResponseBytes);
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), timeoutMs);
  try {
    const res = await fetch(url, { ...init, signal: controller.signal });
    const reader = res.body?.getReader();
    const chunks: Uint8Array[] = [];
    let bytes = 0;
    let responseTruncated = false;
    if (reader !== undefined) {
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        if (bytes + value.byteLength > maxResponseBytes) {
          const keep = Math.max(0, maxResponseBytes - bytes);
          if (keep > 0) {
            chunks.push(value.slice(0, keep));
            bytes += keep;
          }
          responseTruncated = true;
          try {
            await reader.cancel();
          } catch {
            // Ignore cancel failures after the bounded preview has been collected.
          }
          break;
        }
        chunks.push(value);
        bytes += value.byteLength;
      }
    }
    const buffer = new Uint8Array(bytes);
    let offset = 0;
    for (const chunk of chunks) {
      buffer.set(chunk, offset);
      offset += chunk.byteLength;
    }
    const text = new TextDecoder().decode(buffer);
    let body: unknown = null;
    try {
      body = text.length > 0 && !responseTruncated ? JSON.parse(text) : null;
    } catch {
      body = { text };
    }
    if (responseTruncated) {
      body = { _unideskResponseTruncated: true, maxResponseBytes, bytesRead: bytes, contentLength: res.headers.get("content-length"), textPreview: text };
    }
    return { ok: res.ok, status: res.status, body, responseHeaders: responseHeadersRecord(res.headers), responseTruncated, responseBytesRead: bytes, responseContentLength: res.headers.get("content-length") };
  } catch (error) {
    return { ok: false, error: error instanceof Error ? error.message : String(error) };
  } finally {
    clearTimeout(timer);
  }
}

function responseHeadersRecord(headers: Headers): Record<string, string> {
  const record: Record<string, string> = {};
  headers.forEach((value, key) => {
    record[key.toLowerCase()] = value;
  });
  return record;
}

function requestHeaders(init?: RequestInit): Array<[string, string]> {
  const headers = new Headers(init?.headers);
  const output: Array<[string, string]> = [];
  headers.forEach((value, key) => output.push([key, value]));
  return output;
}

async function runCurl(args: string[], timeoutMs: number): Promise<{ status: number | null; stdout: string; stderr: string; timedOut: boolean; error?: string }> {
  const child = spawn("curl", args, { stdio: ["ignore", "pipe", "pipe"] });
  const stdoutChunks: Buffer[] = [];
  const stderrChunks: Buffer[] = [];
  let timedOut = false;
  const timer = setTimeout(() => {
    timedOut = true;
    child.kill("SIGTERM");
  }, timeoutMs + 1000);
  child.stdout?.on("data", (chunk) => stdoutChunks.push(Buffer.from(chunk)));
  child.stderr?.on("data", (chunk) => stderrChunks.push(Buffer.from(chunk)));
  return await new Promise((resolve) => {
    child.on("error", (error) => {
      clearTimeout(timer);
      resolve({ status: null, stdout: "", stderr: "", timedOut, error: error.message });
    });
    child.on("close", (status) => {
      clearTimeout(timer);
      resolve({
        status,
        stdout: Buffer.concat(stdoutChunks).toString("utf8"),
        stderr: Buffer.concat(stderrChunks).toString("utf8"),
        timedOut,
      });
    });
  });
}

function parseCurlResponseHeaders(raw: string): Record<string, string> {
  const blocks = raw.split(/\r?\n\r?\n/u).map((block) => block.trim()).filter(Boolean);
  const latest = blocks.at(-1) ?? "";
  const headers: Record<string, string> = {};
  for (const line of latest.split(/\r?\n/u).slice(1)) {
    const splitAt = line.indexOf(":");
    if (splitAt <= 0) continue;
    headers[line.slice(0, splitAt).trim().toLowerCase()] = line.slice(splitAt + 1).trim();
  }
  return headers;
}

function decodeBoundedBody(buffer: Buffer, maxResponseBytes: number): { text: string; truncated: boolean; bytesRead: number } {
  if (buffer.byteLength <= maxResponseBytes) return { text: buffer.toString("utf8"), truncated: false, bytesRead: buffer.byteLength };
  return { text: buffer.subarray(0, maxResponseBytes).toString("utf8"), truncated: true, bytesRead: maxResponseBytes };
}

async function readJsonWithCurl(url: string, init?: RequestInit, timeoutMs = 8000, maxResponseBytes = 5_000_000): Promise<FetchJsonResult> {
  const dir = await mkdtemp(path.join(tmpdir(), "unidesk-remote-http-"));
  const headersFile = path.join(dir, "headers.txt");
  const bodyFile = path.join(dir, "body.bin");
  const requestBodyFile = path.join(dir, "request-body.bin");
  try {
    const method = init?.method ?? (init?.body === undefined ? "GET" : "POST");
    const args = [
      "-sS",
      "--max-time", String(Math.max(1, Math.ceil(timeoutMs / 1000))),
      "-D", headersFile,
      "-o", bodyFile,
      "-w", "%{http_code}",
      "-X", method,
    ];
    for (const [key, value] of requestHeaders(init)) args.push("-H", `${key}: ${value}`);
    if (init?.body !== undefined) {
      await writeFile(requestBodyFile, typeof init.body === "string" ? init.body : String(init.body));
      args.push("--data-binary", `@${requestBodyFile}`);
    }
    args.push(url);
    const curl = await runCurl(args, timeoutMs);
    if (curl.status !== 0) {
      const curlError = curl.error ?? curl.stderr.trim();
      return {
        ok: false,
        status: curl.stdout.trim().match(/^\d{3}$/u) ? Number(curl.stdout.trim()) : undefined,
        error: curl.timedOut ? `curl timed out after ${timeoutMs}ms` : (curlError.length > 0 ? curlError : `curl exited with ${curl.status}`),
      };
    }
    const status = Number(curl.stdout.trim());
    const headersText = await readFile(headersFile, "utf8").catch(() => "");
    const responseHeaders = parseCurlResponseHeaders(headersText);
    const bodyBuffer = await readFile(bodyFile).catch(() => Buffer.alloc(0));
    const decoded = decodeBoundedBody(bodyBuffer, maxResponseBytes);
    let body: unknown = null;
    try {
      body = decoded.text.length > 0 && !decoded.truncated ? JSON.parse(decoded.text) : null;
    } catch {
      body = { text: decoded.text };
    }
    if (decoded.truncated) {
      body = {
        _unideskResponseTruncated: true,
        maxResponseBytes,
        bytesRead: decoded.bytesRead,
        contentLength: responseHeaders["content-length"] ?? null,
        textPreview: decoded.text,
      };
    }
    return {
      ok: status >= 200 && status < 300,
      status,
      body,
      responseHeaders,
      responseTruncated: decoded.truncated,
      responseBytesRead: decoded.bytesRead,
      responseContentLength: responseHeaders["content-length"] ?? null,
    };
  } catch (error) {
    return { ok: false, error: error instanceof Error ? error.message : String(error) };
  } finally {
    await rm(dir, { recursive: true, force: true }).catch(() => undefined);
  }
}

async function loginFrontend(host: string, config: UniDeskConfig): Promise<FrontendSession> {
  const baseUrl = frontendBaseUrl(host, config);
  const res = await readJson(`${baseUrl}/login`, {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({ username: config.auth.username, password: config.auth.password }),
  }, 8_000, 120_000);
  if (!res.ok) {
    const failureClassification: RemoteFailureClassification = res.status === 401 || res.status === 403 ? "auth-missing" : "remote-proxy-missing";
    throw new RemoteCliFailure(failureClassification, `frontend login failed via ${baseUrl}: status=${res.status ?? "unknown"} body=${JSON.stringify(res.body ?? res.error).slice(0, 300)}`, { baseUrl, status: res.status ?? null });
  }
  const cookie = res.responseHeaders?.["set-cookie"]?.split(";")[0] ?? "";
  if (cookie.length === 0) throw new RemoteCliFailure("auth-missing", `frontend login via ${baseUrl} did not return a session cookie`, { baseUrl, status: res.status ?? null });
  return { baseUrl, cookie, sshClientToken: null };
}

function sshClientTokenFromEnv(env: NodeJS.ProcessEnv = process.env): string | null {
  const token = env.UNIDESK_SSH_CLIENT_TOKEN?.trim() ?? "";
  return token.length > 0 ? token : null;
}

function scopedSshFrontendSession(host: string, config: UniDeskConfig, token: string): FrontendSession {
  return { baseUrl: frontendBaseUrl(host, config), cookie: "", sshClientToken: token };
}

export async function runRemoteSshCommandCapture(
  config: UniDeskConfig,
  host: string,
  target: string,
  args: string[],
  input?: string,
  env: NodeJS.ProcessEnv = process.env,
): Promise<SshCaptureResult> {
  const token = sshClientTokenFromEnv(env);
  const session = token === null
    ? await loginFrontend(host, config)
    : scopedSshFrontendSession(host, config, token);
  const normalizedArgs = normalizeSshOperationArgs(args);
  const invocation = parseSshInvocation(target, normalizedArgs);
  const parsed = invocation.parsed;
  if (parsed.remoteCommand === null) throw new Error(`remote ssh ${target} capture requires a non-interactive operation`);
  const stdin = parsed.stdinPrefix !== undefined || parsed.stdinSuffix !== undefined
    ? `${parsed.stdinPrefix ?? ""}${input ?? ""}${parsed.stdinSuffix ?? ""}`
    : input;
  return await runRemoteSshWebSocketCaptureRemoteCommand(session, invocation, parsed.remoteCommand, stdin);
}

async function frontendJson(session: FrontendSession, path: string, init?: RequestInit, timeoutMs = 8000, maxResponseBytes = 5_000_000): Promise<FetchJsonResult> {
  const headers = new Headers(init?.headers);
  headers.set("cookie", session.cookie);
  if (init?.body !== undefined && !headers.has("content-type")) headers.set("content-type", "application/json");
  return readJson(`${session.baseUrl}${path}`, { ...init, headers }, timeoutMs, maxResponseBytes);
}

function stringOption(args: string[], name: string): string | undefined {
  const index = args.indexOf(name);
  if (index === -1) return undefined;
  const raw = args[index + 1];
  if (raw === undefined || raw.length === 0) throw new Error(`${name} requires a non-empty value`);
  return raw;
}

function numberOption(args: string[], name: string, defaultValue: number): number {
  const raw = stringOption(args, name);
  if (raw === undefined) return defaultValue;
  const value = Number(raw);
  if (!Number.isInteger(value) || value <= 0) throw new Error(`${name} must be a positive integer`);
  return value;
}

function cappedNumberOption(args: string[], name: string, defaultValue: number, maxValue: number): number {
  return Math.min(numberOption(args, name, defaultValue), maxValue);
}

function jsonOption(args: string[], name: string): Record<string, unknown> | undefined {
  const raw = stringOption(args, name);
  if (raw === undefined) return undefined;
  const parsed = JSON.parse(raw) as unknown;
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new Error(`${name} must be a JSON object`);
  return parsed as Record<string, unknown>;
}

function dispatchPayload(args: string[], command: DebugDispatchCommand): Record<string, unknown> {
  const explicit = jsonOption(args, "--payload-json") ?? {};
  if (command === "provider.upgrade") {
    return { source: "cli-remote", mode: stringOption(args, "--mode") ?? stringOption(args, "--upgrade-mode") ?? "plan", ...explicit };
  }
  if (command === "host.ssh") {
    const sshCommand = stringOption(args, "--ssh-command");
    return {
      source: "cli-remote",
      mode: sshCommand === undefined ? "probe" : "exec",
      ...(sshCommand === undefined ? {} : { command: sshCommand }),
      ...(stringOption(args, "--cwd") === undefined ? {} : { cwd: stringOption(args, "--cwd") }),
      ...(args.includes("--timeout-ms") ? { timeoutMs: numberOption(args, "--timeout-ms", 8000) } : {}),
      ...explicit,
    };
  }
  return { source: "cli-remote", ...explicit };
}

function summarizeSystemStatus(response: FetchJsonResult): FetchJsonResult {
  const body = response.body as { systemStatuses?: Array<Record<string, unknown>>; ok?: boolean } | null;
  const systemStatuses = (body?.systemStatuses ?? []).map((item) => {
    const current = (item.current ?? {}) as Record<string, unknown>;
    const history = Array.isArray(item.history) ? item.history : [];
    return {
      providerId: item.providerId,
      name: item.name,
      nodeStatus: item.nodeStatus,
      updatedAt: item.updatedAt,
      current: item.current === null || item.current === undefined ? null : {
        ok: current.ok,
        collectedAt: current.collectedAt,
        cpu: current.cpu,
        memory: current.memory,
        disk: current.disk,
      },
      historyPreview: history.slice(-8),
      historyCount: history.length,
    };
  });
  return { ...response, body: { ok: body?.ok === true, systemStatuses } };
}

function summarizeDockerStatus(response: FetchJsonResult): FetchJsonResult {
  const body = response.body as { dockerStatuses?: Array<Record<string, unknown>>; ok?: boolean } | null;
  const dockerStatuses = (body?.dockerStatuses ?? []).map((item) => {
    const status = (item.dockerStatus ?? {}) as Record<string, unknown>;
    const containers = Array.isArray(status.containers) ? status.containers : [];
    return {
      providerId: item.providerId,
      name: item.name,
      nodeStatus: item.nodeStatus,
      updatedAt: item.updatedAt,
      dockerStatus: {
        ok: status.ok,
        socketPresent: status.socketPresent,
        collectedAt: status.collectedAt,
        counts: status.counts,
        daemon: status.daemon,
        containersPreview: containers.slice(0, 8),
      },
    };
  });
  return { ...response, body: { ok: body?.ok === true, dockerStatuses } };
}

async function waitForFrontendTask(session: FrontendSession, taskId: string, timeoutMs: number): Promise<unknown> {
  const started = Date.now();
  let latest: unknown = null;
  while (Date.now() - started < timeoutMs) {
    latest = await frontendJson(session, `/api/tasks/${encodeURIComponent(taskId)}`, undefined, 8000, 5_000_000);
    const body = latest as { body?: { task?: { id?: string; status?: string; result?: unknown } } };
    const task = body.body?.task;
    if (task?.status === "succeeded" || task?.status === "failed") return { ok: true, task };
    await Bun.sleep(500);
  }
  return { ok: false, timeoutMs, latest };
}

async function remoteHealth(session: FrontendSession, config: UniDeskConfig): Promise<unknown> {
  return {
    transport: "frontend",
    frontendPublic: await readJson(`${session.baseUrl}/health`),
    providerIngressPublic: await readJson(`http://${new URL(session.baseUrl).hostname}:${config.network.providerIngress.port}/health`),
    overviewInternal: await frontendJson(session, "/api/overview"),
    nodesInternal: await frontendJson(session, "/api/nodes"),
    systemStatusInternal: summarizeSystemStatus(await frontendJson(session, "/api/nodes/system-status?limit=24")),
    dockerStatusInternal: summarizeDockerStatus(await frontendJson(session, "/api/nodes/docker-status")),
    publicExposureBoundary: {
      coreHostPort: { port: config.network.core.port, expected: "not-exposed" },
      databaseHostPort: { port: config.network.database.port, expected: "restricted-to-code-queue-provider" },
      oaEventFlowHostPort: { port: 4255, expected: "restricted-to-code-queue-provider" },
    },
  };
}

async function remoteDebugDispatch(session: FrontendSession, config: UniDeskConfig, args: string[]): Promise<unknown> {
  const third = args[2];
  const fourth = args[3];
  const providerId = isDebugDispatchCommand(third) ? config.providerGateway.id : third ?? config.providerGateway.id;
  const commandArg = isDebugDispatchCommand(third) ? third : fourth;
  const dispatchCommand = isDebugDispatchCommand(commandArg) ? commandArg : "docker.ps";
  const dispatch = await frontendJson(session, "/api/dispatch", {
    method: "POST",
    body: JSON.stringify({ providerId, command: dispatchCommand, payload: dispatchPayload(args, dispatchCommand) }),
  });
  const taskId = (dispatch as { body?: { taskId?: string } }).body?.taskId ?? "";
  const waitMs = numberOption(args, "--wait-ms", 0);
  const wait = waitMs > 0 && taskId.length > 0 ? await waitForFrontendTask(session, taskId, waitMs) : null;
  return { transport: "frontend", dispatch, wait };
}

async function remoteDebugTask(session: FrontendSession, args: string[]): Promise<unknown> {
  const taskId = args[2] ?? "latest";
  const tasksResponse = await frontendJson(session, "/api/tasks?limit=100");
  const tasks = (tasksResponse as { body?: { tasks?: Array<{ id?: string }> } }).body?.tasks ?? [];
  const task = taskId === "latest" ? tasks[0] : tasks.find((item) => item.id === taskId);
  return { transport: "frontend", tasksResponse, taskId, task: task ?? null };
}

export function summarizeRemoteMicroserviceResponse(action: string, id: string, response: unknown, args: string[]): unknown {
  const optionArgs = args.slice(3);
  if (action === "health") return summarizeMicroserviceHealthResponse(response, optionArgs, id);
  if (action === "status" || action === "diagnostics") return summarizeMicroserviceObservation(action, id, response, optionArgs);
  return response;
}

async function remoteMicroservice(session: FrontendSession, args: string[]): Promise<unknown> {
  const action = args[1] ?? "list";
  const id = args[2];
  const path = args[3];
  if (action === "list") {
    return { transport: "frontend", response: await frontendJson(session, "/api/microservices", undefined, 12_000) };
  }
  if ((action === "status" || action === "health" || action === "diagnostics" || action === "tunnel-self-test") && id !== undefined) {
    const response = await frontendJson(session, `/api/microservices/${encodeURIComponent(id)}/${action}`, undefined, 18_000);
    return {
      transport: "frontend",
      response: summarizeRemoteMicroserviceResponse(action, id, response, args),
    };
  }
  if (action === "proxy" && id !== undefined && path !== undefined && path.startsWith("/")) {
    const request = parseMicroserviceProxyRequest(args);
    if (request.checkPath) {
      if (id !== "todo-note") throw new Error(`--check-path currently only supports service=todo-note; got ${id}`);
      return { transport: "frontend", response: runTodoNoteCheckPath(request.method, path) };
    }
    const full = args.includes("--full");
    const raw = args.includes("--raw");
    const maxBodyBytes = full ? numberOption(args, "--max-body-bytes", 5_000_000) : cappedNumberOption(args, "--max-body-bytes", raw ? 120_000 : 60_000, 500_000);
    const maxResponseBytes = full ? Math.min(Math.max(maxBodyBytes, 120_000), 5_000_000) : Math.min(Math.max(maxBodyBytes * 3, 240_000), 1_500_000);
    const response = await frontendJson(session, `/api/microservices/${encodeURIComponent(id)}/proxy${path}`, {
      method: request.method,
      body: request.body === undefined ? undefined : JSON.stringify(request.body),
    }, 30_000, maxResponseBytes);
    const rewritten = rewriteTodoNoteMisleadingRouteNotFound(id, request.method, path, response);
    return {
      transport: "frontend",
      response: summarizeMicroserviceProxyResponse(rewritten, args),
    };
  }
  throw new Error("remote microservice command must be: microservice list | status <id> | health <id> | diagnostics <id> | tunnel-self-test <id> | proxy <id> <path>");
}

function remoteMicroserviceOk(result: unknown): boolean {
  if (typeof result !== "object" || result === null || Array.isArray(result)) return true;
  const response = (result as { response?: unknown }).response;
  if (typeof response !== "object" || response === null || Array.isArray(response)) return true;
  return (response as { ok?: unknown }).ok !== false;
}

function commandResultFromFrontendTask(command: string[], task: { status?: string; result?: Record<string, unknown> } | undefined) {
  const result = task?.result ?? {};
  const stdout = typeof result.stdout === "string" ? result.stdout : "";
  const stderr = typeof result.stderr === "string" ? result.stderr : "";
  return {
    command,
    cwd: ".",
    exitCode: typeof result.exitCode === "number" ? result.exitCode : null,
    stdout,
    stderr,
    signal: null,
    timedOut: result.timedOut === true || (task?.status !== "succeeded" && /timeout|timed out/iu.test(stderr)),
  };
}

async function dispatchHostSshJson(
  session: FrontendSession,
  providerId: string,
  command: string,
  timeoutMs: number,
  waitMs = Math.max(timeoutMs + 5000, 20_000),
): Promise<{ dispatch: FetchJsonResult; wait: unknown; task?: { status?: string; result?: Record<string, unknown> }; taskId: string | null }> {
  const dispatch = await frontendJson(session, "/api/dispatch", {
    method: "POST",
    body: JSON.stringify({
      providerId,
      command: "host.ssh",
      payload: { source: "cli-remote-artifact-registry", mode: "exec", command, timeoutMs },
    }),
  });
  const taskId = (dispatch as { body?: { taskId?: string } }).body?.taskId ?? "";
  const wait = taskId.length > 0 ? await waitForFrontendTask(session, taskId, waitMs) : null;
  const task = (wait as { task?: { status?: string; result?: Record<string, unknown> } } | null)?.task;
  return { dispatch, wait, task, taskId: taskId.length > 0 ? taskId : null };
}

async function remoteArtifactRegistry(session: FrontendSession, args: string[]): Promise<unknown> {
  const action = args[1] ?? "status";
  if (action !== "status" && action !== "health") {
    throw new Error("remote frontend transport supports artifact-registry status|health only; use main-server SSH for mutating install/deploy commands");
  }
  const options = parseArtifactRegistryOptions(args.slice(2));
  const probe = buildArtifactRegistryReadonlyProbe(action, options);
  const dispatched = await dispatchHostSshJson(session, probe.providerId, probe.script, probe.timeoutMs);
  const command = ["frontend", "/api/dispatch", probe.providerId, "host.ssh", action];
  const result = commandResultFromFrontendTask(command, dispatched.task);
  const registryResult = artifactRegistryReadonlyResultFromCommand(probe, result);
  const dispatchBody = dispatched.dispatch.body as Record<string, unknown> | null | undefined;
  const dispatchError = typeof dispatchBody?.error === "string" ? dispatchBody.error : null;
  return {
    transport: "frontend",
    readonly: true,
    dispatch: dispatched.dispatch,
    wait: dispatched.wait,
    result: dispatched.taskId === null
      ? {
        ok: false,
        readonly: true,
        installed: false,
        healthy: false,
        decision: "infra-blocked",
        retryable: true,
        runnerDisposition: "infra-blocked",
        failureClassification: "control-plane-missing",
        recommendedAction: "restore the remote frontend/backend-core dispatch control plane, then rerun artifact-registry status|health",
        healthyScopes: [],
        failedScopes: ["control-plane-missing", "backend-core-api"],
        runtimeApiHealthy: false,
        channels: [
          { channel: "backend-core-api", ok: false, requiredFor: "frontend /api/dispatch backend-core session creation", detail: dispatched.dispatch },
          { channel: "provider-dispatch", ok: false, requiredFor: "host.ssh task creation", detail: dispatched.dispatch },
        ],
        controlPlane: {
          transport: "remote-frontend",
          failureClassification: "control-plane-missing",
          dispatchStatus: dispatched.dispatch.status ?? null,
          dispatchError,
        },
        registry: registryResult,
      }
      : registryResult,
  };
}

async function remoteCi(session: FrontendSession, config: UniDeskConfig, args: string[]): Promise<unknown> {
  const action = args[1] ?? "status";
  if ((action !== "publish-user-service" && action !== "publish-backend-core") || !args.includes("--dry-run")) {
    throw new Error("remote frontend transport supports only ci publish-user-service --dry-run and ci publish-backend-core --dry-run preflight; real CI publication must run from the controlled main-server CLI after preflight is ready");
  }
  const transport = {
    kind: "remote-frontend" as const,
    remoteHost: session.baseUrl,
    coreFetch: (path: string, init?: { method?: string; body?: unknown; maxResponseBytes?: number }) => frontendJson(session, path, init === undefined ? undefined : {
      method: init.method,
      body: init.body === undefined ? undefined : JSON.stringify(init.body),
    }, 12_000, init?.maxResponseBytes ?? 500_000),
    dispatchHostSsh: async (command: string, waitMs: number, remoteTimeoutMs: number) => {
      const dispatched = await dispatchHostSshJson(session, "D601", command, remoteTimeoutMs, waitMs);
      const task = dispatched.task;
      const result = task?.result ?? {};
      return {
        ok: task?.status === "succeeded" && (typeof result.exitCode !== "number" || result.exitCode === 0) && dispatched.taskId !== null,
        taskId: dispatched.taskId,
        status: task?.status ?? null,
        stdout: typeof result.stdout === "string" ? result.stdout : "",
        stderr: typeof result.stderr === "string" ? result.stderr : "",
        exitCode: typeof result.exitCode === "number" ? result.exitCode : null,
        raw: task ?? dispatched.wait ?? dispatched.dispatch,
      };
    },
    commandCwd: ".",
    artifactRegistryCommand: (probe: ReturnType<typeof buildArtifactRegistryReadonlyProbe>) => ["frontend", "/api/dispatch", probe.providerId, "host.ssh", probe.action, dispatchedTaskShape(probe.remoteCommandShape)],
  };
  return {
    transport: "frontend",
    readonly: true,
    result: action === "publish-backend-core"
      ? await runCiPublishBackendCoreDryRunPreflight(config, args.slice(1), transport)
      : await runCiPublishUserServiceDryRunPreflight(config, args.slice(1), transport),
  };
}

function dispatchedTaskShape(remoteCommandShape: string): string {
  return remoteCommandShape.length > 0 ? remoteCommandShape : "host.ssh artifact-registry readonly probe";
}

async function remoteCodeQueue(session: FrontendSession, args: string[]): Promise<unknown> {
  const action = args[1] ?? "task";
  if (action !== "task" && action !== "summary" && action !== "show" && action !== "tasks" && action !== "overview" && action !== "unread" && action !== "terminal-unread" && action !== "queues" && action !== "queue-list" && action !== "output" && action !== "judge" && action !== "pr-preflight" && action !== "runtime-preflight") {
    throw new Error("remote codex command must be: codex task <taskId>, codex tasks, codex unread, codex queues, codex output <taskId>, codex judge <taskId> --attempt N, or codex pr-preflight [--remote]");
  }
  const taskId = args[2];
  if ((action === "task" || action === "summary" || action === "show" || action === "output" || action === "judge") && (taskId === undefined || taskId.length === 0)) {
    throw new Error(`codex ${action} requires task id`);
  }
  const requiredTaskId = taskId ?? "";
  const fetcher = (path: string, init?: { method?: string; body?: unknown }): Promise<FetchJsonResult> => {
    const requestInit = init === undefined
      ? undefined
      : {
        method: init.method,
        body: init.body === undefined ? undefined : JSON.stringify(init.body),
      };
    return frontendJson(session, path, requestInit, action === "judge" ? 130_000 : 24_000);
  };
  return {
    transport: "frontend",
    result: action === "tasks" || action === "overview"
      ? await codexTasksQueryAsync(args.slice(1), fetcher)
      : action === "unread" || action === "terminal-unread"
        ? await codexUnreadTriageAsync(args.slice(2), fetcher)
      : action === "queues" || action === "queue-list"
        ? await codexQueuesQueryAsync(args.slice(2), fetcher)
        : action === "output"
        ? await codexOutputQueryAsync(requiredTaskId, args.slice(3), fetcher)
        : action === "pr-preflight" || action === "runtime-preflight"
          ? await codexPrPreflightQueryAsync(args.slice(1), fetcher)
        : action === "judge"
          ? await codexJudgeQueryAsync(requiredTaskId, args.slice(3), fetcher)
          : await codexTaskQueryAsync(requiredTaskId, args.slice(3), fetcher),
  };
}

async function remoteNetworkPerf(options: RemoteCliOptions, config: UniDeskConfig, args: string[]): Promise<unknown> {
  if (options.host === null) throw new Error("network perf requires --main-server-ip when using remote frontend transport");
  return {
    transport: "frontend",
    result: await runNetworkPerf(parseNetworkPerfOptions(config, args.slice(2), options.host)),
  };
}

function frontendSshWebSocketUrl(session: FrontendSession): string {
  const url = new URL("/ws/ssh", session.baseUrl);
  url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
  return url.toString();
}

function webSocketDataText(data: unknown): string {
  if (typeof data === "string") return data;
  if (data instanceof ArrayBuffer) return Buffer.from(data).toString("utf8");
  if (ArrayBuffer.isView(data)) return Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString("utf8");
  return String(data);
}

function openFrontendSshWebSocket(session: FrontendSession): WebSocket {
  const WebSocketWithHeaders = WebSocket as unknown as new (
    url: string,
    options?: { headers?: Record<string, string> },
  ) => WebSocket;
  const headers = session.sshClientToken === null
    ? { cookie: session.cookie }
    : { authorization: `Bearer ${session.sshClientToken}` };
  return new WebSocketWithHeaders(frontendSshWebSocketUrl(session), { headers });
}

async function runRemoteSshWebSocket(
  session: FrontendSession,
  invocation: ReturnType<typeof parseSshInvocation>,
): Promise<number> {
  const parsed = invocation.parsed;
  const startedAtMs = Date.now();
  const size = {
    cols: Number(process.stdout.columns) > 0 ? Number(process.stdout.columns) : 100,
    rows: Number(process.stdout.rows) > 0 ? Number(process.stdout.rows) : 30,
  };
  const openTimeoutMs = Math.max(15000, Number(process.env.UNIDESK_SSH_OPEN_TIMEOUT_MS || 60000));
  const runtimeTimeoutMs = sshRuntimeTimeoutMs();
  const payload = {
    providerId: invocation.providerId,
    command: wrapSshRemoteCommand(parsed.remoteCommand, parsed.requiredHelpers),
    cwd: sshRoutePayloadCwd(invocation.route),
    tty: parsed.remoteCommand === null,
    stdinEotOnEnd: parsed.remoteCommand !== null,
    openTimeoutMs,
    runtimeTimeoutMs,
    cols: size.cols,
    rows: size.rows,
  };
  const ws = openFrontendSshWebSocket(session);
  let exitCode = 255;
  let settled = false;
  let canSend = false;
  let sessionReady = false;
  const pending: string[] = [];
  const pendingSessionMessages: string[] = [];

  const send = (value: unknown): void => {
    const text = JSON.stringify(value);
    if (!canSend || ws.readyState !== WebSocket.OPEN) {
      pending.push(text);
      return;
    }
    ws.send(text);
  };
  const flush = (): void => {
    while (pending.length > 0 && ws.readyState === WebSocket.OPEN) ws.send(pending.shift()!);
  };
  const sendInput = (value: Buffer | string): void => {
    sendWhenSessionReady({ type: "ssh.input", data: Buffer.from(value).toString("base64"), encoding: "base64" });
  };
  const sendInputChunked = (value: string): void => {
    const buffer = Buffer.from(value, "utf8");
    for (let offset = 0; offset < buffer.length; offset += remoteSshInputChunkBytes) {
      sendInput(buffer.subarray(offset, Math.min(buffer.length, offset + remoteSshInputChunkBytes)));
    }
  };
  const sendWhenSessionReady = (value: unknown): void => {
    const text = JSON.stringify(value);
    if (!sessionReady || ws.readyState !== WebSocket.OPEN) {
      pendingSessionMessages.push(text);
      return;
    }
    ws.send(text);
  };
  const flushSessionMessages = (): void => {
    if (!sessionReady || ws.readyState !== WebSocket.OPEN) return;
    while (pendingSessionMessages.length > 0) ws.send(pendingSessionMessages.shift()!);
  };

  return await new Promise<number>((resolve) => {
    const rawMode = parsed.remoteCommand === null && process.stdin.isTTY && typeof process.stdin.setRawMode === "function";
    const stdoutForwarder = parsed.remoteCommand === null ? null : createSshStdoutForwarder({
      invocation,
      transport: "frontend-websocket",
    });
    const stderrForwarder = parsed.remoteCommand === null ? null : createSshStderrForwarder({
      invocation,
      transport: "frontend-websocket",
    });
    let timedOut = false;
    let stderrTail = "";
    const openTimer = setTimeout(() => {
      if (sessionReady || settled) return;
      process.stderr.write("unidesk remote frontend ssh bridge timed out waiting for provider session\n");
      exitCode = 255;
      try {
        ws.close();
      } catch {
        // Ignore close failures while resolving the timeout path.
      }
    }, openTimeoutMs);
    const runtimeTimer = setTimeout(() => {
      if (settled) return;
      timedOut = true;
      exitCode = 124;
      process.stderr.write(formatSshRuntimeTimeoutHint(sshRuntimeTimeoutHint({
        invocation,
        transport: "frontend-websocket",
        timeoutMs: runtimeTimeoutMs,
      })));
      try {
        ws.close();
      } catch {
        // Ignore close failures while resolving the timeout path.
      }
      finish(124);
    }, runtimeTimeoutMs);

    const restore = (): void => {
      clearTimeout(openTimer);
      clearTimeout(runtimeTimer);
      process.stdin.off("data", onStdinData);
      process.stdin.off("end", onStdinEnd);
      if (rawMode) process.stdin.setRawMode(false);
    };
    const finish = (code: number): void => {
      if (settled) return;
      settled = true;
      restore();
      const hint = timedOut ? null : sshFailureHint(invocation.providerId, parsed, code, stderrTail);
      if (hint !== null) process.stderr.write(formatSshFailureHint(hint));
      if (!timedOut) {
        const windowsPlaneHint = sshWindowsPlaneHint(invocation, code, stderrTail);
        if (windowsPlaneHint) process.stderr.write(windowsPlaneHint);
      }
      const timingHint = formatSshRuntimeTimingHint(sshRuntimeTimingHint({
        invocation,
        transport: "frontend-websocket",
        exitCode: code,
        startedAtMs,
      }));
      if (timingHint) process.stderr.write(timingHint);
      resolve(code);
    };
    const onStdinData = (chunk: Buffer): void => {
      sendInput(chunk);
    };
    const onStdinEnd = (): void => {
      if (parsed.stdinSuffix) sendInput(parsed.stdinSuffix);
      if (payload.stdinEotOnEnd === true) sendInput(Buffer.from([4]));
      sendWhenSessionReady({ type: "ssh.eof" });
    };

    ws.addEventListener("open", () => {
      canSend = true;
      send({ type: "ssh.open", ...payload });
      flush();
    });
    ws.addEventListener("message", (event) => {
      const text = webSocketDataText(event.data);
      let message: Record<string, unknown>;
      try {
        message = JSON.parse(text) as Record<string, unknown>;
      } catch {
        process.stderr.write(`${text}\n`);
        return;
      }
      if (message.type === "ssh.dispatched") return;
      if (message.type === "ssh.opened") {
        sessionReady = true;
        clearTimeout(openTimer);
        flushSessionMessages();
        return;
      }
      if (message.type === "ssh.data") {
        const chunk = Buffer.from(String(message.data ?? ""), message.encoding === "base64" ? "base64" : "utf8");
        if (message.stream === "stderr") {
          stderrTail = (stderrTail + chunk.toString("utf8")).slice(-16_384);
          if (stderrForwarder === null) {
            process.stderr.write(chunk);
          } else {
            const hint = stderrForwarder.write(chunk);
            if (hint !== null) process.stderr.write(hint);
          }
        } else if (stdoutForwarder === null) {
          process.stdout.write(chunk);
        } else {
          const hint = stdoutForwarder.write(chunk);
          if (hint !== null) process.stderr.write(hint);
        }
        return;
      }
      if (message.type === "ssh.error") {
        const errorText = `${String(message.message || "ssh bridge error")}\n`;
        stderrTail = (stderrTail + errorText).slice(-16_384);
        process.stderr.write(errorText);
        exitCode = 255;
        ws.close();
        return;
      }
      if (message.type === "ssh.exit") {
        exitCode = Number.isInteger(message.exitCode) ? Number(message.exitCode) : 255;
        ws.close();
      }
    });
    ws.addEventListener("close", () => finish(exitCode));
    ws.addEventListener("error", () => {
      process.stderr.write("unidesk remote frontend ssh bridge websocket error\n");
      finish(255);
    });

    if (rawMode) process.stdin.setRawMode(true);
    process.stdin.resume();
    if (parsed.stdinPrefix) sendInput(parsed.stdinPrefix);
    process.stdin.on("data", onStdinData);
    process.stdin.on("end", onStdinEnd);
  });
}

async function runRemoteSshWebSocketCapture(
  session: FrontendSession,
  invocation: ReturnType<typeof parseSshInvocation>,
  command: string[],
  input?: string,
): Promise<SshCaptureResult> {
  const remoteCommand = remoteCommandForRoute(invocation.route, command, { stdin: input !== undefined });
  return await runRemoteSshWebSocketCaptureRemoteCommand(session, invocation, remoteCommand, input);
}

async function runRemoteSshWebSocketCaptureRemoteCommand(
  session: FrontendSession,
  invocation: ReturnType<typeof parseSshInvocation>,
  remoteCommand: string,
  input?: string,
): Promise<SshCaptureResult> {
  const captureInvocation = {
    ...invocation,
    parsed: { ...invocation.parsed, remoteCommand, requiresStdin: input !== undefined, invocationKind: "helper" as const },
  };
  const startedAtMs = Date.now();
  const size = {
    cols: Number(process.stdout.columns) > 0 ? Number(process.stdout.columns) : 100,
    rows: Number(process.stdout.rows) > 0 ? Number(process.stdout.rows) : 30,
  };
  const runtimeTimeoutMs = sshRuntimeTimeoutMs();
  const payload = {
    providerId: invocation.providerId,
    command: wrapSshRemoteCommand(remoteCommand),
    cwd: sshRoutePayloadCwd(invocation.route),
    tty: false,
    stdinEotOnEnd: false,
    openTimeoutMs: Math.max(15000, Number(process.env.UNIDESK_SSH_OPEN_TIMEOUT_MS || 60000)),
    runtimeTimeoutMs,
    cols: size.cols,
    rows: size.rows,
  };
  const ws = openFrontendSshWebSocket(session);
  let exitCode = 255;
  let settled = false;
  let canSend = false;
  let sessionReady = false;
  let stdout = "";
  let stderr = "";
  const pending: string[] = [];
  const pendingSessionMessages: string[] = [];

  const send = (value: unknown): void => {
    const text = JSON.stringify(value);
    if (!canSend || ws.readyState !== WebSocket.OPEN) {
      pending.push(text);
      return;
    }
    ws.send(text);
  };
  const sendWhenSessionReady = (value: unknown): void => {
    const text = JSON.stringify(value);
    if (!sessionReady || ws.readyState !== WebSocket.OPEN) {
      pendingSessionMessages.push(text);
      return;
    }
    ws.send(text);
  };
  const sendInput = (value: Buffer | string): void => {
    sendWhenSessionReady({ type: "ssh.input", data: Buffer.from(value).toString("base64"), encoding: "base64" });
  };
  const sendInputChunked = (value: string): void => {
    const buffer = Buffer.from(value, "utf8");
    for (let offset = 0; offset < buffer.length; offset += remoteSshInputChunkBytes) {
      sendInput(buffer.subarray(offset, Math.min(buffer.length, offset + remoteSshInputChunkBytes)));
    }
  };
  const flush = (): void => {
    while (pending.length > 0 && ws.readyState === WebSocket.OPEN) ws.send(pending.shift()!);
  };
  const flushSessionMessages = (): void => {
    if (!sessionReady || ws.readyState !== WebSocket.OPEN) return;
    while (pendingSessionMessages.length > 0) ws.send(pendingSessionMessages.shift()!);
  };

  return await new Promise<SshCaptureResult>((resolve) => {
    let killTimer: ReturnType<typeof setTimeout> | null = null;
    const finish = (code: number): void => {
      if (settled) return;
      settled = true;
      clearTimeout(openTimer);
      clearTimeout(runtimeTimer);
      if (killTimer !== null) clearTimeout(killTimer);
      const timingHint = formatSshRuntimeTimingHint(sshRuntimeTimingHint({
        invocation: captureInvocation,
        transport: "frontend-websocket",
        exitCode: code,
        startedAtMs,
      }));
      if (timingHint) stderr += timingHint;
      resolve({ exitCode: code, stdout, stderr });
    };
    const openTimer = setTimeout(() => {
      if (sessionReady || settled) return;
      stderr += "unidesk remote frontend ssh bridge timed out waiting for provider session\n";
      exitCode = 255;
      try {
        ws.close();
      } catch {
        // Ignore.
      }
    }, payload.openTimeoutMs);
    const runtimeTimer = setTimeout(() => {
      if (settled) return;
      exitCode = 124;
      stderr += formatSshRuntimeTimeoutHint(sshRuntimeTimeoutHint({
        invocation: captureInvocation,
        transport: "frontend-websocket",
        timeoutMs: runtimeTimeoutMs,
      }));
      try {
        ws.close();
      } catch {
        // Ignore.
      }
      killTimer = setTimeout(() => finish(124), 2000);
      finish(124);
    }, runtimeTimeoutMs);

    ws.addEventListener("open", () => {
      canSend = true;
      send({ type: "ssh.open", ...payload });
      flush();
    });
    ws.addEventListener("message", (event) => {
      const text = webSocketDataText(event.data);
      let message: Record<string, unknown>;
      try {
        message = JSON.parse(text) as Record<string, unknown>;
      } catch {
        stderr += `${text}\n`;
        return;
      }
      if (message.type === "ssh.dispatched") return;
      if (message.type === "ssh.opened") {
        sessionReady = true;
        clearTimeout(openTimer);
        if (input !== undefined) sendInputChunked(input);
        sendWhenSessionReady({ type: "ssh.eof" });
        flushSessionMessages();
        return;
      }
      if (message.type === "ssh.data") {
        const chunk = Buffer.from(String(message.data ?? ""), message.encoding === "base64" ? "base64" : "utf8").toString("utf8");
        if (message.stream === "stderr") stderr += chunk;
        else stdout += chunk;
        return;
      }
      if (message.type === "ssh.error") {
        stderr += `${String(message.message || "ssh bridge error")}\n`;
        exitCode = 255;
        ws.close();
        return;
      }
      if (message.type === "ssh.exit") {
        exitCode = Number.isInteger(message.exitCode) ? Number(message.exitCode) : 255;
        ws.close();
      }
    });
    ws.addEventListener("close", () => finish(exitCode));
    ws.addEventListener("error", () => {
      stderr += "unidesk remote frontend ssh bridge websocket error\n";
      finish(255);
    });
  });
}

async function runRemoteSshWebSocketStreamRemoteCommand(
  session: FrontendSession,
  invocation: ReturnType<typeof parseSshInvocation>,
  remoteCommand: string,
  handlers: SshRemoteCommandStreamHandlers,
  input?: string,
  options: { inactivityTimeoutMs?: number } = {},
): Promise<SshCaptureResult> {
  const streamInvocation = {
    ...invocation,
    parsed: { ...invocation.parsed, remoteCommand, requiresStdin: input !== undefined, invocationKind: "helper" as const },
  };
  const startedAtMs = Date.now();
  const size = {
    cols: Number(process.stdout.columns) > 0 ? Number(process.stdout.columns) : 100,
    rows: Number(process.stdout.rows) > 0 ? Number(process.stdout.rows) : 30,
  };
  const inactivityTimeoutMs = options.inactivityTimeoutMs ?? sshRuntimeTimeoutMs();
  const runtimeTimeoutMs = options.inactivityTimeoutMs === undefined ? inactivityTimeoutMs : Math.max(inactivityTimeoutMs * 4, 60 * 60_000);
  const payload = {
    providerId: invocation.providerId,
    command: wrapSshRemoteCommand(remoteCommand),
    cwd: sshRoutePayloadCwd(invocation.route),
    tty: false,
    stdinEotOnEnd: false,
    openTimeoutMs: Math.max(15000, Number(process.env.UNIDESK_SSH_OPEN_TIMEOUT_MS || 60000)),
    runtimeTimeoutMs,
    runtimeTimeoutMode: options.inactivityTimeoutMs === undefined ? "wall-clock" : "inactivity",
    cols: size.cols,
    rows: size.rows,
  };
  const ws = openFrontendSshWebSocket(session);
  let exitCode = 255;
  let settled = false;
  let canSend = false;
  let sessionReady = false;
  let stdout = "";
  let stderr = "";
  let streamError: unknown = null;
  let streamWrites = Promise.resolve();
  const pending: string[] = [];
  const pendingSessionMessages: string[] = [];

  const send = (value: unknown): void => {
    const text = JSON.stringify(value);
    if (!canSend || ws.readyState !== WebSocket.OPEN) {
      pending.push(text);
      return;
    }
    ws.send(text);
  };
  const sendWhenSessionReady = (value: unknown): void => {
    const text = JSON.stringify(value);
    if (!sessionReady || ws.readyState !== WebSocket.OPEN) {
      pendingSessionMessages.push(text);
      return;
    }
    ws.send(text);
  };
  const sendInput = (value: Buffer | string): void => {
    sendWhenSessionReady({ type: "ssh.input", data: Buffer.from(value).toString("base64"), encoding: "base64" });
  };
  const sendInputChunked = (value: string): void => {
    const buffer = Buffer.from(value, "utf8");
    for (let offset = 0; offset < buffer.length; offset += remoteSshInputChunkBytes) {
      sendInput(buffer.subarray(offset, Math.min(buffer.length, offset + remoteSshInputChunkBytes)));
    }
  };
  const flush = (): void => {
    while (pending.length > 0 && ws.readyState === WebSocket.OPEN) ws.send(pending.shift()!);
  };
  const flushSessionMessages = (): void => {
    if (!sessionReady || ws.readyState !== WebSocket.OPEN) return;
    while (pendingSessionMessages.length > 0) ws.send(pendingSessionMessages.shift()!);
  };
  const queueStreamWrite = (chunk: Buffer, stream: "stdout" | "stderr"): void => {
    streamWrites = streamWrites.then(async () => {
      if (stream === "stdout") await handlers.onStdout(chunk);
      else if (handlers.onStderr !== undefined) await handlers.onStderr(chunk);
    }).catch((error) => {
      streamError = error;
      stderr += `unidesk remote frontend ssh stream sink failed: ${error instanceof Error ? error.message : String(error)}\n`;
      exitCode = 255;
      try {
        ws.close();
      } catch {
        // Ignore close failures after the local stream sink has failed.
      }
    });
  };

  return await new Promise<SshCaptureResult>((resolve) => {
    let killTimer: ReturnType<typeof setTimeout> | null = null;
    let inactivityTimer: ReturnType<typeof setTimeout> | null = null;
    const refreshActivityTimer = (): void => {
      if (settled || options.inactivityTimeoutMs === undefined) return;
      if (inactivityTimer !== null) clearTimeout(inactivityTimer);
      inactivityTimer = setTimeout(() => {
        exitCode = 124;
        stderr += formatSshRuntimeTimeoutHint(sshRuntimeTimeoutHint({
          invocation: streamInvocation,
          transport: "frontend-websocket",
          timeoutMs: inactivityTimeoutMs,
        }));
        try {
          ws.close();
        } catch {
          // Ignore.
        }
        killTimer = setTimeout(() => finish(124), 2000);
        finish(124);
      }, inactivityTimeoutMs);
    };
    const finish = (code: number): void => {
      if (settled) return;
      settled = true;
      clearTimeout(openTimer);
      clearTimeout(runtimeTimer);
      if (inactivityTimer !== null) clearTimeout(inactivityTimer);
      if (killTimer !== null) clearTimeout(killTimer);
      void streamWrites.then(() => {
        const finalCode = streamError === null ? code : 255;
        const timingHint = formatSshRuntimeTimingHint(sshRuntimeTimingHint({
          invocation: streamInvocation,
          transport: "frontend-websocket",
          exitCode: finalCode,
          startedAtMs,
        }));
        if (timingHint) stderr += timingHint;
        resolve({ exitCode: finalCode, stdout, stderr });
      });
    };
    const openTimer = setTimeout(() => {
      if (sessionReady || settled) return;
      stderr += "unidesk remote frontend ssh bridge timed out waiting for provider session\n";
      exitCode = 255;
      try {
        ws.close();
      } catch {
        // Ignore.
      }
    }, payload.openTimeoutMs);
    const runtimeTimer = setTimeout(() => {
      if (settled) return;
      exitCode = 124;
      stderr += formatSshRuntimeTimeoutHint(sshRuntimeTimeoutHint({
        invocation: streamInvocation,
        transport: "frontend-websocket",
        timeoutMs: runtimeTimeoutMs,
      }));
      try {
        ws.close();
      } catch {
        // Ignore.
      }
      killTimer = setTimeout(() => finish(124), 2000);
      finish(124);
    }, runtimeTimeoutMs);
    refreshActivityTimer();

    ws.addEventListener("open", () => {
      canSend = true;
      send({ type: "ssh.open", ...payload });
      flush();
    });
    ws.addEventListener("message", (event) => {
      const text = webSocketDataText(event.data);
      let message: Record<string, unknown>;
      try {
        message = JSON.parse(text) as Record<string, unknown>;
      } catch {
        stderr += `${text}\n`;
        return;
      }
      if (message.type === "ssh.dispatched") {
        refreshActivityTimer();
        return;
      }
      if (message.type === "ssh.opened") {
        sessionReady = true;
        clearTimeout(openTimer);
        refreshActivityTimer();
        if (input !== undefined) sendInputChunked(input);
        sendWhenSessionReady({ type: "ssh.eof" });
        flushSessionMessages();
        return;
      }
      if (message.type === "ssh.data") {
        refreshActivityTimer();
        const chunk = Buffer.from(String(message.data ?? ""), message.encoding === "base64" ? "base64" : "utf8");
        if (message.stream === "stderr") {
          stderr += chunk.toString("utf8");
          queueStreamWrite(chunk, "stderr");
        } else {
          queueStreamWrite(chunk, "stdout");
        }
        return;
      }
      if (message.type === "ssh.error") {
        stderr += `${String(message.message || "ssh bridge error")}\n`;
        exitCode = 255;
        ws.close();
        return;
      }
      if (message.type === "ssh.exit") {
        exitCode = Number.isInteger(message.exitCode) ? Number(message.exitCode) : 255;
        ws.close();
      }
    });
    ws.addEventListener("close", () => finish(exitCode));
    ws.addEventListener("error", () => {
      stderr += "unidesk remote frontend ssh bridge websocket error\n";
      finish(255);
    });
  });
}

export function remoteSshFrontendPlanForTest(target: string, args: string[]): Record<string, unknown> {
  const invocation = parseSshInvocation(target, args);
  return {
    transport: "frontend-websocket",
    providerId: invocation.providerId,
    route: invocation.route,
    remoteCommand: invocation.parsed.remoteCommand,
    wrappedRemoteCommand: wrapSshRemoteCommand(invocation.parsed.remoteCommand, invocation.parsed.requiredHelpers),
    requiresStdin: invocation.parsed.requiresStdin,
    invocationKind: invocation.parsed.invocationKind,
    payloadCwd: sshRoutePayloadCwd(invocation.route) ?? null,
  };
}

async function runRemoteSshOverFrontend(session: FrontendSession, target: string | undefined, args: string[]): Promise<number> {
  if (!target) throw new Error("remote ssh requires a route, for example: bun scripts/cli.ts --main-server-ip 74.48.78.17 ssh D601 hostname");
  const normalizedArgs = normalizeSshOperationArgs(args);
  process.stderr.write(sshRouteSeparatorCompatibilityHint(args, normalizedArgs));
  const invocation = parseSshInvocation(target, normalizedArgs);
  if (isSshFileTransferOperation(normalizedArgs)) {
    const executor: SshRemoteCommandExecutor = {
      streamInactivityTimeoutMs: sshRuntimeTimeoutMs(),
      runRemoteCommand: (remoteCommand, input) => runRemoteSshWebSocketCaptureRemoteCommand(session, invocation, remoteCommand, input),
      streamRemoteCommand: (remoteCommand, handlers, input, options) => runRemoteSshWebSocketStreamRemoteCommand(session, invocation, remoteCommand, handlers, input, options),
    };
    return await runSshFileTransferOperation(invocation, normalizedArgs, executor, {
      buildRouteCommand: remoteCommandForRoute,
      buildWindowsPowerShellCommand: buildWindowsPowerShellInvocation,
    });
  }
  if ((normalizedArgs[0] ?? "") === "apply-patch") {
    const executor: ApplyPatchV2Executor = invocation.route.plane === "win"
      ? { fs: createWindowsApplyPatchFileSystem(invocation, (remoteCommand, input) => runRemoteSshWebSocketCaptureRemoteCommand(session, invocation, remoteCommand, input)) }
      : invocation.route.plane === "host"
        ? { fs: createPosixApplyPatchFileSystem(invocation, (command, input) => runRemoteSshWebSocketCapture(session, invocation, command, input)) }
        : { run: (command, input) => runRemoteSshWebSocketCapture(session, invocation, command, input) };
    return await runApplyPatchV2({
      executor,
      stdin: process.stdin,
      stdout: process.stdout,
      stderr: process.stderr,
      argv: normalizedArgs.slice(1),
      timing: {
        providerId: invocation.providerId,
        route: invocation.route.raw,
        transport: "frontend-websocket",
      },
    });
  }
  return runRemoteSshWebSocket(session, invocation);
}

async function runRemoteCliOverFrontend(options: RemoteCliOptions, config: UniDeskConfig): Promise<number> {
  if (options.host === null) throw new Error("runRemoteCli requires --main-server-ip or --server");
  const args = options.args.length === 0 ? ["help"] : options.args;
  const name = commandName(args);
  try {
    const [top, sub] = args;
    const scopedSshToken = top === "ssh" ? sshClientTokenFromEnv() : null;
    const session = scopedSshToken === null ? await loginFrontend(options.host, config) : scopedSshFrontendSession(options.host, config, scopedSshToken);
    if (top === "help" || top === "--help" || top === "-h") {
      emitRemoteJson(name, {
        transport: "frontend",
        baseUrl: session.baseUrl,
        commands: ["debug health", "debug dispatch", "debug task", "ssh <providerId> <command>", "ssh <providerId> skills", "artifact-registry status|health", "ci publish-user-service --dry-run", "ci publish-backend-core --dry-run", "microservice list", "microservice status <id>", "microservice health <id>", "microservice diagnostics <id>", "microservice tunnel-self-test <id>", "microservice proxy <id> <path>", "todo-note list|show|add|update|complete|reopen|remind|delete|undo|redo", "decision upload <markdown-file>", "decision list", "decision show <id>", "codex task <taskId>", "codex tasks", "codex unread", "codex queues", "codex judge <taskId> --attempt N", "codex pr-preflight [--remote]", "network perf"],
      });
      return 0;
    }
    if (top === "debug" && sub === "health") {
      emitRemoteJson(name, await remoteHealth(session, config));
      return 0;
    }
    if (top === "debug" && sub === "dispatch") {
      emitRemoteJson(name, await remoteDebugDispatch(session, config, args));
      return 0;
    }
    if (top === "debug" && sub === "task") {
      emitRemoteJson(name, await remoteDebugTask(session, args));
      return 0;
    }
    if (top === "microservice") {
      const result = await remoteMicroservice(session, args);
      const ok = remoteMicroserviceOk(result);
      emitRemoteJson(name, result, ok);
      return ok ? 0 : 1;
    }
    if (top === "todo-note" || top === "todo") {
      const fetcher = (path: string, init?: { method?: string; body?: unknown }): Promise<FetchJsonResult> => {
        const requestInit = init === undefined
          ? undefined
          : {
            method: init.method,
            body: init.body === undefined ? undefined : JSON.stringify(init.body),
          };
        return frontendJson(session, path, requestInit, 30_000, 5_000_000);
      };
      const result = await runTodoNoteCommandAsync(config, args.slice(1), fetcher);
      const ok = typeof result !== "object" || result === null || !("ok" in result) || (result as { ok?: unknown }).ok !== false;
      if (typeof result === "object" && result !== null && "renderedText" in result && typeof (result as { renderedText?: unknown }).renderedText === "string") {
        process.stdout.write((result as { renderedText: string }).renderedText);
      } else {
        emitRemoteJson(name, result, ok);
      }
      return ok ? 0 : 1;
    }
    if (top === "artifact-registry") {
      emitRemoteJson(name, await remoteArtifactRegistry(session, args));
      return 0;
    }
    if (top === "ci") {
      emitRemoteJson(name, await remoteCi(session, config, args));
      return 0;
    }
    if (top === "decision" || top === "decision-center") {
      const fetcher = (path: string, init?: { method?: string; body?: unknown }): Promise<FetchJsonResult> => {
        const requestInit = init === undefined
          ? undefined
          : {
            method: init.method,
            body: init.body === undefined ? undefined : JSON.stringify(init.body),
        };
        return frontendJson(session, path, requestInit, 30_000);
      };
      const result = await runDecisionCenterCommandAsync(config, args.slice(1), fetcher);
      const ok = typeof result !== "object" || result === null || !("ok" in result) || (result as { ok?: unknown }).ok !== false;
      emitRemoteJson(name, result, ok);
      return ok ? 0 : 1;
    }
    if (top === "codex") {
      emitRemoteJson(name, await remoteCodeQueue(session, args));
      return 0;
    }
    if (top === "network" && sub === "perf") {
      emitRemoteJson(name, await remoteNetworkPerf(options, config, args));
      return 0;
    }
    if (top === "ssh") {
      return await runRemoteSshOverFrontend(session, sub, args.slice(2));
    }
    throw new Error(`remote frontend transport does not support command: ${name}`);
  } catch (error) {
    emitRemoteError(name, error);
    return 1;
  }
}

export async function runRemoteCli(options: RemoteCliOptions, config: UniDeskConfig): Promise<number> {
  if (options.host === null) throw new Error("runRemoteCli requires --main-server-ip or --server");
  const useSsh = options.transport === "ssh" || (options.transport === "auto" && options.identityFile !== null);
  if (useSsh) return runRemoteCliOverSsh(options);
  return runRemoteCliOverFrontend(options, config);
}
