// SPEC: PJ2026-01060305 AgentRun execution policy + PJ2026-01020108 cancel lifecycle draft-2026-06-25-p0.
// Renders AgentRun YAML lane policy into runtime manager environment.
import { createHash } from "node:crypto";
import type { AgentRunLaneSpec } from "./agentrun-lanes";
import { gitRepositoryIdentity, resolveCicdDeliveryAuthority } from "./cicd-delivery-authority";
import { renderPacFeatureConfigSchemaStage } from "./pac-feature-config-schema-stage";
import { stableJsonSha256 } from "./stable-json";

export interface AgentRunArtifactService {
  readonly serviceId: string;
  readonly image: string;
  readonly digest: string;
  readonly repositoryDigest: string;
  readonly imageTag: string;
  readonly artifactKind: string;
  readonly status: string;
  readonly envIdentity: string;
  readonly envImage: string;
  readonly envDigest: string;
  readonly envRepositoryDigest: string;
  readonly bootCommit: string;
  readonly bootScript: string;
  readonly provenance: Record<string, unknown>;
}

export interface AgentRunArtifactCatalog {
  readonly lane: string;
  readonly sourceBranch: string;
  readonly gitopsBranch: string;
  readonly sourceCommitId: string;
  readonly summary: string;
  readonly services: readonly AgentRunArtifactService[];
}

export interface AgentRunGitopsRenderInput {
  readonly sourceCommit: string;
  readonly image: AgentRunArtifactService;
}

export interface AgentRunRenderedFile {
  readonly path: string;
  readonly content: string;
}

export function renderAgentRunControlPlaneManifests(spec: AgentRunLaneSpec): readonly Record<string, unknown>[] {
  return [
    { apiVersion: "v1", kind: "Namespace", metadata: { name: spec.ci.namespace } },
    {
      apiVersion: "v1",
      kind: "ServiceAccount",
      metadata: {
        name: spec.ci.serviceAccountName,
        namespace: spec.ci.namespace,
        labels: agentRunLabels(spec),
      },
    },
    {
      apiVersion: "rbac.authorization.k8s.io/v1",
      kind: "Role",
      metadata: {
        name: spec.ci.serviceAccountName,
        namespace: spec.ci.namespace,
        labels: agentRunLabels(spec),
      },
      rules: [
        { apiGroups: ["tekton.dev"], resources: ["pipelineruns", "taskruns"], verbs: ["get", "list", "watch", "create", "patch", "update"] },
        { apiGroups: [""], resources: ["pods", "pods/log", "secrets", "configmaps", "persistentvolumeclaims"], verbs: ["get", "list", "watch", "create", "patch", "update", "delete"] },
      ],
    },
    {
      apiVersion: "rbac.authorization.k8s.io/v1",
      kind: "RoleBinding",
      metadata: {
        name: spec.ci.serviceAccountName,
        namespace: spec.ci.namespace,
        labels: agentRunLabels(spec),
      },
      subjects: [{ kind: "ServiceAccount", name: spec.ci.serviceAccountName }],
      roleRef: { apiGroup: "rbac.authorization.k8s.io", kind: "Role", name: spec.ci.serviceAccountName },
    },
    renderAgentRunPipelineManifest(spec),
    agentRunArgoProjectManifest(spec),
    agentRunArgoApplicationManifest(spec),
  ];
}

export function renderAgentRunGitopsFiles(spec: AgentRunLaneSpec, input: AgentRunGitopsRenderInput): readonly AgentRunRenderedFile[] {
  const catalog = agentRunArtifactCatalog(spec, input.sourceCommit, input.image);
  const source = {
    lane: spec.version,
    sourceCommit: input.sourceCommit,
    generatedBy: "unidesk config/agentrun.yaml",
    configSource: "config/agentrun.yaml",
  };
  return [
    { path: "source.json", content: `${JSON.stringify(source, null, 2)}\n` },
    { path: spec.deployment.artifactCatalogPath, content: `${JSON.stringify(catalog, null, 2)}\n` },
    { path: `${spec.deployment.gitopsRoot}/argocd/project.yaml`, content: yaml(agentRunArgoProjectManifest(spec)) },
    { path: `${spec.deployment.gitopsRoot}/argocd/${spec.deployment.argocd.applicationFile}`, content: yaml(agentRunArgoApplicationManifest(spec)) },
    { path: `${spec.deployment.gitopsRoot}/${spec.deployment.runtimeRenderDir}/kustomization.yaml`, content: yaml(agentRunKustomizationManifest(spec)) },
    { path: `${spec.deployment.gitopsRoot}/${spec.deployment.runtimeRenderDir}/namespace.yaml`, content: yaml(agentRunRuntimeNamespaceManifest(spec)) },
    ...(spec.deployment.localPostgres.enabled ? [{ path: `${spec.deployment.gitopsRoot}/${spec.deployment.runtimeRenderDir}/postgres.yaml`, content: yaml(agentRunPostgresManifest(spec)) }] : []),
    { path: `${spec.deployment.gitopsRoot}/${spec.deployment.runtimeRenderDir}/mgr.yaml`, content: yamlAll(agentRunManagerManifests(spec, input.sourceCommit, input.image)) },
    { path: `${spec.deployment.gitopsRoot}/${spec.deployment.runtimeRenderDir}/runner-rbac.yaml`, content: yamlAll(agentRunRunnerRbacManifests(spec)) },
  ];
}

export function placeholderAgentRunImage(spec: AgentRunLaneSpec, sourceCommit: string): AgentRunArtifactService {
  const digest = `sha256:${"0".repeat(64)}`;
  const image = `${spec.ci.registryPrefix}/agentrun-mgr-env:${sourceCommit}`;
  return {
    serviceId: "agentrun-mgr",
    artifactKind: "env-reuse",
    status: "placeholder",
    image,
    digest,
    repositoryDigest: `${spec.ci.registryPrefix}/agentrun-mgr-env@${digest}`,
    imageTag: sourceCommit,
    envIdentity: sourceCommit,
    envImage: image,
    envDigest: digest,
    envRepositoryDigest: `${spec.ci.registryPrefix}/agentrun-mgr-env@${digest}`,
    bootCommit: sourceCommit,
    bootScript: "deploy/runtime/boot/agentrun-boot.sh",
    provenance: {
      sourceCommitId: sourceCommit,
      source: "placeholder",
      valuesPrinted: false,
    },
  };
}

