// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. control-plane module for scripts/src/agentrun.ts.

// Moved mechanically from scripts/src/agentrun.ts:2022-2592 for #903.

// SPEC: PJ2026-01020108 cancel lifecycle + PJ2026-01020205 AipodSpec binding + PJ2026-01020302 session policy + PJ2026-01020305 cancel control + PJ2026-01060305/06 YAML execution policy and bounded output draft-2026-06-25-p0.
// Exposes AgentRun lane-scoped policy, AipodSpec SecretRef binding, cancel lifecycle, and bounded default output in the UniDesk CLI.
import { chmodSync, copyFileSync, existsSync, readFileSync, statSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { spawnSync } from "node:child_process";
import { rootPath, type UniDeskConfig } from "../config";
import type { RenderedCliResult } from "../output";
import { applyLocalCaddyManagedSite } from "../pk01-caddy";
import { runSshCommandCapture, type SshCaptureResult } from "../ssh";
import { runRemoteSshCommandCapture } from "../remote";
import { startJob } from "../jobs";
import {
  AGENTRUN_CONFIG_PATH,
  agentRunLaneSummary,
  agentRunPipelineRunName,
  agentRunProviderCredentialRefs,
  resolveAgentRunLaneTarget,
  type AgentRunCancelLifecycleSpec,
  type AgentRunLaneSpec,
} from "../agentrun-lanes";
import {
  agentRunImageArtifact,
  placeholderAgentRunImage,
  renderedFilesDigest,
  renderedObjectsDigest,
  renderAgentRunControlPlaneManifests,
  renderAgentRunGitopsFiles,
  type AgentRunArtifactService,
} from "../agentrun-manifests";
import { sha256Fingerprint } from "../platform-infra-ops-library";

import type { CleanupReleasedPvOptions, CleanupRunnersOptions, CleanupRunsOptions, ConfirmOptions, GitMirrorOptions, LaneConfirmOptions, RefreshOptions, SecretSyncOptions, StatusOptions } from "./options";
import { agentRunControlPlaneStatusCommand } from "./public-exposure";
import { applyYamlScript, manifestObjectRef, yamlLaneGitMirrorStatusScript } from "./secrets";
import { compactAgentRunLaneStatusTarget, compactLaneSecretsStatus } from "./trigger";
import { capture, captureJsonPayload, compactCapture, record, stringOrNull, timedStatusStage } from "./utils";
import { yamlLaneRuntimeStatusScript, yamlLaneSourceStatusScript } from "./yaml-lane";

export function parseSecretSyncOptions(args: string[]): SecretSyncOptions {
  const base = parseConfirmOptions(args);
  let node: string | null = null;
  let lane: string | null = null;
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    if (arg === "--confirm" || arg === "--dry-run") continue;
    if (arg === "--node") {
      const value = args[index + 1];
      if (value === undefined || value.startsWith("--")) throw new Error("--node requires a value");
      node = value;
      index += 1;
      continue;
    }
    if (arg === "--lane") {
      const value = args[index + 1];
      if (value === undefined || value.startsWith("--")) throw new Error("--lane requires a value");
      lane = value;
      index += 1;
      continue;
    }
    throw new Error(`unsupported secret-sync option: ${arg}`);
  }
  return { ...base, node, lane };
}

export function parseLaneConfirmOptions(args: string[]): LaneConfirmOptions {
  const base = parseConfirmOptions(args);
  let node: string | null = null;
  let lane: string | null = null;
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    if (arg === "--confirm" || arg === "--dry-run") continue;
    if (arg === "--node") {
      const value = args[index + 1];
      if (value === undefined || value.startsWith("--")) throw new Error("--node requires a value");
      node = value;
      index += 1;
      continue;
    }
    if (arg === "--lane") {
      const value = args[index + 1];
      if (value === undefined || value.startsWith("--")) throw new Error("--lane requires a value");
      lane = value;
      index += 1;
      continue;
    }
    throw new Error(`unsupported control-plane option: ${arg}`);
  }
  if (node === null && lane === null) throw new Error("control-plane apply requires --node and --lane");
  return { ...base, node, lane };
}

