import type { UniDeskConfig } from "./config";
import { runSshCommandCapture, type SshCaptureResult } from "./ssh";
import { startJob } from "./jobs";

const g14SourceRoute = "G14:/root/agentrun-v01";
const g14K3sRoute = "G14:k3s";
const sourceBranch = "v0.1";
const runtimeNamespace = "agentrun-v01";
const ciNamespace = "agentrun-ci";
const pipelineName = "agentrun-v01-ci-image-publish";
const argoNamespace = "argocd";
const argoApplication = "agentrun-g14-v01";
const gitopsBranch = "v0.1-gitops";
const gitMirrorNamespace = "devops-infra";
const gitMirrorReadUrl = "http://git-mirror-http.devops-infra.svc.cluster.local/pikasTech/agentrun.git";
const gitMirrorWriteUrl = "http://git-mirror-write.devops-infra.svc.cluster.local/pikasTech/agentrun.git";
const gitMirrorRepoPath = "/cache/pikasTech/agentrun.git";
const gitMirrorSyncJobPrefix = "git-mirror-agentrun-sync-manual";
const gitMirrorFlushJobPrefix = "git-mirror-agentrun-flush-manual";
const githubSshUrl = "ssh://git@ssh.github.com:443/pikasTech/agentrun.git";
const mirrorToolsImage = "127.0.0.1:5000/hwlab/hwlab-ci-node-tools:node22-alpine-bun-v1";

export function agentRunHelp(): unknown {
  return {
    command: "agentrun v01 control-plane status|trigger-current|refresh | git-mirror status|sync|flush",
    output: "json",
    usage: [
      "bun scripts/cli.ts agentrun v01 control-plane status",
      "bun scripts/cli.ts agentrun v01 control-plane status --full",
      "bun scripts/cli.ts agentrun v01 control-plane trigger-current --dry-run",
      "bun scripts/cli.ts agentrun v01 control-plane trigger-current --confirm",
      "bun scripts/cli.ts agentrun v01 control-plane refresh --dry-run",
      "bun scripts/cli.ts agentrun v01 control-plane refresh --confirm",
      "bun scripts/cli.ts agentrun v01 git-mirror status",
      "bun scripts/cli.ts agentrun v01 git-mirror status --full",
      "bun scripts/cli.ts agentrun v01 git-mirror sync --confirm",
      "bun scripts/cli.ts agentrun v01 git-mirror flush --confirm",
    ],
    description: "Operate AgentRun v0.1 Tekton/Argo control plane and devops-infra git mirror through G14 routes; status is read-only and trigger-current pre-syncs mirror refs before creating the PipelineRun.",
  };
}

export async function runAgentRunCommand(config: UniDeskConfig, args: string[]): Promise<Record<string, unknown>> {
  const [lane, group, action] = args;
  if (lane !== "v01") return unsupported(args);
  if (group === "control-plane") {
    if (action === "status") return await status(config, parseDisclosureOptions(args.slice(3)));
    if (action === "trigger-current") return await triggerCurrent(config, parseTriggerOptions(args.slice(3)));
    if (action === "refresh") return await refresh(config, parseConfirmOptions(args.slice(3)));
  }
  if (group === "git-mirror") {
    if (action === "status") return await gitMirrorStatus(config, parseDisclosureOptions(args.slice(3)));
    if (action === "sync" || action === "flush") {
      const options = parseGitMirrorOptions(args.slice(3));
      if (options.confirm && !options.wait) return startAsyncAgentRunJob(`agentrun_v01_git_mirror_${action}`, ["bun", "scripts/cli.ts", "agentrun", "v01", "git-mirror", action, "--confirm", "--wait", "--timeout-seconds", String(options.timeoutSeconds)], `Run AgentRun v0.1 git mirror ${action} on G14`);
      return await runGitMirrorJob(config, action, options);
    }
  }
  return unsupported(args);
}

interface TriggerOptions {
  confirm: boolean;
  dryRun: boolean;
}

interface ConfirmOptions {
  confirm: boolean;
  dryRun: boolean;
}

interface GitMirrorOptions extends ConfirmOptions {
  timeoutSeconds: number;
  wait: boolean;
}

interface DisclosureOptions {
  full: boolean;
  raw: boolean;
}

interface TimedValue<T> {
  value: T;
  elapsedMs: number;
}

function parseDisclosureOptions(args: string[]): DisclosureOptions {
  for (const arg of args) {
    if (arg !== "--full" && arg !== "--raw") throw new Error(`unsupported status option: ${arg}`);
  }
  const raw = args.includes("--raw");
  return { full: raw || args.includes("--full"), raw };
}

function parseTriggerOptions(args: string[]): TriggerOptions {
  return parseConfirmOptions(args);
}

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"),
  };
}

function parseGitMirrorOptions(args: string[]): GitMirrorOptions {
  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, timeoutSeconds, wait: args.includes("--wait") };
}