export function agentRunImageArtifact(spec: AgentRunLaneSpec, input: {
  sourceCommit: string;
  envIdentity: string;
  digest: string;
  status: string;
}): AgentRunArtifactService {
  const image = `${spec.ci.registryPrefix}/${spec.deployment.manager.imageBuild.repository}:${input.envIdentity}`;
  return {
    serviceId: "agentrun-mgr",
    artifactKind: "env-reuse",
    status: input.status,
    image,
    digest: input.digest,
    repositoryDigest: `${spec.ci.registryPrefix}/${spec.deployment.manager.imageBuild.repository}@${input.digest}`,
    imageTag: input.envIdentity,
    envIdentity: input.envIdentity,
    envImage: image,
    envDigest: input.digest,
    envRepositoryDigest: `${spec.ci.registryPrefix}/${spec.deployment.manager.imageBuild.repository}@${input.digest}`,
    bootCommit: input.sourceCommit,
    bootScript: "deploy/runtime/boot/agentrun-boot.sh",
    provenance: {
      sourceCommitId: input.sourceCommit,
      source: "unidesk-yaml-only",
      configSource: "config/agentrun.yaml",
      valuesPrinted: false,
    },
  };
}

export function renderedFilesDigest(files: readonly AgentRunRenderedFile[]): string {
  const hash = createHash("sha256");
  for (const file of [...files].sort((left, right) => left.path.localeCompare(right.path))) {
    hash.update(file.path);
    hash.update("\0");
    hash.update(file.content);
    hash.update("\0");
  }
  return `sha256:${hash.digest("hex")}`;
}

export function renderedObjectsDigest(objects: readonly Record<string, unknown>[]): string {
  return `sha256:${createHash("sha256").update(yamlAll(objects)).digest("hex")}`;
}

export function renderAgentRunPipelineManifest(spec: AgentRunLaneSpec): Record<string, unknown> {
  const build = spec.deployment.manager.imageBuild;
  if (spec.ci.buildkitImage === null) throw new Error(`config/agentrun.yaml controlPlane.lanes.${spec.lane}.ci.buildkitImage is required for AgentRun Tekton image build`);
  return {
    apiVersion: "tekton.dev/v1",
    kind: "Pipeline",
    metadata: {
      name: spec.ci.pipeline,
      namespace: spec.ci.namespace,
      labels: agentRunLabels(spec),
      annotations: {
        "unidesk.ai/owning-config-ref": `config/agentrun.yaml#controlPlane.lanes.${spec.lane}`,
        "unidesk.ai/effective-config-sha256": stableJsonSha256(spec),
        "unidesk.ai/source-artifact-renderer": "agentrun-control-plane",
        "unidesk.ai/source-artifact-mode": "embedded-pipeline-spec",
      },
    },
    spec: {
      params: [
        { name: "git-url", type: "string", default: spec.source.remote },
        { name: "git-read-url", type: "string", default: spec.gitMirror.readUrl },
        { name: "git-write-url", type: "string", default: spec.gitMirror.writeUrl },
        { name: "source-branch", type: "string", default: spec.source.branch },
        { name: "gitops-branch", type: "string", default: spec.gitops.branch },
        { name: "revision", type: "string" },
        { name: "source-stage-ref", type: "string" },
        { name: "registry-prefix", type: "string", default: spec.ci.registryPrefix },
        { name: "tools-image", type: "string", default: spec.ci.toolsImage },
        { name: "buildkit-image", type: "string", default: spec.ci.buildkitImage },
        { name: "containerfile", type: "string", default: build.containerfile },
        { name: "context-dir", type: "string", default: build.context },
        { name: "image-repository", type: "string", default: `${spec.ci.registryPrefix}/${build.repository}` },
        { name: "build-network", type: "string", default: build.network },
        { name: "build-args-json", type: "string", default: JSON.stringify(Object.entries(build.buildArgs).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => `${key}=${value}`)) },
        { name: "build-http-proxy", type: "string", default: build.httpProxy ?? "" },
        { name: "build-https-proxy", type: "string", default: build.httpsProxy ?? "" },
        { name: "build-no-proxy", type: "string", default: build.noProxy.join(",") },
        { name: "container-http-proxy", type: "string", default: build.buildContainerProxy.httpProxy ?? "" },
        { name: "container-https-proxy", type: "string", default: build.buildContainerProxy.httpsProxy ?? "" },
        { name: "container-no-proxy", type: "string", default: build.buildContainerProxy.noProxy.join(",") },
        { name: "env-identity-files-json", type: "string", default: JSON.stringify(build.envIdentityFiles) },
        { name: "gitops-root", type: "string", default: spec.deployment.gitopsRoot },
        { name: "artifact-catalog", type: "string", default: spec.deployment.artifactCatalogPath },
      ],
      workspaces: [{ name: "source" }],
      tasks: agentRunBuildPublishTasks(spec),
    },
  };
}