export function parseRefreshOptions(args: string[]): RefreshOptions {
  const base = parseConfirmOptions(args);
  let node: string | null = null;
  let lane: string | null = null;
  let full = false;
  let raw = false;
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    if (arg === "--confirm" || arg === "--dry-run") continue;
    if (arg === "--full") {
      full = true;
      continue;
    }
    if (arg === "--raw") {
      raw = true;
      full = true;
      continue;
    }
    if (arg === "--node") {
      const value = args[index + 1];
      if (value === undefined || value.startsWith("--")) throw new Error("--node requires a value");
      node = value;
      index += 1;
      continue;
    }
    if (arg === "--lane") {
      const value = args[index + 1];
      if (value === undefined || value.startsWith("--")) throw new Error("--lane requires a value");
      lane = value;
      index += 1;
      continue;
    }
    throw new Error(`unsupported refresh option: ${arg}`);
  }
  return { ...base, node, lane, full, raw };
}

export function parseConfirmOptions(args: string[]): ConfirmOptions {
  if (args.includes("--confirm") && args.includes("--dry-run")) throw new Error("accepts only one of --confirm or --dry-run");
  return {
    confirm: args.includes("--confirm"),
    dryRun: args.includes("--dry-run") || !args.includes("--confirm"),
  };
}

export function parseGitMirrorOptions(args: string[]): GitMirrorOptions {
  validateOptions(args, new Set(["--confirm", "--dry-run", "--wait"]), new Set(["--timeout-seconds", "--node", "--lane"]));
  const base = parseConfirmOptions(args);
  const timeoutIndex = args.indexOf("--timeout-seconds");
  const timeoutSeconds = timeoutIndex >= 0 ? Number(args[timeoutIndex + 1]) : 300;
  if (!Number.isFinite(timeoutSeconds) || timeoutSeconds < 30) throw new Error("--timeout-seconds must be a number >= 30");
  return {
    ...base,
    node: optionValue(args, "--node") ?? null,
    lane: optionValue(args, "--lane") ?? null,
    timeoutSeconds,
    wait: args.includes("--wait"),
  };
}

export function parseCleanupRunnersOptions(args: string[]): CleanupRunnersOptions {
  validateOptions(args, new Set(["--confirm", "--dry-run", "--force-active", "--full", "--raw"]), new Set(["--timeout-seconds", "--node", "--lane"]));
  const base = parseConfirmOptions(args);
  const raw = args.includes("--raw");
  return {
    ...base,
    node: optionValue(args, "--node") ?? null,
    lane: optionValue(args, "--lane") ?? null,
    timeoutSeconds: positiveIntegerOption(args, "--timeout-seconds", 180, 600),
    forceActive: args.includes("--force-active"),
    full: raw || args.includes("--full"),
    raw,
  };
}

export function parseCleanupRunsOptions(args: string[]): CleanupRunsOptions {
  validateOptions(args, new Set(["--confirm", "--dry-run"]), new Set(["--min-age-minutes", "--limit", "--timeout-seconds", "--node", "--lane"]));
  const base = parseConfirmOptions(args);
  return {
    ...base,
    node: optionValue(args, "--node") ?? null,
    lane: optionValue(args, "--lane") ?? null,
    minAgeMinutes: positiveIntegerOption(args, "--min-age-minutes", 60, 10080),
    limit: positiveIntegerOption(args, "--limit", 20, 500),
    timeoutSeconds: positiveIntegerOption(args, "--timeout-seconds", 180, 600),
  };
}