async function status(config: UniDeskConfig, options: DisclosureOptions): Promise<Record<string, unknown>> {
  const sourceProbe = await timedStatusStage("source", () => capture(config, g14SourceRoute, ["script", "--", [
    "cd /root/agentrun-v01",
    "git fetch origin v0.1 >/dev/null 2>&1 || true",
    "printf 'sourceCommit='",
    "git rev-parse HEAD",
    "printf 'originV01='",
    "git rev-parse origin/v0.1 2>/dev/null || true",
    "printf 'gitopsLatest='",
    `git ls-remote origin ${gitopsBranch} 2>/dev/null | awk '{print $1}' || true`,
    "git status --short --branch",
  ].join("\n")]));
  const source = sourceProbe.value;
  const localSourceCommit = matchLine(source.stdout, "sourceCommit=");
  const originSourceCommit = matchLine(source.stdout, "originV01=");
  const sourceCommit = isGitSha(originSourceCommit ?? "") ? originSourceCommit : localSourceCommit;
  const gitopsLatest = matchLine(source.stdout, "gitopsLatest=");
  const pipelineRun = sourceCommit ? pipelineRunName(sourceCommit) : null;
  const [runtimeProbe, mirrorProbe] = await Promise.all([
    timedStatusStage("runtime", () => capture(config, g14K3sRoute, ["script", "--", statusScript(pipelineRun)])),
    timedStatusStage("git-mirror", () => readGitMirrorStatus(config)),
  ]);
  const k3s = runtimeProbe.value;
  const mirror = mirrorProbe.value;
  const argo = parseArgoStatus(k3s.stdout);
  const ciSummary = labeledJson(k3s.stdout, "ciSummary");
  const pipelineRunCondition = labeledJson(k3s.stdout, "pipelineRunCondition");
  const managerImage = parseManagerImage(k3s.stdout);
  const mirrorSummary = mirror.summary;
  const runtimeAlignment = {
    localHeadMatchesOrigin: Boolean(localSourceCommit && originSourceCommit && localSourceCommit === originSourceCommit),
    argoRevision: argo.revision,
    argoSyncStatus: argo.syncStatus,
    argoHealthStatus: argo.healthStatus,
    syncedToGitopsLatest: Boolean(gitopsLatest && argo.revision === gitopsLatest),
    managerSourceCommit: managerImage.sourceCommit,
    managerSourceMatchesExpected: Boolean(sourceCommit && managerImage.sourceCommit === sourceCommit),
  };
  const summary = {
    sourceCommit,
    expectedPipelineRun: pipelineRun,
    pipelineRun: {
      status: pipelineRunCondition.status ?? null,
      reason: pipelineRunCondition.reason ?? null,
      completionTime: pipelineRunCondition.completionTime ?? null,
    },
    argo,
    managerImage,
    gitMirror: {
      localV01: mirrorSummary.localV01 ?? null,
      githubV01: mirrorSummary.githubV01 ?? null,
      localGitops: mirrorSummary.localGitops ?? null,
      githubGitops: mirrorSummary.githubGitops ?? null,
      pendingFlush: mirrorSummary.pendingFlush ?? null,
      sourceInSync: mirrorSummary.sourceInSync ?? null,
      gitopsInSync: mirrorSummary.gitopsInSync ?? null,
      githubInSync: mirrorSummary.githubInSync ?? null,
    },
    aligned: pipelineRunCondition.status === "True" &&
      runtimeAlignment.localHeadMatchesOrigin === true &&
      runtimeAlignment.syncedToGitopsLatest === true &&
      runtimeAlignment.managerSourceMatchesExpected === true &&
      mirrorSummary.githubInSync === true &&
      mirrorSummary.pendingFlush === false,
  };
  return {
    ok: source.exitCode === 0 && k3s.exitCode === 0 && mirror.ok === true,
    command: "agentrun v01 control-plane status",
    lane: "v0.1",
    summary,
    sourceCommit,
    sourceCommitSource: sourceCommit === originSourceCommit ? "origin/v0.1" : "local-head",
    localSourceCommit,
    originSourceCommit,
    gitopsLatest,
    expectedPipelineRun: pipelineRun,
    timings: {
      sourceMs: sourceProbe.elapsedMs,
      runtimeMs: runtimeProbe.elapsedMs,
      gitMirrorMs: mirrorProbe.elapsedMs,
      totalMs: sourceProbe.elapsedMs + Math.max(runtimeProbe.elapsedMs, mirrorProbe.elapsedMs),
    },
    source: compactCapture(source, { full: options.full || options.raw, stdoutTailChars: 3000, stderrTailChars: 2000 }),
    runtime: compactCapture(k3s, { full: options.full || options.raw, stdoutTailChars: 8000, stderrTailChars: 4000 }),
    pipelineRunCondition,
    ciSummary,
    gitMirror: {
      ok: mirror.ok,
      readUrl: mirror.readUrl,
      writeUrl: mirror.writeUrl,
      summary: mirror.summary,
      probe: compactCapture(mirror.result, { full: options.full || options.raw, stdoutTailChars: 6000, stderrTailChars: 3000 }),
      ...(options.raw ? { raw: mirror.raw } : {}),
    },
    runtimeAlignment,
    disclosure: {
      defaultView: "compact-low-noise",
      full: options.full,
      raw: options.raw,
      stdoutTailOmitted: !(options.full || options.raw),
      rawGitMirrorOmitted: !options.raw,
      expandWith: "bun scripts/cli.ts agentrun v01 control-plane status --full",
      rawWith: "bun scripts/cli.ts agentrun v01 control-plane status --raw",
    },
    next: {
      triggerCurrent: "bun scripts/cli.ts agentrun v01 control-plane trigger-current --confirm",
      refresh: "bun scripts/cli.ts agentrun v01 control-plane refresh --confirm",
    },
  };
}

async function triggerCurrent(config: UniDeskConfig, options: TriggerOptions): Promise<Record<string, unknown>> {
  const source = await capture(config, g14SourceRoute, ["script", "--", [
    "set -u",
    "cd /root/agentrun-v01",
    "fetch_status=succeeded",
    "fetch_output=$(git fetch origin v0.1 2>&1)",
    "fetch_code=$?",
    "if [ \"$fetch_code\" -ne 0 ]; then fetch_status=failed; fi",
    "printf 'fetchStatus=%s\\n' \"$fetch_status\"",
    "printf 'fetchExitCode=%s\\n' \"$fetch_code\"",
    "printf 'fetchOutput=%s\\n' \"$fetch_output\" | tail -n 8",
    "origin_ref=$(git rev-parse refs/remotes/origin/v0.1 2>/dev/null || true)",
    "merge_status=skipped",
    "merge_code=0",
    "if [ -n \"$origin_ref\" ]; then",
    "  merge_output=$(git merge --ff-only refs/remotes/origin/v0.1 2>&1)",
    "  merge_code=$?",
    "  if [ \"$merge_code\" -eq 0 ]; then merge_status=succeeded; else merge_status=failed; fi",
    "  printf 'mergeStatus=%s\\n' \"$merge_status\"",
    "  printf 'mergeExitCode=%s\\n' \"$merge_code\"",
    "  printf 'mergeOutput=%s\\n' \"$merge_output\" | tail -n 8",
    "  if [ \"$merge_code\" -ne 0 ]; then exit \"$merge_code\"; fi",
    "else",
    "  printf 'mergeStatus=skipped-origin-missing\\n'",
    "  printf 'originRefMissing=true\\n'",
    "fi",
    "printf 'sourceCommit='",
    "git rev-parse HEAD",
    "printf 'originV01='",
    "git rev-parse refs/remotes/origin/v0.1 2>/dev/null || true",
    "git status --short --branch",
  ].join("\n")]);
  const sourceCommit = matchLine(source.stdout, "sourceCommit=");
  const pipelineRun = sourceCommit ? pipelineRunName(sourceCommit) : null;
  if (source.exitCode !== 0 || !sourceCommit || !isGitSha(sourceCommit) || !pipelineRun) {
    return { ok: false, command: "agentrun v01 control-plane trigger-current", degradedReason: "source-head-unresolved", source: compactCapture(source) };
  }
  const plan = {
    lane: "v0.1",
    sourceBranch,
    sourceCommit,
    pipelineRun,
    namespace: ciNamespace,
    pipeline: pipelineName,
    runtimeNamespace,
    gitMirror: {
      readUrl: gitMirrorReadUrl,
      writeUrl: gitMirrorWriteUrl,
    },
  };
  const mirrorBefore = await readGitMirrorStatus(config);
  const mirrorRequirement = gitMirrorSyncRequirement(sourceCommit, mirrorBefore.raw);
  if (options.dryRun || !options.confirm) {
    return {
      ok: true,
      command: "agentrun v01 control-plane trigger-current",
      dryRun: true,
      plan,
      gitMirrorPreSync: {
        required: mirrorRequirement.required,
        reason: mirrorRequirement.reason,
        before: mirrorBefore.summary,
      },
      next: { confirm: "bun scripts/cli.ts agentrun v01 control-plane trigger-current --confirm" },
    };
  }
  let gitMirrorPreSync: Record<string, unknown> = {
    required: mirrorRequirement.required,
    reason: mirrorRequirement.reason,
    before: mirrorBefore.summary,
  };
  if (mirrorRequirement.required) {
    const synced = await runGitMirrorJob(config, "sync", { confirm: true, dryRun: false, timeoutSeconds: 300, wait: true });
    const after = await readGitMirrorStatus(config);
    const afterRequirement = gitMirrorSyncRequirement(sourceCommit, after.raw);
    gitMirrorPreSync = { ...gitMirrorPreSync, sync: synced, after: after.summary, ok: synced.ok === true && afterRequirement.required === false };
    if (synced.ok !== true || afterRequirement.required !== false) {
      return {
        ok: false,
        command: "agentrun v01 control-plane trigger-current",
        dryRun: false,
        degradedReason: "git-mirror-local-v01-not-current-after-sync",
        plan,
        gitMirrorPreSync,
      };
    }
  }
  const created = await capture(config, g14K3sRoute, ["script", "--", triggerScript(sourceCommit, pipelineRun)]);
  return {
    ok: created.exitCode === 0,
    command: "agentrun v01 control-plane trigger-current",
    dryRun: false,
    plan,
    gitMirrorPreSync,
    created: compactCapture(created),
    next: {
      status: "bun scripts/cli.ts agentrun v01 control-plane status",
      logs: `trans G14:k3s logs -n ${ciNamespace} -l tekton.dev/pipelineRun=${pipelineRun} --tail 120`,
    },
  };
}