function agentRunBuildPublishTasks(spec: AgentRunLaneSpec): readonly Record<string, unknown>[] {
  const params = [
      { name: "git-read-url", value: "$(params.git-read-url)" },
      { name: "git-write-url", value: "$(params.git-write-url)" },
      { name: "source-branch", value: "$(params.source-branch)" },
      { name: "gitops-branch", value: "$(params.gitops-branch)" },
      { name: "revision", value: "$(params.revision)" },
      { name: "source-stage-ref", value: "$(params.source-stage-ref)" },
      { name: "registry-prefix", value: "$(params.registry-prefix)" },
      { name: "tools-image", value: "$(params.tools-image)" },
      { name: "buildkit-image", value: "$(params.buildkit-image)" },
      { name: "containerfile", value: "$(params.containerfile)" },
      { name: "context-dir", value: "$(params.context-dir)" },
      { name: "image-repository", value: "$(params.image-repository)" },
      { name: "build-network", value: "$(params.build-network)" },
      { name: "build-args-json", value: "$(params.build-args-json)" },
      { name: "build-http-proxy", value: "$(params.build-http-proxy)" },
      { name: "build-https-proxy", value: "$(params.build-https-proxy)" },
      { name: "build-no-proxy", value: "$(params.build-no-proxy)" },
      { name: "container-http-proxy", value: "$(params.container-http-proxy)" },
      { name: "container-https-proxy", value: "$(params.container-https-proxy)" },
      { name: "container-no-proxy", value: "$(params.container-no-proxy)" },
      { name: "env-identity-files-json", value: "$(params.env-identity-files-json)" },
      { name: "gitops-root", value: "$(params.gitops-root)" },
      { name: "artifact-catalog", value: "$(params.artifact-catalog)" },
  ];
  const taskParams = params.map(({ name }) => ({ name }));
  const task = (name: string, steps: readonly Record<string, unknown>[], runAfter: readonly string[] = []): Record<string, unknown> => ({
    name,
    ...(runAfter.length === 0 ? {} : { runAfter }),
    workspaces: [{ name: "source", workspace: "source" }],
    taskSpec: { params: taskParams, workspaces: [{ name: "source" }], steps },
    params,
    when: [{ input: spec.deployment.format, operator: "in", values: ["unidesk-yaml-only"] }],
  });
  return [
    task("plan-artifacts", [
      { name: "source-checkout", image: "$(params.tools-image)", script: agentRunTektonSourceCheckoutScript() },
      { name: "probe-env-image", image: "$(params.tools-image)", script: agentRunTektonProbeImageScript() },
    ]),
    task("collect-artifacts", [{
      name: "build-env-image",
      image: "$(params.buildkit-image)",
      env: [
        { name: "BUILDKITD_FLAGS", value: "--oci-worker-no-process-sandbox --oci-worker-net=host --allow-insecure-entitlement network.host" },
        { name: "HTTP_PROXY", value: "$(params.build-http-proxy)" },
        { name: "http_proxy", value: "$(params.build-http-proxy)" },
        { name: "HTTPS_PROXY", value: "$(params.build-https-proxy)" },
        { name: "https_proxy", value: "$(params.build-https-proxy)" },
        { name: "ALL_PROXY", value: "$(params.build-https-proxy)" },
        { name: "all_proxy", value: "$(params.build-https-proxy)" },
        { name: "NO_PROXY", value: "$(params.build-no-proxy)" },
        { name: "no_proxy", value: "$(params.build-no-proxy)" },
      ],
      securityContext: { privileged: true, runAsUser: 1000, runAsGroup: 1000 },
      script: agentRunTektonBuildImageScript(),
    }], ["plan-artifacts"]),
    task("gitops-promote", [{
      name: "publish-gitops",
      image: "$(params.tools-image)",
      env: [{ name: "GITEA_TOKEN", valueFrom: { secretKeyRef: { name: agentRunPacGiteaSecretName(spec), key: "token", optional: true } } }],
      script: agentRunTektonGitopsPublishScript(spec),
    }], ["collect-artifacts"]),
  ];
}

function agentRunTektonSourceCheckoutScript(): string {
  return [
    "#!/bin/sh",
    "set -eu",
    "root=\"$(workspaces.source.path)\"",
    "rm -rf \"$root/repo\"",
    "git clone --no-checkout \"$(params.git-read-url)\" \"$root/repo\"",
    "cd \"$root/repo\"",
    "git fetch origin \"+$(params.source-stage-ref):refs/remotes/origin/unidesk-source-snapshot\"",
    "git checkout --detach \"$(params.revision)\"",
    "actual=$(git rev-parse HEAD)",
    "test \"$actual\" = \"$(params.revision)\"",
    "ENV_IDENTITY_FILES='$(params.env-identity-files-json)' BUILD_ARGS_JSON='$(params.build-args-json)' CONTAINER_HTTP_PROXY='$(params.container-http-proxy)' CONTAINER_HTTPS_PROXY='$(params.container-https-proxy)' CONTAINER_NO_PROXY='$(params.container-no-proxy)' node <<'NODE' > \"$root/env-identity\"",
    "const { createHash } = require('node:crypto');",
    "const { existsSync, lstatSync, readdirSync, readFileSync } = require('node:fs');",
    "const { join } = require('node:path');",
    "const files = JSON.parse(process.env.ENV_IDENTITY_FILES || '[]');",
    "const buildArgs = JSON.parse(process.env.BUILD_ARGS_JSON || '[]');",
    "const proxy = [`HTTP_PROXY=${process.env.CONTAINER_HTTP_PROXY || ''}`, `HTTPS_PROXY=${process.env.CONTAINER_HTTPS_PROXY || ''}`, `NO_PROXY=${process.env.CONTAINER_NO_PROXY || ''}`];",
    "const skip = new Set(['.git', '.worktree', '.state', 'node_modules', 'coverage', 'tmp', '.tmp']);",
    "const hash = createHash('sha256');",
    "function collect(input) {",
    "  if (!existsSync(input)) return [{ path: input, missing: true }];",
    "  const stat = lstatSync(input);",
    "  if (stat.isFile()) return [{ path: input, missing: false }];",
    "  if (!stat.isDirectory()) return [{ path: input, missing: true }];",
    "  const out = [];",
    "  const stack = [input];",
    "  while (stack.length) {",
    "    const dir = stack.pop();",
    "    for (const entry of readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {",
    "      if (entry.isDirectory() && skip.has(entry.name)) continue;",
    "      const child = join(dir, entry.name);",
    "      if (entry.isDirectory()) stack.push(child);",
    "      else if (entry.isFile()) out.push({ path: child, missing: false });",
    "    }",
    "  }",
    "  return out.sort((a, b) => a.path.localeCompare(b.path));",
    "}",
    "for (const item of buildArgs) { hash.update('build-arg\\0'); hash.update(item); hash.update('\\0'); }",
    "for (const item of proxy) { hash.update('build-container-proxy\\0'); hash.update(item); hash.update('\\0'); }",
    "for (const file of files) for (const entry of collect(file)) { hash.update(entry.path); hash.update('\\0'); if (!entry.missing) hash.update(readFileSync(entry.path)); hash.update('\\0'); }",
    "process.stdout.write(hash.digest('hex').slice(0, 24));",
    "NODE",
    "BUILD_ARGS='$(params.build-args-json)' node <<'NODE' > \"$root/build-args.txt\"",
    "const values = JSON.parse(process.env.BUILD_ARGS || '[]');",
    "for (const value of values) console.log(`build-arg:${value}`);",
    "NODE",
    "chmod -R a+rwX \"$root\"",
    "env_identity=$(cat \"$root/env-identity\")",
    "printf '{\"ok\":true,\"phase\":\"source-checkout\",\"sourceCommit\":\"%s\",\"sourceStageRef\":\"%s\",\"envIdentity\":\"%s\",\"valuesPrinted\":false}\\n' \"$(params.revision)\" \"$(params.source-stage-ref)\" \"$env_identity\"",
  ].join("\n");
}