export function parseCleanupReleasedPvOptions(args: string[]): CleanupReleasedPvOptions {
  validateOptions(args, new Set(["--confirm", "--dry-run"]), new Set(["--limit", "--timeout-seconds", "--node", "--lane"]));
  const base = parseConfirmOptions(args);
  return {
    ...base,
    node: optionValue(args, "--node") ?? null,
    lane: optionValue(args, "--lane") ?? null,
    limit: positiveIntegerOption(args, "--limit", 20, 500),
    timeoutSeconds: positiveIntegerOption(args, "--timeout-seconds", 120, 600),
  };
}

export function validateOptions(args: string[], booleanOptions: Set<string>, valueOptions: Set<string>): void {
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    if (booleanOptions.has(arg)) continue;
    if (valueOptions.has(arg)) {
      const value = args[index + 1];
      if (value === undefined || value.startsWith("--")) throw new Error(`${arg} requires a value`);
      index += 1;
      continue;
    }
    throw new Error(`unsupported option: ${arg}`);
  }
}

export function optionValue(args: string[], name: string): string | undefined {
  const index = args.indexOf(name);
  if (index === -1) return undefined;
  const value = args[index + 1];
  if (value === undefined || value.startsWith("--")) throw new Error(`${name} requires a value`);
  return value;
}

export function positiveIntegerOption(args: string[], name: string, defaultValue: number, maxValue: number): number {
  const raw = optionValue(args, name);
  if (raw === undefined) return defaultValue;
  const value = Number(raw);
  if (!Number.isInteger(value) || value < 0) throw new Error(`${name} must be a non-negative integer`);
  return Math.min(value, maxValue);
}

export async function controlPlanePlan(_config: UniDeskConfig, options: StatusOptions): Promise<Record<string, unknown>> {
  const target = resolveAgentRunLaneTarget(options);
  const spec = target.spec;
  return {
    ok: true,
    command: "agentrun control-plane plan",
    mode: "yaml-declared-node-lane",
    configPath: target.configPath,
    target: agentRunLaneSummary(spec),
    plannedChecks: [
      "source-branch-exists",
      "source-worktree-exists-and-clean",
      "git-mirror-services-ready",
      "ci-namespace-pipeline-serviceaccount",
      "argo-application-alignment",
      "runtime-namespace-manager-service",
      "database-secretref-present",
      "local-postgres-absent-when-external",
    ],
    deploymentBoundary: {
      mutation: false,
      note: "plan/status are read-only. Long writes must use controlled AgentRun/Platform DB commands and this YAML target.",
    },
    next: {
      status: `bun scripts/cli.ts agentrun control-plane status --node ${spec.nodeId} --lane ${spec.lane}`,
      postgresStatus: spec.database.configRef ? `bun scripts/cli.ts platform-db postgres status --config ${spec.database.configRef}` : null,
      postgresApply: spec.database.configRef ? `bun scripts/cli.ts platform-db postgres apply --config ${spec.database.configRef} --confirm` : null,
      controlPlaneApply: `bun scripts/cli.ts agentrun control-plane apply --node ${spec.nodeId} --lane ${spec.lane} --dry-run`,
    },
    valuesPrinted: false,
  };
}