async function refresh(config: UniDeskConfig, options: ConfirmOptions): Promise<Record<string, unknown>> {
  const source = await capture(config, g14SourceRoute, ["script", "--", [
    "cd /root/agentrun-v01",
    "printf 'gitopsLatest='",
    `git ls-remote origin ${gitopsBranch} 2>/dev/null | awk '{print $1}' || true`,
  ].join("\n")]);
  const gitopsLatest = matchLine(source.stdout, "gitopsLatest=");
  const plan = {
    lane: "v0.1",
    argoNamespace,
    argoApplication,
    gitopsBranch,
    gitopsLatest,
  };
  if (options.dryRun || !options.confirm) {
    return {
      ok: true,
      command: "agentrun v01 control-plane refresh",
      dryRun: true,
      plan,
      next: { confirm: "bun scripts/cli.ts agentrun v01 control-plane refresh --confirm" },
    };
  }
  const refreshed = await capture(config, g14K3sRoute, ["script", "--", refreshScript()]);
  return {
    ok: source.exitCode === 0 && refreshed.exitCode === 0,
    command: "agentrun v01 control-plane refresh",
    dryRun: false,
    plan,
    source: compactCapture(source),
    refreshed: compactCapture(refreshed),
    next: { status: "bun scripts/cli.ts agentrun v01 control-plane status" },
  };
}