function agentRunTektonProbeImageScript(): string {
  return [
    "#!/bin/sh",
    "set -eu",
    "root=\"$(workspaces.source.path)\"",
    "env_identity=$(cat \"$root/env-identity\")",
    "image_repository='$(params.image-repository)'",
    "manifest_accept='application/vnd.oci.image.index.v1+json, application/vnd.oci.image.manifest.v1+json, application/vnd.docker.distribution.manifest.v2+json'",
    "repo_path=${image_repository#127.0.0.1:5000/}",
    "headers=$(mktemp)",
    "digest=''",
    "if curl -fsSI -H \"Accept: $manifest_accept\" \"http://127.0.0.1:5000/v2/$repo_path/manifests/$env_identity\" >\"$headers\"; then",
    "  digest=$(awk -F': ' 'tolower($1)==\"docker-content-digest\"{print $2}' \"$headers\" | tr -d '\\r' | head -n 1)",
    "fi",
    "rm -f \"$headers\"",
    "if [ -n \"$digest\" ]; then",
    "  image=\"$image_repository:$env_identity\"",
    "  printf '{\"ok\":true,\"status\":\"reused\",\"sourceCommit\":\"%s\",\"envIdentity\":\"%s\",\"image\":\"%s\",\"digest\":\"%s\",\"repositoryDigest\":\"%s@%s\",\"valuesPrinted\":false}\\n' \"$(params.revision)\" \"$env_identity\" \"$image\" \"$digest\" \"$image_repository\" \"$digest\" > \"$root/build-result.json\"",
    "  touch \"$root/skip-build\"",
    "else",
    "  printf '{\"ok\":false,\"status\":\"cache-miss\",\"sourceCommit\":\"%s\",\"envIdentity\":\"%s\",\"valuesPrinted\":false}\\n' \"$(params.revision)\" \"$env_identity\" > \"$root/build-result.json\"",
    "fi",
    "if [ -f \"$root/skip-build\" ]; then build_services='[]'; reused_services='[\"agentrun-mgr\"]'; else build_services='[\"agentrun-mgr\"]'; reused_services='[]'; fi",
    "printf '{\"event\":\"pac-delivery-plan\",\"schemaVersion\":\"v1\",\"sourceCommitId\":\"%s\",\"affectedServices\":[\"agentrun-mgr\"],\"rolloutServices\":[\"agentrun-mgr\"],\"buildServices\":%s,\"reusedServices\":%s,\"valuesPrinted\":false}\\n' \"$(params.revision)\" \"$build_services\" \"$reused_services\"",
    "chmod a+rw \"$root/build-result.json\"",
    "cat \"$root/build-result.json\"",
  ].join("\n");
}

function agentRunTektonBuildImageScript(): string {
  return [
    "#!/bin/sh",
    "set -eu",
    "root=\"$(workspaces.source.path)\"",
    "if [ -f \"$root/skip-build\" ]; then cat \"$root/build-result.json\"; exit 0; fi",
    "env_identity=$(cat \"$root/env-identity\")",
    "image_repository='$(params.image-repository)'",
    "image=\"$image_repository:$env_identity\"",
    "context_dir='$(params.context-dir)'",
    "if [ \"$context_dir\" = \".\" ]; then context_path=\"$root/repo\"; else context_path=\"$root/repo/${context_dir#./}\"; fi",
    "args=\"build --allow network.host --frontend dockerfile.v0 --local context=$context_path --local dockerfile=$root/repo --opt filename=$(params.containerfile) --opt network=$(params.build-network)\"",
    "add_opt() { args=\"$args --opt $1\"; }",
    "if [ -n '$(params.container-http-proxy)' ]; then add_opt 'build-arg:HTTP_PROXY=$(params.container-http-proxy)'; add_opt 'build-arg:http_proxy=$(params.container-http-proxy)'; fi",
    "if [ -n '$(params.container-https-proxy)' ]; then add_opt 'build-arg:HTTPS_PROXY=$(params.container-https-proxy)'; add_opt 'build-arg:https_proxy=$(params.container-https-proxy)'; fi",
    "if [ -n '$(params.container-https-proxy)' ]; then add_opt 'build-arg:ALL_PROXY=$(params.container-https-proxy)'; add_opt 'build-arg:all_proxy=$(params.container-https-proxy)'; elif [ -n '$(params.container-http-proxy)' ]; then add_opt 'build-arg:ALL_PROXY=$(params.container-http-proxy)'; add_opt 'build-arg:all_proxy=$(params.container-http-proxy)'; fi",
    "if [ -n '$(params.container-no-proxy)' ]; then add_opt 'build-arg:NO_PROXY=$(params.container-no-proxy)'; add_opt 'build-arg:no_proxy=$(params.container-no-proxy)'; fi",
    "while IFS= read -r opt; do [ -n \"$opt\" ] && add_opt \"$opt\"; done < \"$root/build-args.txt\"",
    "args=\"$args --metadata-file $root/build-metadata.json --output type=image,name=$image,push=true,registry.insecure=true\"",
    "buildctl-daemonless.sh $args",
    "metadata_compact=$(tr -d '\\n' < \"$root/build-metadata.json\")",
    "digest=$(printf '%s' \"$metadata_compact\" | sed -n 's/.*\"containerimage.digest\"[[:space:]]*:[[:space:]]*\"\\([^\"]*\\)\".*/\\1/p' | head -n 1)",
    "test -n \"$digest\"",
    "printf '{\"ok\":true,\"status\":\"built\",\"sourceCommit\":\"%s\",\"envIdentity\":\"%s\",\"image\":\"%s\",\"digest\":\"%s\",\"repositoryDigest\":\"%s@%s\",\"valuesPrinted\":false}\\n' \"$(params.revision)\" \"$env_identity\" \"$image\" \"$digest\" \"$image_repository\" \"$digest\" > \"$root/build-result.json\"",
    "cat \"$root/build-result.json\"",
  ].join("\n");
}