export async function controlPlaneApply(config: UniDeskConfig, options: LaneConfirmOptions): Promise<Record<string, unknown>> {
  const { configPath, spec } = resolveAgentRunLaneTarget(options);
  const objects = renderAgentRunControlPlaneManifests(spec);
  const manifestYaml = `${objects.map((object) => Bun.YAML.stringify(object).trim()).join("\n---\n")}\n`;
  const objectRefs = objects.map((object) => manifestObjectRef(object));
  const plan = {
    node: spec.nodeId,
    kubeRoute: spec.nodeKubeRoute,
    lane: spec.lane,
    version: spec.version,
    objectCount: objects.length,
    objects: objectRefs,
    manifestBytes: Buffer.byteLength(manifestYaml, "utf8"),
    manifestDigest: renderedObjectsDigest(objects),
    fieldManager: "unidesk-agentrun-control-plane",
    valuesPrinted: false,
  };
  if (options.dryRun || !options.confirm) {
    return {
      ok: true,
      command: "agentrun control-plane apply",
      mode: "dry-run",
      mutation: false,
      configPath,
      target: agentRunLaneSummary(spec),
      plan,
      next: {
        confirm: `bun scripts/cli.ts agentrun control-plane apply --node ${spec.nodeId} --lane ${spec.lane} --confirm`,
        status: `bun scripts/cli.ts agentrun control-plane status --node ${spec.nodeId} --lane ${spec.lane}`,
      },
      valuesPrinted: false,
    };
  }
  const applied = await capture(config, spec.nodeKubeRoute, ["sh", "--", applyYamlScript(manifestYaml, "unidesk-agentrun-control-plane", false)]);
  const payload = captureJsonPayload(applied);
  return {
    ok: applied.exitCode === 0 && payload.ok !== false,
    command: "agentrun control-plane apply",
    mode: "confirmed-apply",
    mutation: true,
    configPath,
    target: agentRunLaneSummary(spec),
    plan,
    result: payload,
    capture: compactCapture(applied, { full: applied.exitCode !== 0, stdoutTailChars: 5000, stderrTailChars: 5000 }),
    next: {
      secretSync: `bun scripts/cli.ts agentrun control-plane secret-sync --node ${spec.nodeId} --lane ${spec.lane} --confirm`,
      status: `bun scripts/cli.ts agentrun control-plane status --node ${spec.nodeId} --lane ${spec.lane}`,
    },
    valuesPrinted: false,
  };
}

export async function status(config: UniDeskConfig, options: StatusOptions): Promise<Record<string, unknown>> {
  return await statusYamlLane(config, options, resolveAgentRunLaneTarget(options));
}