function statusScript(pipelineRun: string | null): string {
  const pr = pipelineRun ?? "";
  return [
    "set -eu",
    "printf 'pipelineRun\\tstatus\\treason\\tstart\\tcompletion\\n'",
    pr.length > 0
      ? `kubectl -n ${ciNamespace} get pipelinerun ${shQuote(pr)} -o 'jsonpath={.metadata.name}{\"\\t\"}{.status.conditions[0].status}{\"\\t\"}{.status.conditions[0].reason}{\"\\t\"}{.status.startTime}{\"\\t\"}{.status.completionTime}{\"\\n\"}' 2>/dev/null || true`
      : "true",
    "printf 'pipelineRunCondition='",
    pr.length > 0
      ? [
        `if kubectl -n ${ciNamespace} get pipelinerun ${shQuote(pr)} -o json >/tmp/agentrun-v01-pipelinerun.json 2>/dev/null; then`,
        "node <<'NODE'",
        "const fs = require('node:fs');",
        "const pr = JSON.parse(fs.readFileSync('/tmp/agentrun-v01-pipelinerun.json', 'utf8'));",
        "const condition = pr?.status?.conditions?.[0] || {};",
        "console.log(JSON.stringify({",
        "  name: pr?.metadata?.name || null,",
        "  status: condition.status || null,",
        "  reason: condition.reason || null,",
        "  message: condition.message || null,",
        "  startTime: pr?.status?.startTime || null,",
        "  completionTime: pr?.status?.completionTime || null",
        "}));",
        "NODE",
        "else printf '{}\\n'; fi",
      ].join("\n")
      : "printf '{}\\n'",
    "printf 'taskRuns\\n'",
    pr.length > 0
      ? `kubectl -n ${ciNamespace} get taskrun -l tekton.dev/pipelineRun=${shQuote(pr)} -o 'custom-columns=NAME:.metadata.name,STATUS:.status.conditions[0].status,REASON:.status.conditions[0].reason,START:.status.startTime,COMPLETION:.status.completionTime' --no-headers 2>/dev/null || true`
      : "true",
    "printf 'taskRunPods\\n'",
    pr.length > 0
      ? `kubectl -n ${ciNamespace} get pod -l tekton.dev/pipelineRun=${shQuote(pr)} -o 'custom-columns=NAME:.metadata.name,READY:.status.containerStatuses[*].ready,STATUS:.status.phase,RESTARTS:.status.containerStatuses[*].restartCount,AGE:.metadata.creationTimestamp' --no-headers 2>/dev/null || true`
      : "true",
    "printf 'recentPipelineRuns\\n'",
    `kubectl -n ${ciNamespace} get pipelinerun --sort-by=.metadata.creationTimestamp -o 'custom-columns=NAME:.metadata.name,STATUS:.status.conditions[0].status,REASON:.status.conditions[0].reason,CREATED:.metadata.creationTimestamp' --no-headers 2>/dev/null | tail -n 5 || true`,
    "printf 'ciSummary='",
    pr.length > 0
      ? [
        `if kubectl -n ${ciNamespace} get taskrun -l tekton.dev/pipelineRun=${shQuote(pr)} -o json >/tmp/agentrun-v01-taskruns.json 2>/dev/null; then`,
        "node <<'NODE'",
        "const fs = require('node:fs');",
        "const data = JSON.parse(fs.readFileSync('/tmp/agentrun-v01-taskruns.json', 'utf8'));",
        "const items = Array.isArray(data.items) ? data.items : [];",
        "function task(item) { return item?.metadata?.labels?.['tekton.dev/pipelineTask'] || item?.metadata?.name || null; }",
        "function result(item, name) { return (item?.status?.results || item?.status?.taskResults || []).find((entry) => entry.name === name)?.value ?? null; }",
        "function seconds(start, end) { const s = Date.parse(start || ''); const e = Date.parse(end || ''); return Number.isFinite(s) && Number.isFinite(e) ? Math.round((e - s) / 1000) : null; }",
        "const taskRuns = items.map((item) => ({ name: item?.metadata?.name || null, task: task(item), status: item?.status?.conditions?.[0]?.status || null, reason: item?.status?.conditions?.[0]?.reason || null, seconds: seconds(item?.status?.startTime, item?.status?.completionTime) }));",
        "const plan = items.find((item) => task(item) === 'plan-artifacts');",
        "const image = items.find((item) => task(item) === 'image-publish');",
        "const imageSeconds = taskRuns.find((item) => item.task === 'image-publish')?.seconds ?? null;",
        "console.log(JSON.stringify({",
        "  planArtifacts: { summary: plan ? result(plan, 'summary') : null, envIdentity: plan ? result(plan, 'env-identity') : null, buildCount: plan ? Number(result(plan, 'build-count') || 0) : null, reuseCount: plan ? Number(result(plan, 'reuse-count') || 0) : null },",
        "  envImage: { status: image ? result(image, 'status') : null, envIdentity: image ? result(image, 'env-identity') : null, image: image ? result(image, 'image') : null, digest: image ? result(image, 'digest') : null, repositoryDigest: image ? result(image, 'repository-digest') : null },",
        "  taskRuns,",
        "  performance: { imagePublishSeconds: imageSeconds, buildWarning: typeof imageSeconds === 'number' && imageSeconds > 120, criticalWarning: typeof imageSeconds === 'number' && imageSeconds > 180 }",
        "}));",
        "NODE",
        "else printf '{}\\n'; fi",
      ].join("\n")
      : "printf '{}\\n'",
    "printf 'argo\\n'",
    `kubectl -n ${argoNamespace} get application ${argoApplication} -o 'jsonpath={.status.sync.revision}{"\\t"}{.status.sync.status}{"\\t"}{.status.health.status}{"\\n"}' 2>/dev/null || true`,
    "printf 'workloads\\n'",
    `kubectl -n ${runtimeNamespace} get deploy,sts -o wide 2>/dev/null || true`,
    "printf 'managerImage\\n'",
    `kubectl -n ${runtimeNamespace} get deploy agentrun-mgr -o 'jsonpath={.spec.template.spec.containers[0].image}{"\\t"}{.spec.template.spec.containers[0].env[?(@.name=="AGENTRUN_SOURCE_COMMIT")].value}{"\\n"}' 2>/dev/null || true`,
    "printf 'managerPods\\n'",
    `kubectl -n ${runtimeNamespace} get pod -l app.kubernetes.io/name=agentrun-mgr -o 'custom-columns=NAME:.metadata.name,READY:.status.containerStatuses[*].ready,STATUS:.status.phase,RESTARTS:.status.containerStatuses[*].restartCount,CREATED:.metadata.creationTimestamp' --no-headers 2>/dev/null || true`,
    "printf 'recentRunnerPods\\n'",
    `kubectl -n ${runtimeNamespace} get pod -l app.kubernetes.io/component=runner --sort-by=.metadata.creationTimestamp -o 'custom-columns=NAME:.metadata.name,READY:.status.containerStatuses[*].ready,STATUS:.status.phase,RESTARTS:.status.containerStatuses[*].restartCount,CREATED:.metadata.creationTimestamp' --no-headers 2>/dev/null | tail -n 8 || true`,
  ].join("\n");
}

function refreshScript(): string {
  return [
    "set -eu",
    `kubectl -n ${argoNamespace} annotate application ${argoApplication} argocd.argoproj.io/refresh=hard --overwrite`,
    `kubectl -n ${argoNamespace} get application ${argoApplication} -o 'jsonpath={.status.sync.revision}{"\\t"}{.status.sync.status}{"\\t"}{.status.health.status}{"\\n"}' 2>/dev/null || true`,
  ].join("\n");
}

function triggerScript(sourceCommit: string, pipelineRun: string): string {
  return [
    "set -eu",
    "cd /root/agentrun-v01",
    `if kubectl -n ${ciNamespace} get pipelinerun ${shQuote(pipelineRun)} >/dev/null 2>&1; then`,
    `  existing_status="$(kubectl -n ${ciNamespace} get pipelinerun ${shQuote(pipelineRun)} -o 'jsonpath={.status.conditions[0].status}:{.status.conditions[0].reason}' 2>/dev/null || true)"`,
    "  case \"$existing_status\" in",
    "    False:*)",
    "      printf 'deleteExisting=%s\\n' \"$existing_status\"",
    `      kubectl -n ${ciNamespace} delete pipelinerun ${shQuote(pipelineRun)} --wait=true --timeout=20s`,
    "      ;;",
    "    *)",
    "      printf 'refuseExisting=%s\\n' \"$existing_status\"",
    "      printf 'reason=existing-pipelinerun-active-or-succeeded\\n'",
    "      exit 20",
    "      ;;",
    "  esac",
    "fi",
    "kubectl apply -f deploy/templates/tekton/rbac.yaml",
    "kubectl apply -f deploy/templates/tekton/pipeline.yaml",
    "kubectl apply -f deploy/templates/argocd/project.yaml",
    "kubectl apply -f deploy/templates/argocd/application-v01.yaml",
    "cat <<'YAML' | kubectl create -f -",
    "apiVersion: tekton.dev/v1",
    "kind: PipelineRun",
    "metadata:",
    `  name: ${pipelineRun}`,
    `  namespace: ${ciNamespace}`,
    "spec:",
    "  pipelineRef:",
    `    name: ${pipelineName}`,
    "  taskRunTemplate:",
    "    serviceAccountName: agentrun-v01-tekton-runner",
    "    podTemplate:",
    "      hostNetwork: true",
    "      dnsPolicy: ClusterFirstWithHostNet",
    "      securityContext:",
    "        fsGroup: 1000",
    "  params:",
    "    - name: revision",
    `      value: ${sourceCommit}`,
    "    - name: git-read-url",
    `      value: ${gitMirrorReadUrl}`,
    "    - name: git-write-url",
    `      value: ${gitMirrorWriteUrl}`,
    "    - name: tools-image",
    `      value: ${mirrorToolsImage}`,
    "  workspaces:",
    "    - name: source",
    "      volumeClaimTemplate:",
    "        spec:",
    "          accessModes: [\"ReadWriteOnce\"]",
    "          resources:",
    "            requests:",
    "              storage: 5Gi",
    "    - name: git-ssh",
    "      secret:",
    "        secretName: agentrun-git-ssh",
    "YAML",
    `printf 'created=${pipelineRun}\\n'`,
  ].join("\n");
}