function agentRunTektonGitopsPublishScript(spec: AgentRunLaneSpec): string {
  const sourcePlaceholder = "__AGENTRUN_SOURCE_COMMIT__";
  const envPlaceholder = "__AGENTRUN_ENV_IDENTITY__";
  const digestPlaceholder = "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
  const statusPlaceholder = "__AGENTRUN_IMAGE_STATUS__";
  const templateImage = agentRunImageArtifact(spec, { sourceCommit: sourcePlaceholder, envIdentity: envPlaceholder, digest: digestPlaceholder, status: statusPlaceholder });
  const templateFiles = renderAgentRunGitopsFiles(spec, { sourceCommit: sourcePlaceholder, image: templateImage });
  const templateB64 = Buffer.from(JSON.stringify(templateFiles), "utf8").toString("base64");
  const authority = resolveCicdDeliveryAuthority({
    node: spec.nodeId,
    lane: spec.lane,
    sourceRepository: gitRepositoryIdentity(spec.source.repository),
    sourceBranch: spec.source.branch,
  });
  if (authority.kind !== "pac-pr-merge") throw new Error(`AgentRun ${spec.nodeId}/${spec.lane} requires exact PaC consumer authority for feature config validation`);
  const featureConfigSchemaStage = renderPacFeatureConfigSchemaStage({
    repositoryId: authority.consumer.repositoryRef,
    consumer: authority.consumer.consumerId,
    repoDirExpression: '"$root"',
    renderedRootExpression: '"$PWD/$(params.gitops-root)"',
  });
  return [
    "#!/bin/sh",
    "set -eu",
    "root=\"$(workspaces.source.path)\"",
    "build_result=\"$root/build-result.json\"",
    "test -s \"$build_result\"",
    `templates_b64=${JSON.stringify(templateB64)}`,
    "git_write_url='$(params.git-write-url)'",
    "git_auth_url=\"$git_write_url\"",
    "if printf '%s' \"$git_write_url\" | grep -q '^http://gitea-http\\.'; then",
    "  test -n \"${GITEA_TOKEN:-}\"",
    "  git_auth_url=$(printf '%s' \"$git_write_url\" | sed \"s#^http://#http://x-access-token:${GITEA_TOKEN}@#\")",
    "fi",
    "rm -rf \"$root/gitops\"",
    "git clone \"$git_auth_url\" \"$root/gitops\"",
    "cd \"$root/gitops\"",
    "git fetch origin \"$(params.gitops-branch)\" || true",
    "if git rev-parse --verify \"refs/remotes/origin/$(params.gitops-branch)^{commit}\" >/dev/null 2>&1; then git checkout -B \"$(params.gitops-branch)\" \"refs/remotes/origin/$(params.gitops-branch)\"; else git checkout --orphan \"$(params.gitops-branch)\"; git rm -rf . >/dev/null 2>&1 || true; fi",
    "incoming_source_commit='$(params.revision)'",
    "source_branch='$(params.source-branch)'",
    "branch_source_commit=$(git -C \"$root/repo\" rev-parse --verify \"refs/remotes/origin/${source_branch}^{commit}\")",
    "gitops_source_commit=$(node -e 'try { const value = JSON.parse(require(\"node:fs\").readFileSync(\"source.json\", \"utf8\")).sourceCommit; if (typeof value === \"string\") process.stdout.write(value); } catch {}')",
    "stale_reason=''",
    "if [ \"$incoming_source_commit\" != \"$branch_source_commit\" ]; then stale_reason='stale-source-revision'; fi",
    "if [ -z \"$stale_reason\" ] && [ -n \"$gitops_source_commit\" ] && [ \"$incoming_source_commit\" != \"$gitops_source_commit\" ]; then",
    "  if ! git -C \"$root/repo\" cat-file -e \"${gitops_source_commit}^{commit}\" 2>/dev/null; then stale_reason='gitops-source-order-unverifiable';",
    "  elif git -C \"$root/repo\" merge-base --is-ancestor \"$incoming_source_commit\" \"$gitops_source_commit\"; then stale_reason='stale-gitops-source-revision';",
    "  elif ! git -C \"$root/repo\" merge-base --is-ancestor \"$gitops_source_commit\" \"$incoming_source_commit\"; then stale_reason='divergent-gitops-source-revision'; fi",
    "fi",
    "if [ -n \"$stale_reason\" ]; then",
    "  gitops_commit=$(git rev-parse HEAD)",
    "  INCOMING_SOURCE_COMMIT=\"$incoming_source_commit\" CURRENT_SOURCE_COMMIT=\"$branch_source_commit\" GITOPS_SOURCE_COMMIT=\"$gitops_source_commit\" GITOPS_COMMIT=\"$gitops_commit\" STALE_REASON=\"$stale_reason\" node <<'NODE'",
    "console.log(JSON.stringify({ ok: true, status: 'succeeded', phase: 'gitops-publish', reason: process.env.STALE_REASON, warning: true, blocking: false, changed: false, stale: true, gitopsCommit: process.env.GITOPS_COMMIT, sourceCommit: process.env.INCOMING_SOURCE_COMMIT, currentSourceCommit: process.env.CURRENT_SOURCE_COMMIT, gitopsSourceCommit: process.env.GITOPS_SOURCE_COMMIT || null, valuesPrinted: false }));",
    "NODE",
    "  exit 0",
    "fi",
    "git rm -rf --ignore-unmatch \"$(params.gitops-root)\" \"$(params.artifact-catalog)\" source.json >/dev/null 2>&1 || true",
    "rm -rf \"$(params.gitops-root)\" \"$(params.artifact-catalog)\" source.json",
    "TEMPLATES_B64=\"$templates_b64\" BUILD_RESULT=\"$build_result\" node <<'NODE'",
    "const { mkdirSync, readFileSync, writeFileSync } = require('node:fs');",
    "const { dirname } = require('node:path');",
    "const templates = JSON.parse(Buffer.from(process.env.TEMPLATES_B64, 'base64').toString('utf8'));",
    "const build = JSON.parse(readFileSync(process.env.BUILD_RESULT, 'utf8'));",
    "const replacements = new Map([",
    "  ['__AGENTRUN_SOURCE_COMMIT__', build.sourceCommit],",
    "  ['__AGENTRUN_ENV_IDENTITY__', build.envIdentity],",
    "  ['sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', build.digest],",
    "  ['__AGENTRUN_IMAGE_STATUS__', build.status],",
    "]);",
    "for (const file of templates) {",
    "  let content = file.content;",
    "  for (const [from, to] of replacements) content = content.split(from).join(to);",
    "  mkdirSync(dirname(file.path), { recursive: true });",
    "  writeFileSync(file.path, content);",
    "}",
    "NODE",
    featureConfigSchemaStage,
    "git add source.json \"$(params.artifact-catalog)\" \"$(params.gitops-root)\"",
    "if git diff --quiet --cached; then changed=false; else changed=true; git -c user.email=agentrun@unidesk.local -c user.name='UniDesk AgentRun PaC' commit -m \"deploy: render AgentRun $(params.gitops-branch) from PaC\"; fi",
    "git remote set-url origin \"$git_auth_url\"",
    "git push -u origin \"$(params.gitops-branch)\"",
    "gitops_commit=$(git rev-parse HEAD)",
    "BUILD_RESULT=\"$build_result\" CHANGED=\"$changed\" GITOPS_COMMIT=\"$gitops_commit\" node <<'NODE'",
    "const { readFileSync } = require('node:fs');",
    "const build = JSON.parse(readFileSync(process.env.BUILD_RESULT, 'utf8'));",
    "console.log(JSON.stringify({ ok: true, status: 'succeeded', phase: 'gitops-publish', changed: process.env.CHANGED === 'true', gitopsCommit: process.env.GITOPS_COMMIT, sourceCommit: build.sourceCommit, envIdentity: build.envIdentity, imageStatus: build.status, digest: build.digest, valuesPrinted: false }));",
    "NODE",
  ].join("\n");
}