export async function statusYamlLane(config: UniDeskConfig, options: StatusOptions, target: { configPath: string; spec: AgentRunLaneSpec }): Promise<Record<string, unknown>> {
  const spec = target.spec;
  const sourceProbe = await timedStatusStage("source", () => capture(config, `${spec.nodeRoute}:${spec.source.workspace}`, ["sh", "--", yamlLaneSourceStatusScript(spec)]));
  const sourcePayload = captureJsonPayload(sourceProbe.value);
  const branchTipCommit = stringOrNull(sourcePayload.remoteBranchCommit) ?? stringOrNull(sourcePayload.localHead);
  const initialSourceCommit = options.sourceCommit
    ?? stringOrNull(sourcePayload.remoteBranchCommit)
    ?? stringOrNull(sourcePayload.localHead);
  const pipelineRunName = options.pipelineRun ?? (initialSourceCommit ? agentRunPipelineRunName(spec, initialSourceCommit) : null);
  const [runtimeProbe, mirrorProbe] = await Promise.all([
    timedStatusStage("runtime", () => capture(config, spec.nodeKubeRoute, ["sh", "--", yamlLaneRuntimeStatusScript(spec, pipelineRunName)])),
    timedStatusStage("git-mirror", () => capture(config, spec.nodeKubeRoute, ["sh", "--", yamlLaneGitMirrorStatusScript(spec)])),
  ]);
  const runtimePayload = captureJsonPayload(runtimeProbe.value);
  const mirrorPayload = captureJsonPayload(mirrorProbe.value);
  const pipeline = record(runtimePayload.pipeline);
  const pipelineRunStatus = record(runtimePayload.pipelineRun);
  const argo = record(runtimePayload.argo);
  const manager = record(runtimePayload.manager);
  const database = record(runtimePayload.database);
  const secrets = record(runtimePayload.secrets);
  const localPostgres = record(runtimePayload.localPostgres);
  const expectedGitopsRevision = stringOrNull(mirrorPayload.gitopsCommit);
  const mirrorSourceCommit = stringOrNull(mirrorPayload.sourceCommit);
  const pipelineRunSourceCommit = stringOrNull(pipelineRunStatus.sourceCommit);
  const sourceCommit = options.sourceCommit
    ?? (options.pipelineRun !== null ? pipelineRunSourceCommit ?? initialSourceCommit : initialSourceCommit);
  const managerSourceMatchesExpected = Boolean(sourceCommit && manager.sourceCommit === sourceCommit);
  const argoSyncedToGitops = Boolean(expectedGitopsRevision && argo.revision === expectedGitopsRevision);
  const pipelineSucceeded = pipelineRunStatus.status === "True";
  const sourceWorktreeDetached = sourcePayload.branch === "HEAD";
  const targetMode = options.pipelineRun !== null ? "pipeline-run" : options.sourceCommit !== null ? "source-commit" : "latest-source-head";
  const sourceBranchAdvanced = targetMode !== "latest-source-head"
    && sourceCommit !== null
    && branchTipCommit !== null
    && sourceCommit !== branchTipCommit;
  const branchDrift = {
    targetMode,
    sourceBranch: spec.source.branch,
    currentBranchTipCommit: branchTipCommit,
    targetSourceCommit: sourceCommit,
    pipelineRunSourceCommit,
    sourceBranchAdvanced,
    targetSupersededByCurrentBranch: sourceBranchAdvanced,
    closeoutHint: sourceBranchAdvanced
      ? "target PipelineRun/source commit is not the current branch tip; verify the branch tip contains the fix, then trigger-current again for latest-tip closeout"
      : null,
    valuesPrinted: false,
  };
  const warnings = [
    ...(sourceWorktreeDetached ? ["source-worktree-detached"] : []),
    ...(sourceBranchAdvanced ? ["source-branch-advanced-after-target"] : []),
  ];
  const blockers = [
    ...(sourcePayload.workspaceExists === true ? [] : ["source-worktree-missing"]),
    ...(sourcePayload.remoteBranchExists === true ? [] : ["source-branch-missing"]),
    ...(sourcePayload.workspaceClean === true || sourcePayload.workspaceExists !== true ? [] : ["source-worktree-dirty"]),
    ...(mirrorPayload.readReady === true ? [] : ["git-mirror-read-not-ready"]),
    ...(mirrorPayload.writeReady === true ? [] : ["git-mirror-write-not-ready"]),
    ...(mirrorPayload.cacheReady === true ? [] : ["git-mirror-cache-not-ready"]),
    ...(runtimePayload.ciNamespaceExists === true ? [] : ["ci-namespace-missing"]),
    ...(pipeline.exists === true ? [] : ["pipeline-missing"]),
    ...(pipelineRunName !== null && pipelineRunStatus.exists !== true ? ["pipelinerun-missing"] : []),
    ...(pipelineRunStatus.exists !== true || pipelineRunStatus.status === undefined || pipelineRunStatus.status === null || pipelineRunStatus.status === "True" ? [] : ["pipelinerun-not-succeeded"]),
    ...(runtimePayload.serviceAccountExists === true ? [] : ["ci-serviceaccount-missing"]),
    ...(argo.exists === true ? [] : ["argo-application-missing"]),
    ...(mirrorPayload.readReady === true && expectedGitopsRevision === null ? ["gitops-revision-unresolved"] : []),
    ...(argo.exists !== true || expectedGitopsRevision === null || argoSyncedToGitops ? [] : ["argo-revision-stale"]),
    ...(runtimePayload.runtimeNamespaceExists === true ? [] : ["runtime-namespace-missing"]),
    ...(manager.deploymentExists === true ? [] : ["manager-deployment-missing"]),
    ...(manager.deploymentExists !== true || sourceCommit === null || managerSourceMatchesExpected ? [] : ["manager-source-stale"]),
    ...(manager.serviceExists === true ? [] : ["manager-service-missing"]),
    ...(spec.database.mode === "external-postgres" && database.secretPresent !== true ? ["database-secret-missing"] : []),
    ...(secrets.ready === true ? [] : ["lane-secret-missing"]),
    ...(spec.database.localPostgresExpectedAbsent && localPostgres.absent !== true ? ["local-postgres-present"] : []),
  ];
  const ciBlockerNames = new Set(["ci-namespace-missing", "pipeline-missing", "pipelinerun-missing", "pipelinerun-not-succeeded", "ci-serviceaccount-missing"]);
  const ciBlockers = blockers.filter((blocker) => ciBlockerNames.has(blocker));
  const runtimeBlockers = blockers.filter((blocker) => !ciBlockerNames.has(blocker));
  const aligned = blockers.length === 0 && pipelineSucceeded && argoSyncedToGitops && managerSourceMatchesExpected;
  const runtimeAligned = runtimeBlockers.length === 0 && argoSyncedToGitops && managerSourceMatchesExpected;
  const ciEvidenceMissing = pipelineRunName !== null && pipelineRunStatus.exists !== true;
  const mirrorAlreadySynced = mirrorPayload.readReady === true
    && mirrorPayload.writeReady === true
    && sourceCommit !== null
    && mirrorSourceCommit === sourceCommit
    && expectedGitopsRevision !== null;
  const runtimeAlignment = {
    pipelineSucceeded,
    argoRevision: stringOrNull(argo.revision),
    argoSyncedToGitops,
    managerSourceCommit: stringOrNull(manager.sourceCommit),
    managerSourceMatchesExpected,
    runtimeAligned,
  };
  const statusFullCommand = agentRunControlPlaneStatusCommand(spec, options, true);
  const triggerCurrentCommand = `bun scripts/cli.ts agentrun control-plane trigger-current --node ${spec.nodeId} --lane ${spec.lane} --confirm`;
  const nextAction = aligned
    ? { code: "none", summary: "lane aligned; no action required", command: null }
    : ciEvidenceMissing && runtimeAligned && mirrorAlreadySynced
      ? { code: "ci-evidence-missing", summary: "runtime and git mirror are aligned, but the expected PipelineRun evidence is missing; rerun trigger-current to recreate CI evidence", command: triggerCurrentCommand }
      : sourceBranchAdvanced
        ? { code: "target-superseded", summary: "target commit is no longer the branch tip; trigger-current against latest source before closeout", command: triggerCurrentCommand }
        : ciBlockers.length > 0
          ? { code: "ci-blocked", summary: `CI evidence is blocked: ${ciBlockers.join(", ")}`, command: statusFullCommand }
          : runtimeBlockers.length > 0
            ? { code: "runtime-blocked", summary: `runtime alignment is blocked: ${runtimeBlockers.join(", ")}`, command: statusFullCommand }
            : { code: "inspect-full-status", summary: "alignment is inconclusive; inspect full status details", command: statusFullCommand };
  const compactSourceStatus = {
    workspaceExists: sourcePayload.workspaceExists ?? false,
    workspaceClean: sourcePayload.workspaceClean ?? null,
    branch: sourcePayload.branch ?? null,
    remoteBranchExists: sourcePayload.remoteBranchExists ?? false,
    remoteBranchCommit: sourcePayload.remoteBranchCommit ?? null,
    workspaceDetached: sourceWorktreeDetached,
  };
  const compactGitMirrorStatus = {
    readReady: mirrorPayload.readReady ?? false,
    writeReady: mirrorPayload.writeReady ?? false,
    cacheMode: mirrorPayload.cacheMode ?? null,
    cacheReady: mirrorPayload.cacheReady ?? false,
    cachePvcExists: mirrorPayload.cachePvcExists ?? false,
    cacheHostPath: mirrorPayload.cacheHostPath ?? null,
    sourceCommit: mirrorSourceCommit,
    gitopsCommit: expectedGitopsRevision,
    alreadySynced: mirrorAlreadySynced,
  };
  const compactCiStatus = {
    namespaceExists: runtimePayload.ciNamespaceExists ?? false,
    serviceAccountExists: runtimePayload.serviceAccountExists ?? false,
    pipelineExists: pipeline.exists ?? false,
    pipelineRun: {
      name: pipelineRunName,
      exists: pipelineRunStatus.exists ?? false,
      status: pipelineRunStatus.status ?? null,
      reason: pipelineRunStatus.reason ?? null,
      sourceCommit: pipelineRunSourceCommit,
    },
    evidenceMissing: ciEvidenceMissing,
    blockers: ciBlockers,
  };
  const compactArgoStatus = {
    exists: argo.exists ?? false,
    application: argo.application ?? null,
    revision: stringOrNull(argo.revision),
    syncStatus: argo.syncStatus ?? null,
    healthStatus: argo.healthStatus ?? null,
    syncedToGitops: argoSyncedToGitops,
  };
  const compactRuntimeStatus = {
    namespaceExists: runtimePayload.runtimeNamespaceExists ?? false,
    manager: {
      deploymentExists: manager.deploymentExists ?? false,
      serviceExists: manager.serviceExists ?? false,
      sourceCommit: stringOrNull(manager.sourceCommit),
      sourceMatchesExpected: managerSourceMatchesExpected,
    },
    databaseSecretPresent: database.secretPresent ?? null,
    secretsReady: secrets.ready ?? null,
    localPostgresAbsent: localPostgres.absent ?? null,
    blockers: runtimeBlockers,
  };
  const detailedSummary = {
    aligned,
    runtimeAligned,
    ciEvidenceMissing,
    mirrorAlreadySynced,
    blockers,
    warnings,
    sourceCommit,
    expectedPipelineRun: pipelineRunName,
    expectedGitopsRevision,
    runtimeAlignment,
    branchDrift,
    source: {
      workspaceExists: sourcePayload.workspaceExists ?? false,
      workspaceClean: sourcePayload.workspaceClean ?? null,
      branch: sourcePayload.branch ?? null,
      workspaceDetached: sourceWorktreeDetached,
      localHead: sourcePayload.localHead ?? null,
      remoteBranchExists: sourcePayload.remoteBranchExists ?? false,
      remoteBranchCommit: sourcePayload.remoteBranchCommit ?? null,
    },
    gitMirror: {
      readReady: mirrorPayload.readReady ?? false,
      writeReady: mirrorPayload.writeReady ?? false,
      cacheMode: mirrorPayload.cacheMode ?? null,
      cacheReady: mirrorPayload.cacheReady ?? false,
      cachePvcExists: mirrorPayload.cachePvcExists ?? false,
      cacheHostPath: mirrorPayload.cacheHostPath ?? null,
      repositoryCount: Array.isArray(mirrorPayload.repositories) ? mirrorPayload.repositories.length : null,
      sourceCommit: mirrorSourceCommit,
      gitopsCommit: expectedGitopsRevision,
      alreadySynced: mirrorAlreadySynced,
    },
    ci: {
      namespaceExists: runtimePayload.ciNamespaceExists ?? false,
      serviceAccountExists: runtimePayload.serviceAccountExists ?? false,
      pipeline,
      pipelineRun: pipelineRunStatus,
      evidenceMissing: ciEvidenceMissing,
      blockers: ciBlockers,
    },
    argo,
    runtime: {
      namespaceExists: runtimePayload.runtimeNamespaceExists ?? false,
      manager: {
        deploymentExists: manager.deploymentExists ?? false,
        serviceExists: manager.serviceExists ?? false,
        deployment: manager.deployment ?? null,
        service: manager.service ?? null,
        image: manager.image ?? null,
        sourceCommit: stringOrNull(manager.sourceCommit),
        sourceMatchesExpected: managerSourceMatchesExpected,
      },
      database,
      secrets: compactLaneSecretsStatus(secrets),
      localPostgres,
    },
    nextAction,
  };
  const commanderSummary = {
    aligned,
    runtimeAligned,
    ciEvidenceMissing,
    mirrorAlreadySynced,
    blockers,
    warnings,
    sourceCommit,
    expectedPipelineRun: pipelineRunName,
    expectedGitopsRevision,
    runtimeAlignment,
    branchDrift,
    source: compactSourceStatus,
    gitMirror: compactGitMirrorStatus,
    ci: compactCiStatus,
    argo: compactArgoStatus,
    runtime: compactRuntimeStatus,
    nextAction,
  };
  const result: Record<string, unknown> = {
    ok: sourceProbe.value.exitCode === 0 && runtimeProbe.value.exitCode === 0 && mirrorProbe.value.exitCode === 0 && blockers.length === 0,
    command: "agentrun control-plane status",
    mode: "yaml-declared-node-lane",
    configPath: target.configPath,
    target: options.full || options.raw ? agentRunLaneSummary(spec) : compactAgentRunLaneStatusTarget(spec),
    summary: options.full || options.raw ? detailedSummary : commanderSummary,
    alignment: {
      aligned,
      runtimeAligned,
      ciEvidenceMissing,
      mirrorAlreadySynced,
      blockers,
      warnings,
      sourceCommit,
      expectedPipelineRun: pipelineRunName,
      expectedGitopsRevision,
      runtimeAlignment,
      branchDrift,
    },
    timings: {
      sourceMs: sourceProbe.elapsedMs,
      runtimeMs: runtimeProbe.elapsedMs,
      gitMirrorMs: mirrorProbe.elapsedMs,
      totalMs: sourceProbe.elapsedMs + Math.max(runtimeProbe.elapsedMs, mirrorProbe.elapsedMs),
    },
    disclosure: {
      output: options.full || options.raw ? "full" : "compact-summary",
      full: options.full,
      raw: options.raw,
      omittedWhenCompact: options.full || options.raw ? [] : ["full target YAML summary", "detailed source/runtime/gitMirror objects", "capture stdout/stderr tails for successful probes"],
      fullCommand: statusFullCommand,
    },
    next: {
      action: nextAction,
      plan: `bun scripts/cli.ts agentrun control-plane plan --node ${spec.nodeId} --lane ${spec.lane}`,
      postgresStatus: spec.database.configRef ? `bun scripts/cli.ts platform-db postgres status --config ${spec.database.configRef}` : null,
      postgresApply: spec.database.configRef ? `bun scripts/cli.ts platform-db postgres apply --config ${spec.database.configRef} --confirm` : null,
      secretSync: `bun scripts/cli.ts agentrun control-plane secret-sync --node ${spec.nodeId} --lane ${spec.lane} --confirm`,
      restart: `bun scripts/cli.ts agentrun control-plane restart --node ${spec.nodeId} --lane ${spec.lane} --confirm`,
      statusFull: statusFullCommand,
      triggerCurrent: ciEvidenceMissing || sourceBranchAdvanced ? triggerCurrentCommand : null,
      triggerLatest: sourceBranchAdvanced ? `bun scripts/cli.ts agentrun control-plane trigger-current --node ${spec.nodeId} --lane ${spec.lane} --confirm` : null,
    },
    valuesPrinted: false,
  };
  if (options.full || options.raw || sourceProbe.value.exitCode !== 0 || runtimeProbe.value.exitCode !== 0 || mirrorProbe.value.exitCode !== 0) {
    result.captures = {
      source: compactCapture(sourceProbe.value, { full: options.full || options.raw || sourceProbe.value.exitCode !== 0 }),
      runtime: compactCapture(runtimeProbe.value, { full: options.full || options.raw || runtimeProbe.value.exitCode !== 0 }),
      gitMirror: compactCapture(mirrorProbe.value, { full: options.full || options.raw || mirrorProbe.value.exitCode !== 0 }),
    };
  }
  if (options.full || options.raw) {
    result.source = sourcePayload;
    result.runtime = runtimePayload;
    result.gitMirror = mirrorPayload;
  }
  return result;
}