async function gitMirrorStatus(config: UniDeskConfig, options: DisclosureOptions = { full: false, raw: false }): Promise<Record<string, unknown>> {
  const observation = await readGitMirrorStatus(config);
  const summary = observation.summary;
  return {
    ok: observation.ok,
    command: "agentrun v01 git-mirror status",
    namespace: gitMirrorNamespace,
    readUrl: gitMirrorReadUrl,
    writeUrl: gitMirrorWriteUrl,
    summary,
    ...(options.raw ? { raw: observation.raw } : {}),
    probe: compactCapture(observation.result, { full: options.full || options.raw, stdoutTailChars: 6000, stderrTailChars: 3000 }),
    disclosure: {
      defaultView: "compact-low-noise",
      full: options.full,
      raw: options.raw,
      rawOmitted: !options.raw,
      probeTailOmitted: !(options.full || options.raw),
      expandWith: "bun scripts/cli.ts agentrun v01 git-mirror status --full",
      rawWith: "bun scripts/cli.ts agentrun v01 git-mirror status --raw",
    },
    next: {
      sync: "bun scripts/cli.ts agentrun v01 git-mirror sync --confirm",
      flush: summary.pendingFlush === true ? "bun scripts/cli.ts agentrun v01 git-mirror flush --confirm" : null,
    },
  };
}

async function readGitMirrorStatus(config: UniDeskConfig): Promise<Record<string, unknown> & { result: SshCaptureResult; raw: string; summary: Record<string, unknown> }> {
  const script = [
    "set +e",
    "printf 'resources\\n'",
    `kubectl -n ${gitMirrorNamespace} get deploy,svc,pvc,cm -l app.kubernetes.io/name=git-mirror -o name 2>/dev/null || true`,
    "printf 'jobs\\n'",
    `kubectl -n ${gitMirrorNamespace} get job -l app.kubernetes.io/name=git-mirror --sort-by=.metadata.creationTimestamp -o 'custom-columns=NAME:.metadata.name,SUCCEEDED:.status.succeeded,FAILED:.status.failed,START:.status.startTime,COMPLETION:.status.completionTime' --no-headers 2>/dev/null | tail -n 8 || true`,
    "printf 'cache\\n'",
    `kubectl exec -n ${gitMirrorNamespace} deploy/git-mirror-http -- sh -lc ${shQuote(gitMirrorCacheProbeScript())}`,
  ].join("\n");
  const result = await capture(config, g14K3sRoute, ["script", "--", script]);
  const raw = result.stdout;
  const summary = gitMirrorStatusSummary(raw);
  return {
    ok: result.exitCode === 0 && summary.localV01 !== null,
    namespace: gitMirrorNamespace,
    readUrl: gitMirrorReadUrl,
    writeUrl: gitMirrorWriteUrl,
    raw,
    summary,
    result,
  };
}

async function runGitMirrorJob(config: UniDeskConfig, action: "sync" | "flush", options: GitMirrorOptions): Promise<Record<string, unknown>> {
  const jobName = `${action === "sync" ? gitMirrorSyncJobPrefix : gitMirrorFlushJobPrefix}-${Date.now().toString(36)}`.slice(0, 63);
  const manifest = gitMirrorJobManifest(action, jobName);
  const manifestB64 = Buffer.from(JSON.stringify(manifest), "utf8").toString("base64");
  const command = `agentrun v01 git-mirror ${action}`;
  if (options.dryRun || !options.confirm) {
    return {
      ok: true,
      command,
      dryRun: true,
      namespace: gitMirrorNamespace,
      jobName,
      manifest,
      next: { confirm: `bun scripts/cli.ts ${command} --confirm` },
    };
  }
  const created = await createGitMirrorJob(config, jobName, manifestB64);
  if (created.exitCode !== 0 || !options.wait) {
    const status = await gitMirrorStatus(config);
    return {
      ok: created.exitCode === 0,
      command,
      dryRun: false,
      mode: options.wait ? "create-failed" : "submitted",
      namespace: gitMirrorNamespace,
      jobName,
      result: compactCapture(created),
      status,
      next: {
        status: "bun scripts/cli.ts agentrun v01 git-mirror status",
        wait: `bun scripts/cli.ts agentrun v01 git-mirror ${action} --confirm --wait`,
      },
    };
  }
  const wait = await waitForGitMirrorJob(config, action, jobName, options.timeoutSeconds);
  const status = await gitMirrorStatus(config);
  return {
    ok: created.exitCode === 0 && wait.ok === true,
    command,
    dryRun: false,
    mode: "waited",
    namespace: gitMirrorNamespace,
    jobName,
    result: compactCapture(created),
    wait,
    status,
    next: {
      status: "bun scripts/cli.ts agentrun v01 git-mirror status",
      flush: action === "sync" && status.summary && record(status.summary).pendingFlush === true ? "bun scripts/cli.ts agentrun v01 git-mirror flush --confirm" : null,
    },
  };
}

async function createGitMirrorJob(config: UniDeskConfig, jobName: string, manifestB64: string): Promise<SshCaptureResult> {
  const script = [
    "set -eu",
    `job=${shQuote(jobName)}`,
    `manifest_b64=${shQuote(manifestB64)}`,
    "manifest_path=\"/tmp/$job.json\"",
    "printf '%s' \"$manifest_b64\" | base64 -d > \"$manifest_path\"",
    `kubectl delete job -n ${gitMirrorNamespace} "$job" --ignore-not-found=true >/dev/null`,
    "kubectl create -f \"$manifest_path\"",
    `kubectl get job -n ${gitMirrorNamespace} "$job" -o 'jsonpath=created={.metadata.name}{\"\\n\"}'`,
  ].join("\n");
  return await capture(config, g14K3sRoute, ["script", "--", script]);
}