function agentRunArgoProjectManifest(spec: AgentRunLaneSpec): Record<string, unknown> {
  return {
    apiVersion: "argoproj.io/v1alpha1",
    kind: "AppProject",
    metadata: {
      name: spec.deployment.argocd.project,
      namespace: spec.gitops.argoNamespace,
      labels: agentRunLabels(spec),
    },
    spec: {
      description: `AgentRun ${spec.version} GitOps lane`,
      sourceRepos: [spec.gitops.repoURL, spec.source.remote],
      destinations: [{ server: "https://kubernetes.default.svc", namespace: spec.runtime.namespace }],
      clusterResourceWhitelist: [{ group: "", kind: "Namespace" }],
      namespaceResourceWhitelist: [{ group: "*", kind: "*" }],
    },
  };
}

function agentRunArgoApplicationManifest(spec: AgentRunLaneSpec): Record<string, unknown> {
  return {
    apiVersion: "argoproj.io/v1alpha1",
    kind: "Application",
    metadata: {
      name: spec.gitops.argoApplication,
      namespace: spec.gitops.argoNamespace,
      labels: agentRunLabels(spec),
    },
    spec: {
      project: spec.deployment.argocd.project,
      source: {
        repoURL: spec.gitops.repoURL,
        targetRevision: spec.gitops.branch,
        path: spec.gitops.path,
      },
      destination: {
        server: "https://kubernetes.default.svc",
        namespace: spec.runtime.namespace,
      },
      syncPolicy: {
        automated: { prune: false, selfHeal: true },
        syncOptions: ["CreateNamespace=true", "ApplyOutOfSyncOnly=true"],
      },
    },
  };
}

function agentRunKustomizationManifest(spec: AgentRunLaneSpec): Record<string, unknown> {
  return {
    apiVersion: "kustomize.config.k8s.io/v1beta1",
    kind: "Kustomization",
    resources: [
      "namespace.yaml",
      ...(spec.deployment.localPostgres.enabled ? ["postgres.yaml"] : []),
      "mgr.yaml",
      "runner-rbac.yaml",
    ],
  };
}

function agentRunRuntimeNamespaceManifest(spec: AgentRunLaneSpec): Record<string, unknown> {
  return {
    apiVersion: "v1",
    kind: "Namespace",
    metadata: {
      name: spec.runtime.namespace,
      labels: agentRunLabels(spec),
    },
  };
}

function agentRunPostgresManifest(spec: AgentRunLaneSpec): Record<string, unknown> {
  const localPostgres = spec.deployment.localPostgres;
  if (!localPostgres.enabled || localPostgres.serviceName === null || localPostgres.image === null || localPostgres.storage === null || localPostgres.port === null || localPostgres.database === null || localPostgres.user === null) {
    throw new Error(`localPostgres is enabled for ${spec.version} without renderable YAML fields`);
  }
  const name = localPostgres.serviceName;
  const secretName = spec.database.secretRef.name;
  return {
    apiVersion: "v1",
    kind: "List",
    items: [
      {
        apiVersion: "v1",
        kind: "Service",
        metadata: { name, namespace: spec.runtime.namespace, labels: agentRunLabels(spec) },
        spec: { selector: { "app.kubernetes.io/name": name }, ports: [{ name: "postgres", port: localPostgres.port, targetPort: "postgres" }] },
      },
      {
        apiVersion: "apps/v1",
        kind: "StatefulSet",
        metadata: { name, namespace: spec.runtime.namespace, labels: agentRunLabels(spec) },
        spec: {
          serviceName: name,
          replicas: 1,
          selector: { matchLabels: { "app.kubernetes.io/name": name } },
          template: {
            metadata: { labels: { ...agentRunLabels(spec), "app.kubernetes.io/name": name } },
            spec: {
              containers: [
                {
                  name: "postgres",
                  image: localPostgres.image,
                  ports: [{ name: "postgres", containerPort: localPostgres.port }],
                  env: [
                    { name: "POSTGRES_DB", valueFrom: { secretKeyRef: { name: secretName, key: "POSTGRES_DB" } } },
                    { name: "POSTGRES_USER", valueFrom: { secretKeyRef: { name: secretName, key: "POSTGRES_USER" } } },
                    { name: "POSTGRES_PASSWORD", valueFrom: { secretKeyRef: { name: secretName, key: "POSTGRES_PASSWORD" } } },
                    { name: "PGDATA", value: "/var/lib/postgresql/data/pgdata" },
                  ],
                  volumeMounts: [{ name: "data", mountPath: "/var/lib/postgresql/data" }],
                },
              ],
            },
          },
          volumeClaimTemplates: [
            {
              metadata: { name: "data" },
              spec: { accessModes: ["ReadWriteOnce"], resources: { requests: { storage: localPostgres.storage } } },
            },
          ],
        },
      },
    ],
  };
}