async function waitForGitMirrorJob(config: UniDeskConfig, action: "sync" | "flush", jobName: string, timeoutSeconds: number): Promise<Record<string, unknown>> {
  const startedAtMs = Date.now();
  let lastProbe: SshCaptureResult | null = null;
  let polls = 0;
  while (Date.now() - startedAtMs <= timeoutSeconds * 1000) {
    polls += 1;
    lastProbe = await capture(config, g14K3sRoute, ["script", "--", gitMirrorJobProbeScript(jobName)]);
    const summary = gitMirrorJobProbeSummary(lastProbe.stdout);
    process.stderr.write(`${JSON.stringify({
      event: `agentrun.git-mirror.${action}.progress`,
      at: new Date().toISOString(),
      stage: "k8s-job",
      status: summary.succeeded ? "succeeded" : summary.failed ? "failed" : "running",
      jobName,
      polls,
      elapsedMs: Date.now() - startedAtMs,
    })}\n`);
    if (summary.succeeded) {
      return {
        ok: true,
        action,
        jobName,
        polls,
        elapsedMs: Date.now() - startedAtMs,
        summary,
        probe: compactCapture(lastProbe),
      };
    }
    if (summary.failed) {
      return {
        ok: false,
        action,
        jobName,
        polls,
        elapsedMs: Date.now() - startedAtMs,
        degradedReason: "git-mirror-job-failed",
        summary,
        probe: compactCapture(lastProbe),
      };
    }
    await sleep(5_000);
  }
  return {
    ok: false,
    action,
    jobName,
    polls,
    elapsedMs: Date.now() - startedAtMs,
    degradedReason: "git-mirror-job-timeout",
    probe: lastProbe ? compactCapture(lastProbe) : null,
  };
}

function gitMirrorJobProbeScript(jobName: string): string {
  return [
    "set +e",
    `job=${shQuote(jobName)}`,
    "printf 'jobStatus='",
    `kubectl get job -n ${gitMirrorNamespace} "$job" -o jsonpath='succeeded={.status.succeeded} failed={.status.failed} active={.status.active} start={.status.startTime} completion={.status.completionTime}' 2>/dev/null || true`,
    "printf '\\n'",
    "printf 'pods\\n'",
    `kubectl get pod -n ${gitMirrorNamespace} -l job-name="$job" -o 'custom-columns=NAME:.metadata.name,READY:.status.containerStatuses[*].ready,STATUS:.status.phase,RESTARTS:.status.containerStatuses[*].restartCount,START:.status.startTime' --no-headers 2>/dev/null || true`,
    "printf 'logs\\n'",
    `kubectl logs -n ${gitMirrorNamespace} "job/$job" --tail=120 2>/dev/null || true`,
  ].join("\n");
}

function gitMirrorJobProbeSummary(stdout: string): Record<string, unknown> {
  const line = matchLine(stdout, "jobStatus=") ?? "";
  const succeeded = /(?:^|\s)succeeded=1(?:\s|$)/u.test(line);
  const failedRaw = firstMatch(line, /(?:^|\s)failed=([0-9]+)/u);
  const failed = failedRaw !== null && Number(failedRaw) > 0;
  const activeRaw = firstMatch(line, /(?:^|\s)active=([0-9]+)/u);
  return {
    statusLine: line,
    succeeded,
    failed,
    active: activeRaw === null ? null : Number(activeRaw),
  };
}

function gitMirrorJobManifest(action: "sync" | "flush", name: string): Record<string, unknown> {
  return {
    apiVersion: "batch/v1",
    kind: "Job",
    metadata: {
      name,
      namespace: gitMirrorNamespace,
      labels: {
        "app.kubernetes.io/name": "git-mirror",
        "app.kubernetes.io/part-of": "devops-infra",
        "app.kubernetes.io/component": action === "sync" ? "sync-controller" : "flush-controller",
        "agentrun.pikastech.local/trigger": "manual-cli",
      },
    },
    spec: {
      backoffLimit: 0,
      activeDeadlineSeconds: 300,
      ttlSecondsAfterFinished: 3600,
      template: {
        metadata: {
          labels: {
            "app.kubernetes.io/name": "git-mirror",
            "app.kubernetes.io/part-of": "devops-infra",
            "app.kubernetes.io/component": action === "sync" ? "sync-controller" : "flush-controller",
            "agentrun.pikastech.local/trigger": "manual-cli",
          },
        },
        spec: {
          restartPolicy: "Never",
          hostNetwork: true,
          dnsPolicy: "ClusterFirstWithHostNet",
          volumes: [
            { name: "cache", persistentVolumeClaim: { claimName: "git-mirror-cache" } },
            { name: "git-ssh", secret: { secretName: "git-mirror-github-ssh", defaultMode: 0o400 } },
          ],
          containers: [{
            name: action,
            image: mirrorToolsImage,
            imagePullPolicy: "IfNotPresent",
            command: ["/bin/sh", "-ec", action === "sync" ? gitMirrorSyncShellScript() : gitMirrorFlushShellScript()],
            volumeMounts: [
              { name: "cache", mountPath: "/cache" },
              { name: "git-ssh", mountPath: "/git-ssh", readOnly: true },
            ],
          }],
        },
      },
    },
  };
}

function gitMirrorSyncShellScript(): string {
  return [
    "set -eu",
    "started_at=$(date -u +%Y-%m-%dT%H:%M:%SZ)",
    "mkdir -p /cache/pikasTech",
    "export GIT_SSH_COMMAND='ssh -i /git-ssh/ssh-privatekey -o StrictHostKeyChecking=no -o UserKnownHostsFile=/tmp/agentrun-known-hosts'",
    `repo=${shQuote(gitMirrorRepoPath)}`,
    `remote=${shQuote(githubSshUrl)}`,
    "if [ ! -d \"$repo\" ]; then git clone --mirror \"$remote\" \"$repo\"; else git --git-dir=\"$repo\" remote set-url origin \"$remote\"; fi",
    "git --git-dir=\"$repo\" config uploadpack.allowReachableSHA1InWant true",
    "git --git-dir=\"$repo\" config http.receivepack true",
    "git --git-dir=\"$repo\" fetch origin +refs/heads/v0.1:refs/heads/v0.1 +refs/heads/v0.1:refs/mirror-stage/heads/v0.1",
    "if git --git-dir=\"$repo\" fetch origin +refs/heads/v0.1-gitops:refs/mirror-stage/heads/v0.1-gitops; then",
    "  if ! git --git-dir=\"$repo\" rev-parse --verify 'refs/heads/v0.1-gitops^{commit}' >/dev/null 2>&1; then",
    "    git --git-dir=\"$repo\" update-ref refs/heads/v0.1-gitops \"$(git --git-dir=\"$repo\" rev-parse --verify 'refs/mirror-stage/heads/v0.1-gitops^{commit}')\"",
    "  fi",
    "fi",
    "local_v01=$(git --git-dir=\"$repo\" rev-parse --verify 'refs/heads/v0.1^{commit}')",
    "github_v01=$(git --git-dir=\"$repo\" rev-parse --verify 'refs/mirror-stage/heads/v0.1^{commit}')",
    "local_gitops=$(git --git-dir=\"$repo\" rev-parse --verify 'refs/heads/v0.1-gitops^{commit}' 2>/dev/null || true)",
    "github_gitops=$(git --git-dir=\"$repo\" rev-parse --verify 'refs/mirror-stage/heads/v0.1-gitops^{commit}' 2>/dev/null || true)",
    "pending=false; if [ -n \"$local_gitops\" ] && { [ -z \"$github_gitops\" ] || [ \"$local_gitops\" != \"$github_gitops\" ]; }; then pending=true; fi",
    "json_ref() { if [ -n \"$1\" ]; then printf '\"%s\"' \"$1\"; else printf null; fi; }",
    "cat > /cache/agentrun.last-sync.json <<EOF",
    "{\"event\":\"git-mirror-sync\",\"repo\":\"pikasTech/agentrun\",\"status\":\"succeeded\",\"startedAt\":\"$started_at\",\"syncedAt\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"localV01\":\"$local_v01\",\"githubV01\":\"$github_v01\",\"localGitops\":$(json_ref \"$local_gitops\"),\"githubGitops\":$(json_ref \"$github_gitops\"),\"pendingFlush\":$pending}",
    "EOF",
    "cat /cache/agentrun.last-sync.json",
  ].join("\n");
}