function agentRunManagerManifests(spec: AgentRunLaneSpec, sourceCommit: string, image: AgentRunArtifactService): readonly Record<string, unknown>[] {
  const imageRef = image.envRepositoryDigest || image.repositoryDigest;
  return [
    { apiVersion: "v1", kind: "ServiceAccount", metadata: { name: spec.deployment.manager.serviceAccount, namespace: spec.runtime.namespace, labels: agentRunLabels(spec) } },
    {
      apiVersion: "v1",
      kind: "Service",
      metadata: { name: spec.runtime.managerService, namespace: spec.runtime.namespace, labels: agentRunLabels(spec) },
      spec: {
        selector: { "app.kubernetes.io/name": spec.runtime.managerDeployment },
        ports: [{ name: "http", port: spec.runtime.managerPort, targetPort: "http" }],
      },
    },
    {
      apiVersion: "apps/v1",
      kind: "Deployment",
      metadata: { name: spec.runtime.managerDeployment, namespace: spec.runtime.namespace, labels: agentRunLabels(spec) },
      spec: {
        replicas: 1,
        selector: { matchLabels: { "app.kubernetes.io/name": spec.runtime.managerDeployment } },
        template: {
          metadata: {
            labels: { ...agentRunLabels(spec), "app.kubernetes.io/name": spec.runtime.managerDeployment },
            annotations: {
              "agentrun.pikastech.local/lane": spec.version,
              "agentrun.pikastech.local/source-commit": sourceCommit,
              "agentrun.pikastech.local/env-identity": image.envIdentity,
            },
          },
          spec: {
            serviceAccountName: spec.deployment.manager.serviceAccount,
            containers: [
              {
                name: "mgr",
                image: imageRef,
                imagePullPolicy: "IfNotPresent",
                ports: [{ name: "http", containerPort: 8080 }],
                env: managerEnv(spec, sourceCommit, imageRef, image.envIdentity),
                readinessProbe: { httpGet: { path: "/health/readiness", port: "http" }, timeoutSeconds: 2 },
                livenessProbe: { httpGet: { path: "/health/live", port: "http" }, timeoutSeconds: 2 },
                startupProbe: { httpGet: { path: "/health/live", port: "http" }, periodSeconds: 10, timeoutSeconds: 2, failureThreshold: 90 },
                resources: spec.deployment.manager.resources,
              },
            ],
          },
        },
      },
    },
    {
      apiVersion: "rbac.authorization.k8s.io/v1",
      kind: "Role",
      metadata: { name: `${spec.deployment.manager.serviceAccount}-runner-job-controller`, namespace: spec.runtime.namespace, labels: agentRunLabels(spec) },
      rules: [
        { apiGroups: ["batch"], resources: ["jobs"], verbs: ["create", "delete", "get", "list", "watch"] },
        { apiGroups: [""], resources: ["pods"], verbs: ["delete", "get", "list", "watch"] },
        { apiGroups: [""], resources: ["events"], verbs: ["get", "list", "watch"] },
        { apiGroups: [""], resources: ["persistentvolumeclaims"], verbs: ["create", "get", "list", "watch", "delete"] },
      ],
    },
    {
      apiVersion: "rbac.authorization.k8s.io/v1",
      kind: "RoleBinding",
      metadata: { name: `${spec.deployment.manager.serviceAccount}-runner-job-controller`, namespace: spec.runtime.namespace, labels: agentRunLabels(spec) },
      subjects: [{ kind: "ServiceAccount", name: spec.deployment.manager.serviceAccount }],
      roleRef: { apiGroup: "rbac.authorization.k8s.io", kind: "Role", name: `${spec.deployment.manager.serviceAccount}-runner-job-controller` },
    },
    {
      apiVersion: "rbac.authorization.k8s.io/v1",
      kind: "Role",
      metadata: { name: `${spec.deployment.manager.serviceAccount}-provider-secret-manager`, namespace: spec.runtime.namespace, labels: agentRunLabels(spec) },
      rules: [{ apiGroups: [""], resources: ["secrets"], verbs: ["create", "delete", "get", "list", "patch", "update"] }],
    },
    {
      apiVersion: "rbac.authorization.k8s.io/v1",
      kind: "RoleBinding",
      metadata: { name: `${spec.deployment.manager.serviceAccount}-provider-secret-manager`, namespace: spec.runtime.namespace, labels: agentRunLabels(spec) },
      subjects: [{ kind: "ServiceAccount", name: spec.deployment.manager.serviceAccount }],
      roleRef: { apiGroup: "rbac.authorization.k8s.io", kind: "Role", name: `${spec.deployment.manager.serviceAccount}-provider-secret-manager` },
    },
  ];
}

function managerEnv(spec: AgentRunLaneSpec, sourceCommit: string, imageRef: string, envIdentity: string): readonly Record<string, unknown>[] {
  return [
    { name: "AGENTRUN_LANE", value: spec.version },
    { name: "DATABASE_URL", valueFrom: { secretKeyRef: spec.database.secretRef } },
    { name: "AGENTRUN_SOURCE_COMMIT", value: sourceCommit },
    { name: "AGENTRUN_BOOT_COMMIT", value: sourceCommit },
    { name: "AGENTRUN_BOOT_MODE", value: "mgr" },
    { name: "AGENTRUN_BOOT_REPO_URL", value: spec.deployment.manager.bootRepoUrl },
    { name: "AGENTRUN_ENV_IDENTITY", value: envIdentity },
    { name: "AGENTRUN_RUNTIME_NAMESPACE", value: spec.runtime.namespace },
    { name: "AGENTRUN_INTERNAL_MGR_URL", value: spec.runtime.internalBaseUrl },
    { name: "AGENTRUN_RUNNER_IMAGE", value: imageRef },
    { name: "AGENTRUN_RUNNER_SERVICE_ACCOUNT", value: spec.deployment.runner.serviceAccount },
    { name: "AGENTRUN_RUNNER_JOB_NAME_PREFIX", value: spec.deployment.runner.jobNamePrefix },
    { name: "AGENTRUN_RUNNER_API_KEY_SECRET_NAME", value: spec.deployment.runner.apiKeySecretRef.name },
    { name: "AGENTRUN_RUNNER_API_KEY_SECRET_KEY", value: spec.deployment.runner.apiKeySecretRef.key },
    { name: "AGENTRUN_GIT_MIRROR_BASE_URL", value: spec.gitMirror.resourceBundleBaseUrl },
    { name: "AGENTRUN_RUNNER_IDLE_TIMEOUT_MS", value: String(spec.deployment.runner.idleTimeoutMs) },
    { name: "AGENTRUN_BACKEND_RETRY_MAX_ATTEMPTS", value: String(spec.deployment.runner.backendRetry.maxAttempts) },
    { name: "AGENTRUN_BACKEND_RETRY_INITIAL_BACKOFF_MS", value: String(spec.deployment.runner.backendRetry.initialBackoffMs) },
    { name: "AGENTRUN_BACKEND_RETRY_MAX_BACKOFF_MS", value: String(spec.deployment.runner.backendRetry.maxBackoffMs) },
    { name: "AGENTRUN_RUNNER_RETENTION_MAX_RUNNERS", value: String(spec.deployment.runner.retention.maxRunners) },
    { name: "AGENTRUN_RUNNER_RETENTION_CLEANUP_ORDER", value: spec.deployment.runner.retention.cleanupOrder },
    { name: "AGENTRUN_RUNNER_RETENTION_ACTIVE_HEARTBEAT_MAX_AGE_MS", value: String(spec.deployment.runner.retention.activeHeartbeatMaxAgeMs) },
    { name: "AGENTRUN_RUNNER_RETENTION_STALE_PENDING_MAX_AGE_MS", value: String(spec.deployment.runner.retention.stalePendingMaxAgeMs) },
    { name: "AGENTRUN_RUNNER_RETENTION_MATCH_LABELS_JSON", value: JSON.stringify(spec.deployment.runner.retention.selectors.matchLabels) },
    { name: "AGENTRUN_RUNNER_RETENTION_JOB_NAME_PREFIXES", value: spec.deployment.runner.retention.selectors.jobNamePrefixes.join(",") },
    { name: "AGENTRUN_RUNNER_RETENTION_AGE_BASED_CLEANUP_ENABLED", value: String(spec.deployment.runner.retention.ageBasedCleanup.enabled) },
    ...(spec.deployment.runner.retention.ageBasedCleanup.maxAgeHours === null ? [] : [{ name: "AGENTRUN_RUNNER_RETENTION_AGE_BASED_MAX_AGE_HOURS", value: String(spec.deployment.runner.retention.ageBasedCleanup.maxAgeHours) }]),
    { name: "AGENTRUN_CANCEL_DELIVERY_MODE", value: spec.deployment.runner.cancelLifecycle.deliveryMode },
    { name: "AGENTRUN_CANCEL_GRACEFUL_ABORT_MS", value: String(spec.deployment.runner.cancelLifecycle.gracefulAbortMs) },
    { name: "AGENTRUN_CANCEL_KILL_ESCALATION_MS", value: String(spec.deployment.runner.cancelLifecycle.killEscalationMs) },
    { name: "AGENTRUN_CANCEL_STALE_HEARTBEAT_FENCING_MS", value: String(spec.deployment.runner.cancelLifecycle.staleHeartbeatFencingMs) },
    { name: "AGENTRUN_CANCEL_LATE_WRITE_FENCING_ENABLED", value: String(spec.deployment.runner.cancelLifecycle.lateWriteFencing.enabled) },
    { name: "AGENTRUN_CANCEL_EVENT_STAGES", value: spec.deployment.runner.cancelLifecycle.eventStages.join(",") },
    ...(spec.deployment.runner.egressProxyUrl === null ? [] : [{ name: "AGENTRUN_RUNNER_EGRESS_PROXY_URL", value: spec.deployment.runner.egressProxyUrl }]),
    ...(spec.deployment.runner.noProxyExtra.length === 0 ? [] : [{ name: "AGENTRUN_RUNNER_NO_PROXY_EXTRA", value: spec.deployment.runner.noProxyExtra.join(",") }]),
    { name: "AGENTRUN_API_KEY", valueFrom: { secretKeyRef: spec.deployment.manager.apiKeySecretRef } },
    ...Object.entries(spec.deployment.manager.env).sort(([left], [right]) => left.localeCompare(right)).map(([name, value]) => ({ name, value })),
    ...(spec.deployment.manager.unideskSshEndpointEnv === null ? [] : [{ name: spec.deployment.manager.unideskSshEndpointEnv.name, value: spec.deployment.manager.unideskSshEndpointEnv.value }]),
  ];
}

function agentRunRunnerRbacManifests(spec: AgentRunLaneSpec): readonly Record<string, unknown>[] {
  return [
    { apiVersion: "v1", kind: "ServiceAccount", metadata: { name: spec.deployment.runner.serviceAccount, namespace: spec.runtime.namespace, labels: agentRunLabels(spec) } },
    {
      apiVersion: "rbac.authorization.k8s.io/v1",
      kind: "Role",
      metadata: { name: `${spec.deployment.runner.serviceAccount}-secret-reader`, namespace: spec.runtime.namespace, labels: agentRunLabels(spec) },
      rules: [{ apiGroups: [""], resources: ["secrets"], verbs: ["get"] }],
    },
    {
      apiVersion: "rbac.authorization.k8s.io/v1",
      kind: "RoleBinding",
      metadata: { name: `${spec.deployment.runner.serviceAccount}-secret-reader`, namespace: spec.runtime.namespace, labels: agentRunLabels(spec) },
      subjects: [{ kind: "ServiceAccount", name: spec.deployment.runner.serviceAccount }],
      roleRef: { apiGroup: "rbac.authorization.k8s.io", kind: "Role", name: `${spec.deployment.runner.serviceAccount}-secret-reader` },
    },
  ];
}

function agentRunArtifactCatalog(spec: AgentRunLaneSpec, sourceCommit: string, image: AgentRunArtifactService): AgentRunArtifactCatalog {
  return {
    lane: spec.version,
    sourceBranch: spec.source.branch,
    gitopsBranch: spec.gitops.branch,
    sourceCommitId: sourceCommit,
    summary: image.status === "placeholder"
      ? "build=0 reuse=0 placeholder=1"
      : image.status === "reused"
        ? "build=0 reuse=1 placeholder=0"
        : "build=1 reuse=0 placeholder=0",
    services: [image],
  };
}

function agentRunLabels(spec: AgentRunLaneSpec): Record<string, string> {
  return {
    "app.kubernetes.io/part-of": "agentrun",
    "agentrun.pikastech.local/lane": spec.version,
    "agentrun.pikastech.local/node": spec.nodeId,
  };
}

function agentRunPacGiteaSecretName(spec: AgentRunLaneSpec): string {
  const consumerId = spec.ci.pipelineRunPrefix.replace(/-ci$/u, "");
  if (consumerId === spec.ci.pipelineRunPrefix) throw new Error(`config/agentrun.yaml controlPlane.lanes.${spec.lane}.ci.pipelineRunPrefix must end with -ci`);
  return `pac-gitea-${consumerId}`;
}

function yaml(value: unknown): string {
  return `${yamlDocument(value)}\n`;
}

function yamlAll(values: readonly unknown[]): string {
  return `${values.map(yamlDocument).join("\n---\n")}\n`;
}

function yamlDocument(value: unknown): string {
  const rendered = Bun.YAML.stringify(value).trim();
  const reparsed = Bun.YAML.parse(rendered) as unknown;
  // JSON is valid YAML and preserves scalar types when Bun's YAML emitter does not.
  return JSON.stringify(reparsed) === JSON.stringify(value) ? rendered : JSON.stringify(value);
}