function gitMirrorFlushShellScript(): string {
  return [
    "set -eu",
    "started_at=$(date -u +%Y-%m-%dT%H:%M:%SZ)",
    "export GIT_SSH_COMMAND='ssh -i /git-ssh/ssh-privatekey -o StrictHostKeyChecking=no -o UserKnownHostsFile=/tmp/agentrun-known-hosts'",
    `repo=${shQuote(gitMirrorRepoPath)}`,
    `remote=${shQuote(githubSshUrl)}`,
    "test -d \"$repo\"",
    "git --git-dir=\"$repo\" remote set-url origin \"$remote\"",
    "local_gitops=$(git --git-dir=\"$repo\" rev-parse --verify 'refs/heads/v0.1-gitops^{commit}' 2>/dev/null || true)",
    "if [ -n \"$local_gitops\" ]; then",
    "  git --git-dir=\"$repo\" -c remote.origin.mirror=false push origin refs/heads/v0.1-gitops:refs/heads/v0.1-gitops",
    "  git --git-dir=\"$repo\" fetch origin +refs/heads/v0.1-gitops:refs/mirror-stage/heads/v0.1-gitops",
    "fi",
    "github_gitops=$(git --git-dir=\"$repo\" rev-parse --verify 'refs/mirror-stage/heads/v0.1-gitops^{commit}' 2>/dev/null || true)",
    "pending=false; if [ -n \"$local_gitops\" ] && { [ -z \"$github_gitops\" ] || [ \"$local_gitops\" != \"$github_gitops\" ]; }; then pending=true; fi",
    "json_ref() { if [ -n \"$1\" ]; then printf '\"%s\"' \"$1\"; else printf null; fi; }",
    "cat > /cache/agentrun.last-flush.json <<EOF",
    "{\"event\":\"git-mirror-flush\",\"repo\":\"pikasTech/agentrun\",\"status\":\"succeeded\",\"startedAt\":\"$started_at\",\"flushedAt\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"localGitops\":$(json_ref \"$local_gitops\"),\"githubGitops\":$(json_ref \"$github_gitops\"),\"pendingFlush\":$pending}",
    "EOF",
    "cat /cache/agentrun.last-flush.json",
  ].join("\n");
}

function gitMirrorCacheProbeScript(): string {
  return [
    "printf 'lastSync='; cat /cache/agentrun.last-sync.json 2>/dev/null || true; printf '\\n'",
    "printf 'lastFlush='; cat /cache/agentrun.last-flush.json 2>/dev/null || true; printf '\\n'",
    `repo=${shQuote(gitMirrorRepoPath)}`,
    "rev() { git --git-dir=\"$repo\" rev-parse --verify \"$1^{commit}\" 2>/dev/null || true; }",
    "local_v01=$(rev refs/heads/v0.1)",
    "github_v01=$(rev refs/mirror-stage/heads/v0.1)",
    "local_gitops=$(rev refs/heads/v0.1-gitops)",
    "github_gitops=$(rev refs/mirror-stage/heads/v0.1-gitops)",
    "exact=false",
    "exact_commit=\"\"",
    "if [ -n \"$local_v01\" ]; then",
    "  tmp=$(mktemp -d)",
    "  if git init -q \"$tmp\" && git -C \"$tmp\" remote add origin http://127.0.0.1:8080/pikasTech/agentrun.git && git -C \"$tmp\" fetch --depth=1 origin \"$local_v01\" >/tmp/agentrun-exact-fetch.log 2>&1; then",
    "    exact_commit=$(git -C \"$tmp\" rev-parse FETCH_HEAD 2>/dev/null || true)",
    "    if [ \"$exact_commit\" = \"$local_v01\" ]; then exact=true; fi",
    "  fi",
    "  rm -rf \"$tmp\"",
    "fi",
    "node -e 'const [localV01,githubV01,localGitops,githubGitops,exact,exactCommit]=process.argv.slice(1); const n=v=>v&&v.length>0?v:null; const pending=Boolean(n(localGitops)&&(!n(githubGitops)||localGitops!==githubGitops)); console.log(\"refs=\"+JSON.stringify({refs:{localV01:n(localV01),githubV01:n(githubV01),localGitops:n(localGitops),githubGitops:n(githubGitops)},pendingFlush:pending,exactFetch:{localV01:exact===\"true\",commit:n(exactCommit)}}));' \"$local_v01\" \"$github_v01\" \"$local_gitops\" \"$github_gitops\" \"$exact\" \"$exact_commit\"",
  ].join("\n");
}

function gitMirrorStatusSummary(raw: string): Record<string, unknown> {
  const refs = labeledJson(raw, "refs");
  const lastSync = labeledJson(raw, "lastSync");
  const lastFlush = labeledJson(raw, "lastFlush");
  const refsRecord = record(record(refs).refs);
  const localV01 = stringOrNull(refsRecord.localV01);
  const githubV01 = stringOrNull(refsRecord.githubV01);
  const localGitops = stringOrNull(refsRecord.localGitops);
  const githubGitops = stringOrNull(refsRecord.githubGitops);
  const pendingFlush = typeof record(refs).pendingFlush === "boolean" ? Boolean(record(refs).pendingFlush) : null;
  return {
    localV01,
    githubV01,
    localGitops,
    githubGitops,
    pendingFlush,
    sourceInSync: Boolean(localV01 && githubV01 && localV01 === githubV01),
    gitopsInSync: Boolean(localGitops && githubGitops && localGitops === githubGitops),
    githubInSync: Boolean(localV01 && githubV01 && localV01 === githubV01 && (!localGitops || localGitops === githubGitops)),
    flushNeeded: pendingFlush === true,
    flushCommand: pendingFlush === true ? "bun scripts/cli.ts agentrun v01 git-mirror flush --confirm" : null,
    exactFetch: record(refs).exactFetch ?? null,
    lastSync,
    lastFlush,
  };
}

function gitMirrorSyncRequirement(sourceCommit: string, rawStatus: string): { required: boolean; reason: string; localV01: string | null } {
  const summary = gitMirrorStatusSummary(rawStatus);
  const localV01 = stringOrNull(summary.localV01);
  return {
    required: localV01 !== sourceCommit,
    reason: localV01 === sourceCommit ? "local-v01-current" : localV01 === null ? "local-v01-unresolved" : "local-v01-stale",
    localV01,
  };
}

function startAsyncAgentRunJob(name: string, command: string[], note: string): Record<string, unknown> {
  const job = startJob(name, command, note);
  const statusCommand = `bun scripts/cli.ts job status ${job.id} --tail-bytes 12000`;
  return {
    ok: true,
    mode: "async-job",
    job,
    statusCommand,
    tailCommand: `tail -f ${job.stdoutFile}`,
    next: {
      status: statusCommand,
      tail: `tail -f ${job.stdoutFile}`,
    },
  };
}

async function capture(config: UniDeskConfig, target: string, args: string[]): Promise<SshCaptureResult> {
  return await runSshCommandCapture(config, target, args);
}

function compactCapture(result: SshCaptureResult, options: { full?: boolean; stdoutTailChars?: number; stderrTailChars?: number } = {}): Record<string, unknown> {
  const stdoutTailChars = options.stdoutTailChars ?? 8000;
  const stderrTailChars = options.stderrTailChars ?? 4000;
  const full = options.full ?? true;
  const payload: Record<string, unknown> = {
    exitCode: result.exitCode,
    stdoutBytes: Buffer.byteLength(result.stdout, "utf8"),
    stderrBytes: Buffer.byteLength(result.stderr, "utf8"),
    stdoutTailOmitted: !full && result.exitCode === 0,
    stderrTailOmitted: !full && result.exitCode === 0,
  };
  if (full || result.exitCode !== 0) {
    payload.stdoutTail = tail(result.stdout, stdoutTailChars);
    payload.stderrTail = tail(result.stderr, stderrTailChars);
    payload.stdoutTruncated = result.stdout.length > stdoutTailChars;
    payload.stderrTruncated = result.stderr.length > stderrTailChars;
  }
  return payload;
}

async function timedStatusStage<T>(stage: string, action: () => Promise<T>): Promise<TimedValue<T>> {
  const startedAtMs = Date.now();
  progressEvent("agentrun.control-plane.status.progress", { stage, status: "started" });
  try {
    const value = await action();
    const exitCode = isCaptureResult(value) ? value.exitCode : typeof record(value).ok === "boolean" && record(value).ok !== true ? 1 : 0;
    progressEvent("agentrun.control-plane.status.progress", {
      stage,
      status: exitCode === 0 ? "succeeded" : "failed",
      exitCode,
      elapsedMs: Date.now() - startedAtMs,
    });
    return { value, elapsedMs: Date.now() - startedAtMs };
  } catch (error) {
    progressEvent("agentrun.control-plane.status.progress", {
      stage,
      status: "failed",
      elapsedMs: Date.now() - startedAtMs,
      error: error instanceof Error ? error.message : String(error),
    });
    throw error;
  }
}

function progressEvent(event: string, payload: Record<string, unknown>): void {
  process.stderr.write(`${JSON.stringify({ event, at: new Date().toISOString(), ...payload })}\n`);
}

function isCaptureResult(value: unknown): value is SshCaptureResult {
  return typeof value === "object" && value !== null && "exitCode" in value && typeof (value as { exitCode?: unknown }).exitCode === "number";
}

function pipelineRunName(sourceCommit: string): string {
  return `agentrun-v01-ci-${sourceCommit.slice(0, 12)}`;
}

function matchLine(text: string, prefix: string): string | null {
  const line = text.split(/\r?\n/u).find((item) => item.startsWith(prefix));
  return line ? line.slice(prefix.length).trim() || null : null;
}

function firstMatch(text: string, pattern: RegExp): string | null {
  return pattern.exec(text)?.[1] ?? null;
}

function labeledJson(text: string, label: string): Record<string, unknown> {
  const prefix = `${label}=`;
  const line = text.split(/\r?\n/u).find((item) => item.startsWith(prefix));
  if (!line) return {};
  try {
    return record(JSON.parse(line.slice(prefix.length)));
  } catch {
    return {};
  }
}

function record(value: unknown): Record<string, unknown> {
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value as Record<string, unknown> : {};
}

function stringOrNull(value: unknown): string | null {
  return typeof value === "string" && value.length > 0 ? value : null;
}

function parseArgoStatus(text: string): { revision: string | null; syncStatus: string | null; healthStatus: string | null } {
  const lines = text.split(/\r?\n/u);
  const index = lines.findIndex((line) => line.trim() === "argo");
  if (index < 0) return { revision: null, syncStatus: null, healthStatus: null };
  const [revision, syncStatus, healthStatus] = (lines[index + 1] ?? "").split("\t");
  return {
    revision: revision?.trim() || null,
    syncStatus: syncStatus?.trim() || null,
    healthStatus: healthStatus?.trim() || null,
  };
}

function parseManagerImage(text: string): { image: string | null; sourceCommit: string | null } {
  const lines = text.split(/\r?\n/u);
  const index = lines.findIndex((line) => line.trim() === "managerImage");
  if (index < 0) return { image: null, sourceCommit: null };
  const [image, sourceCommit] = (lines[index + 1] ?? "").split("\t");
  return {
    image: image?.trim() || null,
    sourceCommit: sourceCommit?.trim() || null,
  };
}

function isGitSha(value: string): boolean {
  return /^[0-9a-f]{40}$/u.test(value);
}

function tail(text: string, maxChars: number): string {
  return text.length > maxChars ? text.slice(-maxChars) : text;
}

function sleep(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

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

function unsupported(args: string[]): Record<string, unknown> {
  return {
    ok: false,
    command: `agentrun ${args.join(" ")}`.trim(),
    degradedReason: "unsupported-command",
    message: "supported commands: agentrun v01 control-plane status|trigger-current|refresh; agentrun v01 git-mirror status|sync|flush",
  };
}
